blob: 6a0abf7501aa20c086cf5552fcb7e0aec7812af0 [file] [log] [blame]
/*******************************************************************************
* 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));
}
/** @} */