| /******************************************************************************* |
| * Copyright (C) 2004-2006 Intel Corp. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * - Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Intel Corp. nor the names of its |
| * contributors may be used to endorse or promote products derived from this |
| * software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| *******************************************************************************/ |
| |
| /** |
| * @author Anas Nashif |
| * @author Eugene Yarmosh |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <wsman_config.h> |
| #endif |
| |
| #define _GNU_SOURCE |
| #include <string.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <ctype.h> |
| |
| #include "u/libu.h" |
| #include "wsman-xml-api.h" |
| #include "wsman-client-api.h" |
| #include "wsman-soap.h" |
| #include "wsman-xml.h" |
| |
| #include "wsman-dispatcher.h" |
| #include "wsman-xml-serialize.h" |
| #include "wsman-faults.h" |
| #include "wsman-soap-envelope.h" |
| |
| |
| /** |
| * @defgroup Dispatcher Dispatcher |
| * @brief SOAP Dispatcher |
| * |
| * @{ |
| */ |
| |
| struct __MuHeaderInfo { |
| char *ns; |
| char *name; |
| }; |
| |
| static int is_mu_header(WsXmlNodeH header) |
| { |
| int i; |
| char *name, *ns; |
| static struct __MuHeaderInfo s_Info[] = { |
| {XML_NS_ADDRESSING, WSA_TO}, |
| {XML_NS_ADDRESSING, WSA_MESSAGE_ID}, |
| {XML_NS_ADDRESSING, WSA_RELATES_TO}, |
| {XML_NS_ADDRESSING, WSA_ACTION}, |
| {XML_NS_ADDRESSING, WSA_REPLY_TO}, |
| {XML_NS_ADDRESSING, WSA_FROM}, |
| {XML_NS_WS_MAN, WSM_RESOURCE_URI}, |
| {XML_NS_WS_MAN, WSM_SELECTOR_SET}, |
| {XML_NS_WS_MAN, WSM_MAX_ENVELOPE_SIZE}, |
| {XML_NS_WS_MAN, WSM_OPERATION_TIMEOUT}, |
| {XML_NS_WS_MAN, WSM_FRAGMENT_TRANSFER}, |
| {XML_NS_TRUST, WST_ISSUEDTOKENS}, |
| {NULL, NULL} |
| }; |
| |
| name = ws_xml_get_node_local_name(header); |
| ns = ws_xml_get_node_name_ns(header); |
| |
| for (i = 0; s_Info[i].name != NULL; i++) { |
| if ((ns == NULL && s_Info[i].ns == NULL) || |
| (ns != NULL && s_Info[i].ns != NULL && |
| !strcmp(ns, s_Info[i].ns))) { |
| if (!strcmp(name, s_Info[i].name)) |
| return 1; |
| } |
| } |
| debug("mustUnderstand: %s:%s", !ns ? "null" : ns, name ? name : "NULL"); |
| return 0; |
| } |
| |
| |
| |
| static void |
| generate_op_fault(op_t * op, |
| WsmanFaultCodeType faultCode, |
| WsmanFaultDetailType faultDetail) |
| { |
| if (op->out_doc) { |
| ws_xml_destroy_doc(op->out_doc); |
| op->out_doc = NULL; |
| } |
| if (op->in_doc == NULL) { |
| return; |
| } |
| op->out_doc = wsman_generate_fault(op->in_doc, faultCode, faultDetail, NULL); |
| return; |
| } |
| |
| static void |
| generate_notunderstood_fault(op_t * op, |
| WsXmlNodeH notUnderstoodHeader) |
| { |
| WsXmlNodeH child; |
| WsXmlNodeH header; |
| |
| if (op->in_doc == NULL) |
| return; |
| generate_op_fault(op, SOAP_FAULT_MUSTUNDERSTAND, 0); |
| |
| if (op->out_doc != NULL) { |
| header = ws_xml_get_soap_header(op->out_doc); |
| if (header) { |
| child = ws_xml_add_child(header, XML_NS_SOAP_1_2, |
| "NotUnderstood", NULL); |
| ws_xml_add_qname_attr(child, NULL, "qname", |
| ws_xml_get_node_name_ns |
| (notUnderstoodHeader), |
| ws_xml_get_node_local_name |
| (notUnderstoodHeader)); |
| } |
| } else { |
| error("cant generate fault"); |
| } |
| return; |
| } |
| |
| |
| static int check_for_duplicate_selectors(op_t * op) |
| { |
| WsXmlNodeH header, node, selector; |
| int retval = 0, index = 0; |
| hash_t *h; |
| |
| header = wsman_get_soap_header_element( op->in_doc, NULL, NULL); |
| if ((node = ws_xml_get_child(header, 0, XML_NS_WS_MAN, |
| WSM_SELECTOR_SET)) == NULL) { |
| // No selectors |
| return 0; |
| } |
| h = hash_create(HASHCOUNT_T_MAX, 0, 0); |
| if (h == NULL) { |
| generate_op_fault(op, WSMAN_INTERNAL_ERROR, |
| OWSMAN_NO_DETAILS); |
| error("could not create hash"); |
| return 1; |
| } |
| |
| while ((selector = ws_xml_get_child(node, index++, XML_NS_WS_MAN, |
| WSM_SELECTOR))) { |
| char *attrVal = ws_xml_find_attr_value(selector, NULL, |
| WSM_NAME); |
| if (!attrVal) |
| continue; |
| |
| if (hash_lookup(h, attrVal)) { |
| generate_op_fault(op, WSMAN_INVALID_SELECTORS, |
| WSMAN_DETAIL_DUPLICATE_SELECTORS); |
| debug("Selector %s duplicated", attrVal); |
| retval = 1; |
| break; |
| } |
| |
| if (!hash_alloc_insert(h, attrVal, |
| ws_xml_get_node_text(selector))) { |
| generate_op_fault(op, WSMAN_INTERNAL_ERROR, |
| OWSMAN_NO_DETAILS); |
| retval = 1; |
| error("hash_alloc_insert failed"); |
| break; |
| } |
| } |
| hash_free_nodes(h); |
| hash_destroy(h); |
| return retval; |
| } |
| |
| static int validate_control_headers(op_t * op) |
| { |
| unsigned long size = 0; |
| time_t duration; |
| WsXmlNodeH header, child, maxsize; |
| char *mu = NULL; |
| |
| header = wsman_get_soap_header_element( op->in_doc, NULL, NULL); |
| maxsize = ws_xml_get_child(header, 0, XML_NS_WS_MAN, |
| WSM_MAX_ENVELOPE_SIZE); |
| mu = ws_xml_find_attr_value(maxsize, XML_NS_SOAP_1_2, |
| SOAP_MUST_UNDERSTAND); |
| if (mu != NULL && strcmp(mu, "true") == 0) { |
| size = ws_deserialize_uint32(NULL, header, |
| 0, XML_NS_WS_MAN, |
| WSM_MAX_ENVELOPE_SIZE); |
| if (size < WSMAN_MINIMAL_ENVELOPE_SIZE_REQUEST) { |
| generate_op_fault(op, WSMAN_ENCODING_LIMIT, |
| WSMAN_DETAIL_MINIMUM_ENVELOPE_LIMIT); |
| return 0; |
| } |
| op->maxsize = size; |
| } |
| child = ws_xml_get_child(header, 0, |
| XML_NS_WS_MAN, WSM_OPERATION_TIMEOUT); |
| if (child != NULL) { |
| char *text = ws_xml_get_node_text(child); |
| char *nsUri = ws_xml_get_node_name_ns(header); |
| if (text == NULL || |
| ws_deserialize_duration(text, &duration)) { |
| generate_op_fault(op, |
| WSA_INVALID_MESSAGE_INFORMATION_HEADER, |
| WSMAN_DETAIL_OPERATION_TIMEOUT); |
| return 0; |
| } |
| if (duration <= 0) { |
| generate_op_fault(op, WSMAN_TIMED_OUT, 0); |
| return 0; |
| } |
| op->expires = duration; |
| // Not supported now |
| if (ws_xml_find_attr_bool |
| (child, nsUri, SOAP_MUST_UNDERSTAND)) { |
| generate_op_fault(op, |
| WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_OPERATION_TIMEOUT); |
| return 0; |
| } |
| } |
| return 1; |
| } |
| |
| |
| static WsXmlNodeH |
| validate_mustunderstand_headers(op_t * op) |
| { |
| WsXmlNodeH child = NULL, header = NULL; |
| int i; |
| char *nsUri; |
| |
| header = wsman_get_soap_header_element(op->in_doc, NULL, NULL); |
| nsUri = ws_xml_get_node_name_ns(header); |
| |
| for (i = 0;(child = ws_xml_get_child(header, i, NULL, NULL)) != NULL; i++) { |
| if (ws_xml_find_attr_bool(child, nsUri, SOAP_MUST_UNDERSTAND)) { |
| if (!is_mu_header(child)) { |
| break; |
| } |
| } |
| } |
| |
| if (child != NULL) { |
| debug("Mustunderstand Fault: %s", ws_xml_get_node_text(child)); |
| } |
| return child; |
| } |
| |
| static int |
| check_supported_dialect(const char *dialect) |
| { |
| if (strcmp(dialect, WSM_ASSOCIATION_FILTER_DIALECT) == 0) |
| return 0; |
| else if (strcmp(dialect, WSM_XPATH_FILTER_DIALECT) == 0) |
| return 0; |
| else if (strcmp(dialect, WSM_WQL_FILTER_DIALECT) == 0) |
| return 0; |
| else if (strcmp(dialect, WSM_CQL_FILTER_DIALECT) == 0) |
| return 0; |
| else if (strcmp(dialect, WSM_SELECTOR_FILTER_DIALECT) == 0) |
| return 0; |
| return 1; |
| } |
| |
| |
| /** |
| * Check for duplicate Message ID |
| * @param op operation |
| * @return status |
| */ |
| static int |
| check_unsupported_features(op_t * op) |
| { |
| WsXmlNodeH enumurate; |
| WsXmlNodeH subscribe; |
| WsXmlNodeH header = wsman_get_soap_header_element( op->in_doc, NULL, NULL); |
| WsXmlNodeH body = ws_xml_get_soap_body(op->in_doc); |
| int retVal = 0; |
| WsXmlNodeH n, m, k; |
| char *resource_uri = NULL, *mu = NULL; |
| WsXmlAttrH attr = NULL; |
| |
| |
| n = ws_xml_get_child(header, 0, XML_NS_ADDRESSING, WSA_FAULT_TO); |
| if (n != NULL) { |
| retVal = 1; |
| generate_op_fault(op, WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_ADDRESSING_MODE); |
| goto DONE; |
| } |
| n = ws_xml_get_child(header, 0, XML_NS_WS_MAN, WSM_LOCALE); |
| if (n != NULL) { |
| debug("Locale header found"); |
| mu = ws_xml_find_attr_value(n, XML_NS_SOAP_1_2, |
| SOAP_MUST_UNDERSTAND); |
| if (mu != NULL && strcmp(mu, "true") == 0) { |
| retVal = 1; |
| generate_op_fault(op, |
| WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_LOCALE); |
| goto DONE; |
| } |
| } |
| #if 0 |
| n = ws_xml_get_child(header, 0, XML_NS_WS_MAN, |
| WSM_FRAGMENT_TRANSFER); |
| if (n != NULL) { |
| debug("FragmentTransfer header found"); |
| mu = ws_xml_find_attr_value(n, XML_NS_SOAP_1_2, |
| SOAP_MUST_UNDERSTAND); |
| if (mu != NULL && strcmp(mu, "true") == 0) { |
| retVal = 1; |
| generate_op_fault(op, |
| WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_FRAGMENT_LEVEL_ACCESS); |
| goto DONE; |
| } |
| } |
| #endif |
| enumurate = ws_xml_get_child(body, 0, XML_NS_ENUMERATION, |
| WSENUM_ENUMERATE); |
| if (enumurate) { |
| |
| n = ws_xml_get_child(enumurate, 0, XML_NS_ENUMERATION, |
| WSENUM_END_TO); |
| if (n != NULL) { |
| retVal = 1; |
| generate_op_fault(op, WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_ADDRESSING_MODE); |
| } |
| n = ws_xml_get_child(enumurate, 0, XML_NS_ENUMERATION, |
| WSENUM_FILTER); |
| m = ws_xml_get_child(enumurate, 0, XML_NS_WS_MAN, WSM_FILTER); |
| if (n != NULL && m != NULL) { |
| retVal = 1; |
| generate_op_fault(op, WSEN_CANNOT_PROCESS_FILTER, 0); |
| goto DONE; |
| } else if (n || m) { |
| char *dia = NULL; |
| if (n) { |
| dia = ws_xml_find_attr_value(n, NULL, WSM_DIALECT); |
| } else if (m) { |
| dia = ws_xml_find_attr_value(m, NULL, WSM_DIALECT); |
| } |
| if (dia) |
| retVal = check_supported_dialect(dia); |
| else |
| retVal = check_supported_dialect (WSM_XPATH_FILTER_DIALECT); |
| |
| if (retVal) { |
| retVal = 1; |
| generate_op_fault(op, WSEN_FILTER_DIALECT_REQUESTED_UNAVAILABLE, |
| 0); |
| goto DONE; |
| } |
| } |
| k = ws_xml_get_child(header, 0, XML_NS_WS_MAN, WSM_RESOURCE_URI); |
| if (k) |
| resource_uri = ws_xml_get_node_text(k); |
| if (resource_uri && |
| (strcmp(resource_uri, CIM_ALL_AVAILABLE_CLASSES) == 0)) { |
| if (!n && !m) { |
| retVal = 1; |
| generate_op_fault(op, WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_FILTERING_REQUIRED); |
| goto DONE; |
| } |
| |
| } |
| } |
| subscribe = ws_xml_get_child(body, 0, XML_NS_EVENTING, WSEVENT_SUBSCRIBE); |
| if(subscribe) { |
| /* n = ws_xml_get_child(subscribe, 0, XML_NS_EVENTING, WSEVENT_ENDTO); |
| if(n) { |
| retVal = 1; |
| generate_op_fault(op, WSMAN_UNSUPPORTED_FEATURE, |
| WSMAN_DETAIL_ADDRESSING_MODE); |
| goto DONE; |
| } |
| */ n = ws_xml_get_child(subscribe, 0, XML_NS_EVENTING, WSEVENT_DELIVERY); |
| if(n == NULL) { |
| retVal = 1; |
| generate_op_fault(op, WSE_INVALID_MESSAGE, 0); |
| goto DONE; |
| } |
| attr = ws_xml_find_node_attr(n, NULL,WSEVENT_DELIVERY_MODE); |
| if(attr) { |
| mu = ws_xml_get_attr_value(attr); |
| if (strcasecmp(mu, WSEVENT_DELIVERY_MODE_PUSH) && |
| strcasecmp(mu, WSEVENT_DELIVERY_MODE_PUSHWITHACK) && |
| strcasecmp(mu, WSEVENT_DELIVERY_MODE_EVENTS) && |
| strcasecmp(mu, WSEVENT_DELIVERY_MODE_PULL)) { |
| debug("Unsupported delivery mode : %s",ws_xml_get_attr_value(attr)); |
| retVal = 1; |
| generate_op_fault(op, WSE_DELIVERY_MODE_REQUESTED_UNAVAILABLE, 0); |
| goto DONE; |
| } |
| } |
| m = ws_xml_get_child(n, 0, XML_NS_WS_MAN, WSM_CONNECTIONRETRY); |
| if(m) { |
| retVal = 1; |
| generate_op_fault(op, WSMAN_UNSUPPORTED_FEATURE, WSMAN_DETAIL_DELIVERY_RETRIES); |
| goto DONE; |
| } |
| } |
| DONE: |
| return retVal; |
| } |
| |
| |
| |
| /** |
| * Check for duplicate Message ID |
| * @param op operation |
| * @return status |
| */ |
| static int wsman_is_duplicate_message_id(op_t * op) |
| { |
| WsXmlNodeH header = wsman_get_soap_header_element(op->in_doc, NULL, NULL); |
| int retVal = 0; |
| SoapH soap; |
| WsXmlNodeH msgIdNode; |
| soap = op->dispatch->soap; |
| |
| msgIdNode = ws_xml_get_child(header, 0, XML_NS_ADDRESSING, WSA_MESSAGE_ID); |
| if (msgIdNode != NULL) { |
| lnode_t *node; |
| char *msgId; |
| msgId = ws_xml_get_node_text(msgIdNode); |
| if (msgId[0] == 0 ) { |
| generate_op_fault(op, WSA_INVALID_MESSAGE_INFORMATION_HEADER, 0 ); |
| debug("MessageId missing"); |
| return 1; |
| } |
| debug("Checking Message ID: %s", msgId); |
| u_lock(soap); |
| |
| if (soap->processedMsgIdList == NULL) { |
| soap->processedMsgIdList = list_create(LISTCOUNT_T_MAX); |
| } |
| #ifndef IGNORE_DUPLICATE_ID |
| node = list_first(soap->processedMsgIdList); |
| while (node != NULL) { |
| if (!strcmp(msgId, (char *) node->list_data)) { |
| debug("Duplicate Message ID: %s", msgId); |
| retVal = 1; |
| generate_op_fault(op, WSA_INVALID_MESSAGE_INFORMATION_HEADER, |
| WSA_DETAIL_DUPLICATE_MESSAGE_ID); |
| break; |
| } |
| node = list_next(soap->processedMsgIdList, node); |
| } |
| #endif |
| |
| |
| if (!retVal) { |
| while (list_count(soap->processedMsgIdList) >= PROCESSED_MSG_ID_MAX_SIZE) { |
| node = list_del_first(soap->processedMsgIdList); |
| u_free(node->list_data); |
| u_free(node); |
| } |
| |
| node = lnode_create(NULL); |
| if (node) { |
| node->list_data = u_str_clone(msgId); |
| if (node->list_data == NULL) { |
| u_free(node); |
| } else { |
| list_append(soap->processedMsgIdList, node); |
| } |
| } |
| } |
| u_unlock(soap); |
| } else if (!wsman_is_identify_request(op->in_doc)) { |
| generate_op_fault(op, WSA_MESSAGE_INFORMATION_HEADER_REQUIRED, 0); |
| debug("No MessageId Header found"); |
| return 1; |
| } |
| |
| return retVal; |
| } |
| |
| int |
| soap_add_filter(SoapH soap, |
| SoapServiceCallback callbackProc, |
| void *callbackData, int inbound) |
| { |
| callback_t *entry = NULL; |
| |
| if (soap) { |
| if (!inbound) { |
| if (!soap->outboundFilterList) |
| soap->outboundFilterList = list_create(LISTCOUNT_T_MAX); |
| entry = make_callback_entry(callbackProc, callbackData, soap->outboundFilterList); |
| } else { |
| if (!soap->inboundFilterList) |
| soap->inboundFilterList = list_create(LISTCOUNT_T_MAX); |
| entry = make_callback_entry(callbackProc, callbackData, soap->inboundFilterList); |
| } |
| } |
| if (entry == NULL) |
| return 0; |
| else |
| return 1; |
| } |
| |
| |
| int |
| outbound_control_header_filter(SoapOpH opHandle, |
| void *data, void *opaqueData) |
| { |
| op_t *op = (op_t *)opHandle; |
| WsmanMessage *msg = wsman_get_msg_from_op(opHandle); |
| if(check_envelope_size(op->out_doc, op->maxsize, msg->charset)) { |
| debug("****should not go here"); |
| generate_op_fault(op, WSMAN_ENCODING_LIMIT, |
| WSMAN_DETAIL_SERVICE_ENVELOPE_LIMIT); |
| } |
| return 0; |
| } |
| |
| int |
| outbound_addressing_filter(SoapOpH opHandle, void *data, void *opaqueData) |
| { |
| WsXmlDocH in_doc = soap_get_op_doc(opHandle, 1); |
| WsXmlDocH out_doc = soap_get_op_doc(opHandle, 0); |
| |
| WsXmlNodeH outHeaders = wsman_get_soap_header_element(out_doc, NULL, NULL); |
| |
| if (!outHeaders) { |
| return 0; |
| } |
| if (ws_xml_get_child(outHeaders, 0, XML_NS_ADDRESSING, WSA_MESSAGE_ID) == NULL && |
| !wsman_is_identify_request(in_doc)) { |
| char uuidBuf[100]; |
| generate_uuid(uuidBuf, sizeof(uuidBuf), 0); |
| ws_xml_add_child(outHeaders, XML_NS_ADDRESSING, WSA_MESSAGE_ID, uuidBuf); |
| debug("Adding message id: %s", uuidBuf); |
| } |
| if (in_doc != NULL) { |
| WsXmlNodeH inMsgIdNode; |
| inMsgIdNode = wsman_get_soap_header_element(in_doc,XML_NS_ADDRESSING, |
| WSA_MESSAGE_ID); |
| if (inMsgIdNode != NULL && |
| !ws_xml_get_child(outHeaders, 0, XML_NS_ADDRESSING, WSA_RELATES_TO)) { |
| ws_xml_add_child(outHeaders, XML_NS_ADDRESSING, WSA_RELATES_TO, |
| ws_xml_get_node_text(inMsgIdNode)); |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| static int |
| process_filter_chain(op_t *op, list_t *list, void *opaqueData) |
| { |
| int retVal = 0; |
| callback_t *filter = NULL; |
| if (list != NULL) { |
| filter = (callback_t *) list_first(list); |
| while (!retVal && filter != NULL) { |
| retVal = filter->proc((SoapOpH) op, filter->node.list_data, |
| opaqueData); |
| filter = (callback_t *) list_next(list, &filter->node); |
| } |
| } |
| return retVal; |
| } |
| |
| /** |
| * Process Filters |
| * @param op SOAP operation |
| * @param inbound Direction of message, 0 for outbound and 1 for inbound. |
| * @return 0 on success, 1 on error. |
| **/ |
| static int process_filters(op_t * op, int inbound, void *opaqueData) |
| { |
| int retVal = 0; |
| list_t *list; |
| |
| debug("Processing Filters: %s", (!inbound) ? "outbound" : "inbound"); |
| if (!(op->dispatch->flags & SOAP_SKIP_DEF_FILTERS)) { |
| list = inbound ? op->dispatch->soap->inboundFilterList : |
| op->dispatch->soap->outboundFilterList; |
| retVal = process_filter_chain(op, list, opaqueData); |
| } |
| if (retVal) { |
| debug("process_filter_chain returned 1 for DEF FILTERS"); |
| return 1; |
| } |
| list = inbound ? op->dispatch->inboundFilterList : |
| op->dispatch->outboundFilterList; |
| retVal = process_filter_chain(op, list, opaqueData); |
| |
| if (retVal) { |
| debug("process_filter_chain returned 1"); |
| return 1; |
| } |
| |
| if (inbound) { |
| WsXmlNodeH notUnderstoodHeader; |
| if (wsman_is_duplicate_message_id(op)) { |
| debug("wsman_is_duplicate_message_id"); |
| return 1; |
| } |
| if (check_unsupported_features(op)) { |
| debug("check_unsupported_features"); |
| return 1; |
| } |
| if ((notUnderstoodHeader = |
| validate_mustunderstand_headers(op)) != 0) { |
| generate_notunderstood_fault(op, notUnderstoodHeader); |
| debug("validate_mustunderstand_headers"); |
| return 1; |
| } |
| if (!validate_control_headers(op)) { |
| debug("validate_control_headers"); |
| return 1; |
| } |
| if (check_for_duplicate_selectors(op)) { |
| debug("check_for_duplicate_selectors"); |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| |
| |
| static void |
| dispatcher_create_fault(SoapH soap, WsmanMessage * msg, WsXmlDocH in_doc) |
| { |
| char *buf = NULL; |
| int len; |
| if (!soap) |
| return; |
| |
| if (wsman_fault_occured(msg)) { |
| wsman_generate_fault_buffer(in_doc, |
| msg->charset, |
| msg->status.fault_code, |
| msg->status.fault_detail_code, |
| msg->status.fault_msg, |
| &buf, &len); |
| u_buf_set(msg->response, buf, len); |
| u_free(buf); |
| msg->http_code = wsman_find_httpcode_for_fault_code( |
| msg->status. |
| fault_code); |
| } |
| return; |
| } |
| |
| |
| static int |
| process_inbound_operation(op_t * op, WsmanMessage * msg, void *opaqueData) |
| { |
| int retVal = 1; |
| char *buf = NULL; |
| int len; |
| |
| msg->http_code = WSMAN_STATUS_OK; |
| op->out_doc = NULL; |
| if (op->dispatch->serviceCallback == NULL) { |
| wsman_set_fault(msg, WSA_ACTION_NOT_SUPPORTED, |
| OWSMAN_NO_DETAILS, NULL); |
| debug("op service callback is null"); |
| goto GENERATE_FAULT; |
| } |
| |
| if (process_filters(op, 1, opaqueData)) { |
| if (op->out_doc == NULL) { |
| error("doc is null"); |
| wsman_set_fault(msg, WSMAN_INTERNAL_ERROR, |
| OWSMAN_NO_DETAILS, NULL); |
| goto GENERATE_FAULT; |
| } |
| if (wsman_is_fault_envelope(op->out_doc)) { |
| msg->http_code = |
| wsman_find_httpcode_for_value(op->out_doc); |
| } else { |
| error("not fault envelope"); |
| } |
| |
| ws_xml_dump_memory_enc(op->out_doc, &buf, &len, msg->charset); |
| u_buf_set(msg->response, buf, len); |
| ws_xml_destroy_doc(op->out_doc); |
| op->out_doc = NULL; |
| u_free(buf); |
| return 1; |
| } |
| |
| |
| retVal = op->dispatch->serviceCallback((SoapOpH) op, |
| op->dispatch->serviceData, |
| opaqueData); |
| if (op->out_doc == NULL) { |
| // XXX (correct fault?) |
| wsman_set_fault(msg, WSA_DESTINATION_UNREACHABLE, |
| WSMAN_DETAIL_INVALID_RESOURCEURI, NULL); |
| error("output doc is null"); |
| goto GENERATE_FAULT; |
| } |
| |
| process_filters(op, 0, opaqueData); |
| if (op->out_doc == NULL) { |
| error("doc is null"); |
| wsman_set_fault(msg, WSMAN_INTERNAL_ERROR, |
| OWSMAN_NO_DETAILS, NULL); |
| goto GENERATE_FAULT; |
| } |
| if (wsman_is_fault_envelope(op->out_doc)) { |
| msg->http_code = |
| wsman_find_httpcode_for_value(op->out_doc); |
| } |
| else { |
| wsman_add_fragement_for_header(op->in_doc, op->out_doc); |
| } |
| ws_xml_dump_memory_enc(op->out_doc, &buf, &len, msg->charset); |
| u_buf_set(msg->response, buf, len); |
| ws_xml_destroy_doc(op->out_doc); |
| op->out_doc = NULL; |
| u_free(buf); |
| return 0; |
| |
| GENERATE_FAULT: |
| return retVal; |
| } |
| |
| |
| static SoapDispatchH get_dispatch_entry(SoapH soap, WsXmlDocH doc) |
| { |
| SoapDispatchH dispatch = NULL; |
| if (soap->dispatcherProc) { |
| dispatch = soap->dispatcherProc(soap->cntx, |
| soap->dispatcherData, doc); |
| } |
| if (dispatch == NULL) { |
| error("Dispatcher Error"); |
| } else { |
| dispatch->usageCount++; |
| } |
| return dispatch; |
| } |
| |
| void |
| dispatch_inbound_call(SoapH soap, WsmanMessage * msg, void *opaqueData) |
| { |
| op_t *op = NULL; |
| WsXmlDocH in_doc = wsman_build_inbound_envelope( msg); |
| SoapDispatchH dispatch = NULL; |
| debug("Inbound call..."); |
| #if 0 |
| /* debug incoming message */ |
| int size; |
| char *buf; |
| ws_xml_dump_memory_node_tree_enc( ws_xml_get_soap_body(in_doc), &buf, &size, "UTF-8" ); |
| debug(buf); |
| #endif |
| if (wsman_fault_occured(msg)) { |
| error("document is null"); |
| goto DONE; |
| } |
| dispatch = get_dispatch_entry(soap, in_doc); |
| |
| if (dispatch == NULL) { |
| wsman_set_fault(msg, WSA_DESTINATION_UNREACHABLE, |
| WSMAN_DETAIL_INVALID_RESOURCEURI, NULL); |
| debug("dispatch == NULL"); |
| goto DONE; |
| } |
| op = create_op_entry(soap, dispatch, msg); |
| if (op == NULL) { |
| wsman_set_fault(msg, WSA_DESTINATION_UNREACHABLE, |
| WSMAN_DETAIL_INVALID_RESOURCEURI, NULL); |
| destroy_dispatch_entry(dispatch); |
| debug("dispatch == NULL"); |
| goto DONE; |
| } |
| op->in_doc = in_doc; |
| process_inbound_operation(op, msg, opaqueData); |
| DONE: |
| dispatcher_create_fault(soap, msg, in_doc); |
| destroy_op_entry(op); |
| ws_xml_destroy_doc(in_doc); |
| debug("Inbound call completed"); |
| return; |
| } |
| |
| |
| static char *wsman_dispatcher_match_ns(WsDispatchInterfaceInfo * r, |
| char *uri) |
| { |
| char *ns = NULL; |
| lnode_t *node = NULL; |
| if (r->namespaces == NULL) { |
| return NULL; |
| } |
| if (!uri) |
| return NULL; |
| |
| node = list_first(r->namespaces); |
| while (node) { |
| WsSupportedNamespaces *sns = |
| (WsSupportedNamespaces *) node->list_data; |
| debug("namespace: %s", sns->ns); |
| if (sns->ns != NULL && strstr(uri, sns->ns)) { |
| ns = u_strdup(sns->ns); |
| break; |
| } |
| node = list_next(r->namespaces, node); |
| } |
| return ns; |
| } |
| |
| |
| WsEndPointRelease |
| wsman_get_release_endpoint(WsContextH cntx, WsXmlDocH doc) |
| { |
| WsManDispatcherInfo *dispInfo = |
| (WsManDispatcherInfo *) cntx->soap->dispatcherData; |
| lnode_t *node = NULL; |
| WsDispatchInterfaceInfo *r = NULL; |
| WsDispatchEndPointInfo *ep = NULL; |
| char *ptr = ENUM_ACTION_RELEASE, *ns = NULL, *uri = NULL; |
| int i; |
| |
| if (dispInfo->interfaces) { |
| node = list_first((list_t *) dispInfo->interfaces); |
| } |
| uri = wsman_get_resource_uri(cntx, doc); |
| |
| while (node != NULL) { |
| WsDispatchInterfaceInfo *ifc = |
| (WsDispatchInterfaceInfo *) node->list_data; |
| if (ifc->wsmanResourceUri == NULL && |
| (ns = wsman_dispatcher_match_ns(ifc, uri))) { |
| r = ifc; |
| break; |
| } |
| if (ifc->wsmanResourceUri && |
| !strcmp(uri, ifc->wsmanResourceUri)) { |
| r = ifc; |
| break; |
| } |
| node = list_next((list_t *) dispInfo->interfaces, node); |
| } |
| if (r == NULL) { |
| u_free(ns); |
| return NULL; |
| } |
| /* |
| * See if the action is part of the namespace which means that |
| * we are dealing with a custom action |
| */ |
| if (ns != NULL) { |
| size_t len = strlen(ns); |
| if (!strncmp(ptr, ns, len) && ptr[len] == '/') { |
| ptr += len + 1; |
| } |
| } |
| for (i = 0; r->endPoints[i].serviceEndPoint != NULL; i++) { |
| if (r->endPoints[i].inAction != NULL && |
| !strcmp(ptr, r->endPoints[i].inAction)) { |
| ep = &r->endPoints[i]; |
| break; |
| } |
| } |
| u_free(ns); |
| |
| if (ep == NULL) { |
| debug("no ep"); |
| return NULL; |
| } |
| debug("Release endpoint: %p", ep->serviceEndPoint); |
| return (WsEndPointRelease) ep->serviceEndPoint; |
| } |
| |
| SoapDispatchH wsman_dispatcher(WsContextH cntx, void *data, WsXmlDocH doc) |
| { |
| SoapDispatchH disp = NULL; |
| char *uri = NULL, *action; |
| WsManDispatcherInfo *dispInfo = (WsManDispatcherInfo *) data; |
| WsDispatchEndPointInfo *ep = NULL; |
| WsDispatchEndPointInfo *ep_custom = NULL; |
| |
| WsXmlDocH notdoc = NULL; |
| |
| #ifdef ENABLE_EVENTING_SUPPORT |
| WsXmlNodeH nodedoc = NULL; |
| #endif |
| /* FIXME: resUriMatch set but not used */ |
| int i, resUriMatch = 0; |
| char *ns = NULL; |
| |
| WsDispatchInterfaceInfo *r = NULL; |
| lnode_t *node = list_first((list_t *) dispInfo->interfaces); |
| |
| if (doc == NULL) { |
| error("doc is null"); |
| u_free(data); |
| goto cleanup; |
| } |
| uri = wsman_get_resource_uri(cntx, doc); |
| action = wsman_get_action(cntx, doc); |
| #ifdef ENABLE_EVENTING_SUPPORT |
| if(wsman_is_event_related_request(doc)) { |
| WsXmlNodeH temp = ws_xml_get_child( ws_xml_get_soap_header(doc), 0, |
| XML_NS_EVENTING, WSEVENT_IDENTIFIER); |
| char *uuid = ws_xml_get_node_text(temp); |
| debug("Request uuid: %s", uuid ? uuid : "NULL"); |
| if(uuid) { |
| lnode_t *t = list_first(cntx->subscriptionMemList); |
| while(t != NULL) { |
| WsSubscribeInfo *subsInfo = (WsSubscribeInfo *)t->list_data; |
| if(!strcmp(uuid+5, subsInfo->subsId)) { |
| uri = subsInfo->uri; |
| break; |
| } |
| else |
| t = list_next(cntx->subscriptionMemList, t); |
| } |
| if(t == NULL) { |
| unsigned char *buf = NULL; |
| int len; |
| if(cntx->soap->subscriptionOpSet->get_subscription(cntx->soap->uri_subsRepository, |
| uuid+5, &buf, &len) == 0) { |
| notdoc = ws_xml_read_memory( (char *)buf, len, "UTF-8", 0); |
| if(notdoc) { |
| nodedoc = ws_xml_get_soap_header(notdoc); |
| if(nodedoc) { |
| nodedoc = ws_xml_get_child(nodedoc, 0, XML_NS_WS_MAN, WSM_RESOURCE_URI); |
| if(nodedoc) { |
| uri = ws_xml_get_node_text(nodedoc); |
| } |
| } |
| } |
| u_free(buf); |
| } |
| } |
| } |
| } |
| #endif |
| debug("uri: %s, action: %s", uri ? uri : "NULL", action ? action : "NULL"); |
| if ((!uri || !action) && !wsman_is_identify_request(doc)) { |
| goto cleanup; |
| } |
| while (node != NULL) { |
| |
| WsDispatchInterfaceInfo *ifc = (WsDispatchInterfaceInfo *) node->list_data; |
| if (wsman_is_identify_request(doc)) { |
| if ((ns = wsman_dispatcher_match_ns(ifc, |
| XML_NS_WSMAN_ID))) { |
| r = ifc; |
| resUriMatch = 1; |
| break; |
| } |
| debug("ns did not match"); |
| } |
| /* |
| * If Resource URI is null then most likely we are dealing |
| * with a generic plugin supporting a namespace with |
| * multiple Resource URIs (e.g. CIM) |
| **/ |
| else if (ifc->wsmanResourceUri == NULL && |
| (ns = wsman_dispatcher_match_ns(ifc, uri))) { |
| r = ifc; |
| resUriMatch = 1; |
| break; |
| } else if (ifc->wsmanResourceUri && |
| !strcmp(uri, ifc->wsmanResourceUri)) { |
| r = ifc; |
| resUriMatch = 1; |
| break; |
| } |
| node = list_next((list_t *) dispInfo->interfaces, node); |
| } |
| |
| |
| if (wsman_is_identify_request(doc) && r != NULL) { |
| ep = &r->endPoints[0]; |
| } else if (r != NULL) { |
| char *ptr = action; |
| /* |
| * See if the action is part of the namespace which means that |
| * we are dealing with a custom action |
| */ |
| if (ns != NULL) { |
| size_t len = strlen(ns); |
| if (!strncmp(action, ns, len) && |
| action[len] == '/') |
| ptr = &action[len + 1]; |
| } |
| for (i = 0; r->endPoints[i].serviceEndPoint != NULL; i++) { |
| if (r->endPoints[i].inAction != NULL && |
| !strcmp(ptr, r->endPoints[i].inAction)) { |
| ep = &r->endPoints[i]; |
| break; |
| } else if (r->endPoints[i].inAction == NULL) { |
| /* |
| * Just store it for later |
| * in case no match is found for above condition |
| */ |
| ep_custom = &r->endPoints[i]; |
| } |
| } |
| } |
| ws_remove_context_val(cntx, WSM_RESOURCE_URI); |
| |
| if (ep != NULL) { |
| for (i = 0; i < dispInfo->mapCount; i++) { |
| if (dispInfo->map[i].ep == ep) { |
| disp = dispInfo->map[i].disp; |
| break; |
| } |
| } |
| } else if (ep_custom != NULL) { |
| for (i = 0; i < dispInfo->mapCount; i++) { |
| if (dispInfo->map[i].ep == ep_custom) { |
| disp = dispInfo->map[i].disp; |
| break; |
| } |
| } |
| } |
| |
| cleanup: |
| if(notdoc) |
| ws_xml_destroy_doc(notdoc); |
| if (ns) |
| u_free(ns); |
| return disp; |
| } |
| |
| |
| /* |
| * Create dispatch Entry |
| * |
| * @param soap Soap Framework Handle |
| * @param inboundAction Inbound Action |
| * @param outboundAction Outbound Action |
| * @param role Role |
| * @param proc Call back processor |
| * @param data Callback Data |
| * @param flags Flags |
| * @return Dispatch Entry |
| */ |
| static SoapDispatchH |
| create_dispatch_entry(SoapH soap, |
| char *inboundAction, |
| char *outboundAction, |
| char *role, |
| SoapServiceCallback proc, |
| void *data, unsigned long flags) |
| { |
| |
| SoapDispatchH entry = wsman_dispatch_entry_new(); |
| if (entry) { |
| entry->soap = soap; |
| entry->flags = flags; |
| entry->inboundAction = u_str_clone(inboundAction); |
| entry->outboundAction = u_str_clone(outboundAction); |
| entry->serviceCallback = proc; |
| entry->serviceData = data; |
| entry->usageCount = 1; |
| } |
| return entry; |
| } |
| |
| |
| |
| /* |
| * Create Dispatch Entry |
| * @param soap Soap handle |
| * @param inboundAction Inbound Action |
| * @param outboundAction Outbound Action (optional) |
| * @param role Role (reserved, must be NULL) |
| * @param callbackProc Callback processor |
| * @param callbackData Callback data |
| * @param flags Flags |
| * @return Dispatch Handle |
| */ |
| SoapDispatchH wsman_dispatch_create(SoapH soap, |
| char *inboundAction, char *outboundAction, //optional |
| char *role, //reserved, must be NULL |
| SoapServiceCallback callbackProc, |
| void *callbackData, |
| unsigned long flags) |
| { |
| |
| SoapDispatchH disp = NULL; |
| if (soap && role == NULL) { |
| disp = create_dispatch_entry(soap, inboundAction, |
| outboundAction, role, |
| callbackProc, callbackData, |
| flags); |
| } |
| return disp; |
| } |
| |
| /* |
| * Start Dispatcher |
| */ |
| void wsman_dispatch_start(SoapDispatchH disp) |
| { |
| list_t *displist = NULL; |
| if (disp) { |
| displist = disp->soap->dispatchList; |
| if (displist != NULL || ( displist = list_create(LISTCOUNT_T_MAX) )) { |
| list_append(displist, &(disp)->node); |
| } |
| } |
| } |
| |
| |
| SoapDispatchH wsman_dispatch_entry_new(void) |
| { |
| return (SoapDispatchH) u_zalloc(sizeof(struct __dispatch_t)); |
| } |
| |
| |
| |
| /** @} */ |