/**
* XML Security Library (http://www.aleksey.com/xmlsec).
*
* Simple SOAP messages parsing/creation.
*
* This is free software; see Copyright file in the source
* distribution for preciese wording.
*
* Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
* Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
*/
#include "xmlsec_config.h"
#ifndef XMLSEC_NO_SOAP
#include "xmlsec_globals.h"
#include <stdlib.h>
#include <string.h>
#include <libxml2_tree.h>
#include <libxml2_globals.h>
#include "xmlsec_xmlsec.h"
#include "xmlsec_xmltree.h"
#include "xmlsec_soap.h"
#include "xmlsec_errors.h"
/***********************************************************************
*
* SOAP 1.1
*
**********************************************************************/
/**
* xmlSecSoap11CreateEnvelope:
* @doc: the parent doc (might be NULL).
*
* Creates a new SOAP Envelope node. Caller is responsible for
* adding the returned node to the XML document.
*
* XML Schema (http://schemas.xmlsoap.org/soap/envelope/):
*
* <xs:element name="Envelope" type="tns:Envelope"/>
* <xs:complexType name="Envelope">
* <xs:sequence>
* <xs:element ref="tns:Header" minOccurs="0"/>
* <xs:element ref="tns:Body" minOccurs="1"/>
* <xs:any namespace="##other" minOccurs="0"
* maxOccurs="unbounded" processContents="lax"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##other" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to newly created <soap:Envelope> node or NULL
* if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11CreateEnvelope(xmlDocPtr doc) {
xmlNodePtr envNode;
xmlNodePtr bodyNode;
xmlNsPtr ns;
/* create Envelope node */
envNode = xmlNewDocNode(doc, NULL, xmlSecNodeEnvelope, NULL);
if(envNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlNewDocNode",
XMLSEC_ERRORS_R_XML_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeEnvelope));
return(NULL);
}
ns = xmlNewNs(envNode, xmlSecSoap11Ns, NULL) ;
if(ns == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlNewNs",
XMLSEC_ERRORS_R_XML_FAILED,
"ns=%s",
xmlSecErrorsSafeString(xmlSecSoap11Ns));
xmlFreeNode(envNode);
return(NULL);
}
xmlSetNs(envNode, ns);
/* add required Body node */
bodyNode = xmlSecAddChild(envNode, xmlSecNodeBody, xmlSecSoap11Ns);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeBody));
xmlFreeNode(envNode);
return(NULL);
}
return(envNode);
}
/**
* xmlSecSoap11EnsureHeader:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets the pointer to <soap:Header> node (if necessary, the node
* is created).
*
* XML Schema (http://schemas.xmlsoap.org/soap/envelope/):
*
* <xs:element name="Header" type="tns:Header"/>
* <xs:complexType name="Header">
* <xs:sequence>
* <xs:any namespace="##other" minOccurs="0"
* maxOccurs="unbounded" processContents="lax"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##other" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to <soap:Header> node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11EnsureHeader(xmlNodePtr envNode) {
xmlNodePtr hdrNode;
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* try to find Header node first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) {
return(cur);
}
/* if the first element child is not Header then it is Body */
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap11Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
/* finally add Header node before body */
hdrNode = xmlSecAddPrevSibling(cur, xmlSecNodeHeader, xmlSecSoap11Ns);
if(hdrNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddPrevSibling",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(hdrNode);
}
/**
* xmlSecSoap11AddBodyEntry:
* @envNode: the pointer to <soap:Envelope> node.
* @entryNode: the pointer to body entry node.
*
* Adds a new entry to <soap:Body> node.
*
* Returns pointer to the added entry (@contentNode) or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11AddBodyEntry(xmlNodePtr envNode, xmlNodePtr entryNode) {
xmlNodePtr bodyNode;
xmlSecAssert2(envNode != NULL, NULL);
xmlSecAssert2(entryNode != NULL, NULL);
bodyNode = xmlSecSoap11GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap11GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(xmlSecAddChildNode(bodyNode, entryNode));
}
/**
* xmlSecSoap11AddFaultEntry:
* @envNode: the pointer to <soap:Envelope> node.
* @faultCodeHref: the fault code QName href (must be known in th context of
* <soap:Body> node).
* @faultCodeLocalPart: the fault code QName LocalPart.
* @faultString: the human readable explanation of the fault.
* @faultActor: the information about who caused the fault (might be NULL).
*
* Adds <soap:Fault> entry to the @envNode. Note that only one <soap:Fault>
* entry is allowed.
*
* XML Schema (http://schemas.xmlsoap.org/soap/envelope/):
*
* <xs:element name="Fault" type="tns:Fault"/>
* <xs:complexType name="Fault" final="extension">
* <xs:sequence>
* <xs:element name="faultcode" type="xs:QName"/>
* <xs:element name="faultstring" type="xs:string"/>
* <xs:element name="faultactor" type="xs:anyURI" minOccurs="0"/>
* <xs:element name="detail" type="tns:detail" minOccurs="0"/>
* </xs:sequence>
* </xs:complexType>
* <xs:complexType name="detail">
* <xs:sequence>
* <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded"
* processContents="lax"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##any" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to the added entry or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11AddFaultEntry(xmlNodePtr envNode, const xmlChar* faultCodeHref,
const xmlChar* faultCodeLocalPart,
const xmlChar* faultString, const xmlChar* faultActor) {
xmlNodePtr bodyNode;
xmlNodePtr faultNode;
xmlNodePtr cur;
xmlChar* qname;
xmlSecAssert2(envNode != NULL, NULL);
xmlSecAssert2(faultCodeLocalPart != NULL, NULL);
xmlSecAssert2(faultString != NULL, NULL);
/* get Body node */
bodyNode = xmlSecSoap11GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap11GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
/* check that we don't have Fault node already */
faultNode = xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap11Ns);
if(faultNode != NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
/* add Fault node */
faultNode = xmlSecAddChild(bodyNode, xmlSecNodeFault, xmlSecSoap11Ns);
if(faultNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeFault));
return(NULL);
}
/* add faultcode node */
cur = xmlSecAddChild(faultNode, xmlSecNodeFaultCode, xmlSecSoap11Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeFaultCode));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* create qname for fault code */
qname = xmlSecGetQName(cur, faultCodeHref, faultCodeLocalPart);
if(qname == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecGetQName",
XMLSEC_ERRORS_R_XML_FAILED,
"node=%s",
xmlSecErrorsSafeString(cur->name));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* set faultcode value */
xmlNodeSetContent(cur, qname);
xmlFree(qname);
/* add faultstring node */
cur = xmlSecAddChild(faultNode, xmlSecNodeFaultString, xmlSecSoap11Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeFaultString));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* set faultstring node */
xmlNodeSetContent(cur, faultString);
if(faultActor != NULL) {
/* add faultactor node */
cur = xmlSecAddChild(faultNode, xmlSecNodeFaultActor, xmlSecSoap11Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeFaultActor));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* set faultactor node */
xmlNodeSetContent(cur, faultActor);
}
return(faultNode);
}
/**
* xmlSecSoap11CheckEnvelope:
* @envNode: the pointer to <soap:Envelope> node.
*
* Validates <soap:Envelope> node structure.
*
* Returns 1 if @envNode has a valid <soap:Envelope> element, 0 if it is
* not valid or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecSoap11CheckEnvelope(xmlNodePtr envNode) {
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, -1);
/* verify envNode itself */
if(!xmlSecCheckNodeName(envNode, xmlSecNodeEnvelope, xmlSecSoap11Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeEnvelope),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(0);
}
/* optional Header node first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) {
cur = xmlSecGetNextElementNode(cur->next);
}
/* required Body node is next */
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap11Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(0);
}
return(1);
}
/**
* xmlSecSoap11GetHeader:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets pointer to the <soap:Header> node.
*
* Returns pointer to <soap:Header> node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11GetHeader(xmlNodePtr envNode) {
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* optional Header node is first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) {
return(cur);
}
return(NULL);
}
/**
* xmlSecSoap11GetBody:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets pointer to the <soap:Body> node.
*
* Returns pointer to <soap:Body> node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11GetBody(xmlNodePtr envNode) {
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* optional Header node first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) {
cur = xmlSecGetNextElementNode(cur->next);
}
/* Body node is next */
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap11Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(cur);
}
/**
* xmlSecSoap11GetBodyEntriesNumber:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets the number of body entries.
*
* Returns the number of body entries.
*/
EXPORT_C
xmlSecSize
xmlSecSoap11GetBodyEntriesNumber(xmlNodePtr envNode) {
xmlSecSize number = 0;
xmlNodePtr bodyNode;
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, 0);
/* get Body node */
bodyNode = xmlSecSoap11GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap11GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(0);
}
cur = xmlSecGetNextElementNode(bodyNode->children);
while(cur != NULL) {
number++;
cur = xmlSecGetNextElementNode(cur->next);
}
return(number);
}
/**
* xmlSecSoap11GetBodyEntry:
* @envNode: the pointer to <soap:Envelope> node.
* @pos: the body entry number.
*
* Gets the body entry number @pos.
*
* Returns pointer to body entry node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11GetBodyEntry(xmlNodePtr envNode, xmlSecSize pos) {
xmlNodePtr bodyNode;
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* get Body node */
bodyNode = xmlSecSoap11GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap11GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
cur = xmlSecGetNextElementNode(bodyNode->children);
while((cur != NULL) && (pos > 0)) {
pos--;
cur = xmlSecGetNextElementNode(cur->next);
}
return(cur);
}
/**
* xmlSecSoap11GetFaultEntry:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets the Fault entry (if any).
*
* Returns pointer to Fault entry or NULL if it does not exist.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap11GetFaultEntry(xmlNodePtr envNode) {
xmlNodePtr bodyNode;
xmlSecAssert2(envNode != NULL, NULL);
/* get Body node */
bodyNode = xmlSecSoap11GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap11GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap11Ns));
}
/***********************************************************************
*
* SOAP 1.2
*
**********************************************************************/
static const xmlSecQName2IntegerInfo gXmlSecSoap12FaultCodeInfo[] =
{
{ xmlSecSoap12Ns, xmlSecSoapFaultCodeVersionMismatch,
xmlSecSoap12FaultCodeVersionMismatch },
{ xmlSecSoap12Ns, xmlSecSoapFaultCodeMustUnderstand,
xmlSecSoap12FaultCodeMustUnderstand },
{ xmlSecSoap12Ns, xmlSecSoapFaultDataEncodningUnknown,
xmlSecSoap12FaultCodeDataEncodingUnknown },
{ xmlSecSoap12Ns, xmlSecSoapFaultCodeSender,
xmlSecSoap12FaultCodeSender },
{ xmlSecSoap12Ns, xmlSecSoapFaultCodeReceiver,
xmlSecSoap12FaultCodeReceiver },
{ NULL, NULL, 0 } /* MUST be last in the list */
};
/**
* xmlSecSoap12CreateEnvelope:
* @doc: the parent doc (might be NULL).
*
* Creates a new SOAP 1.2 Envelope node. Caller is responsible for
* adding the returned node to the XML document.
*
* XML Schema (http://www.w3.org/2003/05/soap-envelope):
*
* <xs:element name="Envelope" type="tns:Envelope"/>
* <xs:complexType name="Envelope">
* <xs:sequence>
* <xs:element ref="tns:Header" minOccurs="0"/>
* <xs:element ref="tns:Body" minOccurs="1"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##other" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to newly created <soap:Envelope> node or NULL
* if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12CreateEnvelope(xmlDocPtr doc) {
xmlNodePtr envNode;
xmlNodePtr bodyNode;
xmlNsPtr ns;
/* create Envelope node */
envNode = xmlNewDocNode(doc, NULL, xmlSecNodeEnvelope, NULL);
if(envNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlNewDocNode",
XMLSEC_ERRORS_R_XML_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeEnvelope));
return(NULL);
}
ns = xmlNewNs(envNode, xmlSecSoap12Ns, NULL) ;
if(ns == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlNewNs",
XMLSEC_ERRORS_R_XML_FAILED,
"ns=%s",
xmlSecErrorsSafeString(xmlSecSoap12Ns));
xmlFreeNode(envNode);
return(NULL);
}
xmlSetNs(envNode, ns);
/* add required Body node */
bodyNode = xmlSecAddChild(envNode, xmlSecNodeBody, xmlSecSoap12Ns);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeBody));
xmlFreeNode(envNode);
return(NULL);
}
return(envNode);
}
/**
* xmlSecSoap12EnsureHeader:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets the pointer to <soap:Header> node (if necessary, the node
* is created).
*
* XML Schema (http://www.w3.org/2003/05/soap-envelope):
*
* <xs:element name="Header" type="tns:Header"/>
* <xs:complexType name="Header">
* <xs:sequence>
* <xs:any namespace="##any" processContents="lax"
* minOccurs="0" maxOccurs="unbounded"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##other" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to <soap:Header> node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12EnsureHeader(xmlNodePtr envNode) {
xmlNodePtr hdrNode;
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* try to find Header node first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) {
return(cur);
}
/* if the first element child is not Header then it is Body */
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap12Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
/* finally add Header node before body */
hdrNode = xmlSecAddPrevSibling(cur, xmlSecNodeHeader, xmlSecSoap12Ns);
if(hdrNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddPrevSibling",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(hdrNode);
}
/**
* xmlSecSoap12AddBodyEntry:
* @envNode: the pointer to <soap:Envelope> node.
* @entryNode: the pointer to body entry node.
*
* Adds a new entry to <soap:Body> node.
*
* XML Schema (http://www.w3.org/2003/05/soap-envelope):
*
* <xs:element name="Body" type="tns:Body"/>
* <xs:complexType name="Body">
* <xs:sequence>
* <xs:any namespace="##any" processContents="lax"
* minOccurs="0" maxOccurs="unbounded"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##other" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to the added entry (@contentNode) or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12AddBodyEntry(xmlNodePtr envNode, xmlNodePtr entryNode) {
xmlNodePtr bodyNode;
xmlSecAssert2(envNode != NULL, NULL);
xmlSecAssert2(entryNode != NULL, NULL);
bodyNode = xmlSecSoap12GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap12GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(xmlSecAddChildNode(bodyNode, entryNode));
}
/**
* xmlSecSoap12AddFaultEntry:
* @envNode: the pointer to <soap:Envelope> node.
* @faultCode: the fault code.
* @faultReasonText: the human readable explanation of the fault.
* @faultReasonLang: the language (xml:lang) for @faultReason string.
* @faultNodeURI: the more preciese information about fault source
* (might be NULL).
* @faultRole: the role the node was operating in at the point
* the fault occurred (might be NULL).
*
* Adds <soap:Fault> entry to the @envNode. Note that only one <soap:Fault>
* entry is allowed.
*
* XML Schema (http://www.w3.org/2003/05/soap-envelope):
*
* <xs:element name="Fault" type="tns:Fault"/>
* <xs:complexType name="Fault" final="extension">
* <xs:sequence>
* <xs:element name="Code" type="tns:faultcode"/>
* <xs:element name="Reason" type="tns:faultreason"/>
* <xs:element name="Node" type="xs:anyURI" minOccurs="0"/>
* <xs:element name="Role" type="xs:anyURI" minOccurs="0"/>
* <xs:element name="Detail" type="tns:detail" minOccurs="0"/>
* </xs:sequence>
* </xs:complexType>
*
* <xs:complexType name="faultcode">
* <xs:sequence>
* <xs:element name="Value" type="tns:faultcodeEnum"/>
* <xs:element name="Subcode" type="tns:subcode" minOccurs="0"/>
* </xs:sequence>
* </xs:complexType>
*
* <xs:complexType name="faultreason">
* <xs:sequence>
* <xs:element name="Text" type="tns:reasontext"
* minOccurs="1" maxOccurs="unbounded"/>
* </xs:sequence>
* </xs:complexType>
*
* <xs:complexType name="reasontext">
* <xs:simpleContent>
* <xs:extension base="xs:string">
* <xs:attribute ref="xml:lang" use="required"/>
* </xs:extension>
* </xs:simpleContent>
* </xs:complexType>
*
* <xs:simpleType name="faultcodeEnum">
* <xs:restriction base="xs:QName">
* <xs:enumeration value="tns:DataEncodingUnknown"/>
* <xs:enumeration value="tns:MustUnderstand"/>
* <xs:enumeration value="tns:Receiver"/>
* <xs:enumeration value="tns:Sender"/>
* <xs:enumeration value="tns:VersionMismatch"/>
* </xs:restriction>
* </xs:simpleType>
*
* <xs:complexType name="subcode">
* <xs:sequence>
* <xs:element name="Value" type="xs:QName"/>
* <xs:element name="Subcode" type="tns:subcode" minOccurs="0"/>
* </xs:sequence>
* </xs:complexType>
*
* <xs:complexType name="detail">
* <xs:sequence>
* <xs:any namespace="##any" processContents="lax"
* minOccurs="0" maxOccurs="unbounded"/>
* </xs:sequence>
* <xs:anyAttribute namespace="##other" processContents="lax"/>
* </xs:complexType>
*
* Returns pointer to the added entry or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12AddFaultEntry(xmlNodePtr envNode, xmlSecSoap12FaultCode faultCode,
const xmlChar* faultReasonText, const xmlChar* faultReasonLang,
const xmlChar* faultNodeURI, const xmlChar* faultRole) {
xmlNodePtr bodyNode;
xmlNodePtr faultNode;
xmlNodePtr cur;
int ret;
xmlSecAssert2(envNode != NULL, NULL);
xmlSecAssert2(faultCode != xmlSecSoap12FaultCodeUnknown, NULL);
xmlSecAssert2(faultReasonText != NULL, NULL);
xmlSecAssert2(faultReasonLang != NULL, NULL);
/* get Body node */
bodyNode = xmlSecSoap12GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap12GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
/* check that we don't have Fault node already */
faultNode = xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap12Ns);
if(faultNode != NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
/* add Fault node */
faultNode = xmlSecAddChild(bodyNode, xmlSecNodeFault, xmlSecSoap12Ns);
if(faultNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeFault));
return(NULL);
}
/* add Code node */
cur = xmlSecAddChild(faultNode, xmlSecNodeCode, xmlSecSoap12Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeCode));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* write the fault code in Value child */
ret = xmlSecQName2IntegerNodeWrite(gXmlSecSoap12FaultCodeInfo, cur,
xmlSecNodeValue, xmlSecSoap12Ns,
faultCode);
if(ret < 0) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecQName2IntegerNodeWrite",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"faultCode=%d",
faultCode);
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* add Reason node */
cur = xmlSecAddChild(faultNode, xmlSecNodeReason, xmlSecSoap12Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeReason));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
/* Add Reason/Text node */
if(xmlSecSoap12AddFaultReasonText(faultNode, faultReasonText, faultReasonLang) == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap12AddFaultReasonText",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"text=%s",
xmlSecErrorsSafeString(faultReasonText));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
if(faultNodeURI != NULL) {
/* add Node node */
cur = xmlSecAddChild(faultNode, xmlSecNodeNode, xmlSecSoap12Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeNode));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
xmlNodeSetContent(cur, faultNodeURI);
}
if(faultRole != NULL) {
/* add Role node */
cur = xmlSecAddChild(faultNode, xmlSecNodeRole, xmlSecSoap12Ns);
if(cur == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeRole));
xmlUnlinkNode(faultNode);
xmlFreeNode(faultNode);
return(NULL);
}
xmlNodeSetContent(cur, faultRole);
}
return(faultNode);
}
/**
* xmlSecSoap12AddFaultSubcode:
* @faultNode: the pointer to <Fault> node.
* @subCodeHref: the subcode href.
* @subCodeName: the subcode name.
*
* Adds a new <Subcode> node to the <Code> node or the last <Subcode> node.
*
* Returns a pointer to the newly created <Subcode> node or NULL if an error
* occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12AddFaultSubcode(xmlNodePtr faultNode, const xmlChar* subCodeHref, const xmlChar* subCodeName) {
xmlNodePtr cur, subcodeNode, valueNode;
xmlChar* qname;
xmlSecAssert2(faultNode != NULL, NULL);
xmlSecAssert2(subCodeHref != NULL, NULL);
xmlSecAssert2(subCodeName != NULL, NULL);
/* Code node is the first childern in Fault node */
cur = xmlSecGetNextElementNode(faultNode->children);
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeCode, xmlSecSoap12Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
NULL,
XMLSEC_ERRORS_R_INVALID_NODE,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeCode));
return(NULL);
}
/* find the Code or Subcode node that does not have Subcode child */
while(1) {
xmlNodePtr tmp;
tmp = xmlSecFindChild(cur, xmlSecNodeSubcode, xmlSecSoap12Ns);
if(tmp != NULL) {
cur = tmp;
} else {
break;
}
}
xmlSecAssert2(cur != NULL, NULL);
/* add Subcode node */
subcodeNode = xmlSecAddChild(cur, xmlSecNodeSubcode, xmlSecSoap12Ns);
if(subcodeNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeSubcode));
return(NULL);
}
/* add Value node */
valueNode = xmlSecAddChild(subcodeNode, xmlSecNodeValue, xmlSecSoap12Ns);
if(valueNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeValue));
xmlUnlinkNode(subcodeNode);
xmlFreeNode(subcodeNode);
return(NULL);
}
/* create qname for fault code */
qname = xmlSecGetQName(cur, subCodeHref, subCodeName);
if(qname == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecGetQName",
XMLSEC_ERRORS_R_XML_FAILED,
"node=%s",
xmlSecErrorsSafeString(cur->name));
xmlUnlinkNode(subcodeNode);
xmlFreeNode(subcodeNode);
return(NULL);
}
/* set result qname in Value node */
xmlNodeSetContent(cur, qname);
if(qname != subCodeName) {
xmlFree(qname);
}
return(subcodeNode);
}
/**
* xmlSecSoap12AddFaultReasonText:
* @faultNode: the pointer to <Fault> node.
* @faultReasonText: the new reason text.
* @faultReasonLang: the new reason xml:lang attribute.
*
* Adds a new Text node to the Fault/Reason node.
*
* Returns a pointer to the newly created <Text> node or NULL if an error
* occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12AddFaultReasonText(xmlNodePtr faultNode, const xmlChar* faultReasonText,
const xmlChar* faultReasonLang) {
xmlNodePtr reasonNode;
xmlNodePtr textNode;
xmlSecAssert2(faultNode != NULL, NULL);
xmlSecAssert2(faultReasonText != NULL, NULL);
xmlSecAssert2(faultReasonLang != NULL, NULL);
/* find Reason node */
reasonNode = xmlSecFindChild(faultNode, xmlSecNodeReason, xmlSecSoap12Ns);
if(reasonNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecFindChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeReason));
return(NULL);
}
/* add Text node */
textNode = xmlSecAddChild(reasonNode, xmlSecNodeText, xmlSecSoap12Ns);
if(textNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeText));
return(NULL);
}
xmlNodeSetContent(textNode, faultReasonText);
xmlNodeSetLang(textNode, faultReasonLang);
return(textNode);
}
/**
* xmlSecSoap12AddFaultDetailEntry:
* @faultNode: the pointer to <Fault> node.
* @detailEntryNode: the pointer to detail entry node.
*
* Adds a new child to the Detail child element of @faultNode.
*
* Returns pointer to the added child (@detailEntryNode) or NULL if an error
* occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12AddFaultDetailEntry(xmlNodePtr faultNode, xmlNodePtr detailEntryNode) {
xmlNodePtr detailNode;
xmlSecAssert2(faultNode != NULL, NULL);
xmlSecAssert2(detailEntryNode != NULL, NULL);
/* find Detail node and add it if needed */
detailNode = xmlSecFindChild(faultNode, xmlSecNodeDetail, xmlSecSoap12Ns);
if(detailNode == NULL) {
detailNode = xmlSecAddChild(faultNode, xmlSecNodeDetail, xmlSecSoap12Ns);
if(detailNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecAddChild",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
"node=%s",
xmlSecErrorsSafeString(xmlSecNodeDetail));
return(NULL);
}
}
return(xmlSecAddChildNode(detailNode, detailEntryNode));
}
/**
* xmlSecSoap12CheckEnvelope:
* @envNode: the pointer to <soap:Envelope> node.
*
* Validates <soap:Envelope> node structure.
*
* Returns 1 if @envNode has a valid <soap:Envelope> element, 0 if it is
* not valid or a negative value if an error occurs.
*/
EXPORT_C
int
xmlSecSoap12CheckEnvelope(xmlNodePtr envNode) {
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, -1);
/* verify envNode itself */
if(!xmlSecCheckNodeName(envNode, xmlSecNodeEnvelope, xmlSecSoap12Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeEnvelope),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(0);
}
/* optional Header node first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) {
cur = xmlSecGetNextElementNode(cur->next);
}
/* required Body node is next */
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap12Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(0);
}
return(1);
}
/**
* xmlSecSoap12GetHeader:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets pointer to the <soap:Header> node.
*
* Returns pointer to <soap:Header> node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12GetHeader(xmlNodePtr envNode) {
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* optional Header node is first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) {
return(cur);
}
return(NULL);
}
/**
* xmlSecSoap12GetBody:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets pointer to the <soap:Body> node.
*
* Returns pointer to <soap:Body> node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12GetBody(xmlNodePtr envNode) {
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* optional Header node first */
cur = xmlSecGetNextElementNode(envNode->children);
if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) {
cur = xmlSecGetNextElementNode(cur->next);
}
/* Body node is next */
if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap12Ns)) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
xmlSecErrorsSafeString(xmlSecNodeBody),
XMLSEC_ERRORS_R_NODE_NOT_FOUND,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(cur);
}
/**
* xmlSecSoap12GetBodyEntriesNumber:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets the number of body entries.
*
* Returns the number of body entries.
*/
EXPORT_C
xmlSecSize
xmlSecSoap12GetBodyEntriesNumber(xmlNodePtr envNode) {
xmlSecSize number = 0;
xmlNodePtr bodyNode;
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, 0);
/* get Body node */
bodyNode = xmlSecSoap12GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap12GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(0);
}
cur = xmlSecGetNextElementNode(bodyNode->children);
while(cur != NULL) {
number++;
cur = xmlSecGetNextElementNode(cur->next);
}
return(number);
}
/**
* xmlSecSoap12GetBodyEntry:
* @envNode: the pointer to <soap:Envelope> node.
* @pos: the body entry number.
*
* Gets the body entry number @pos.
*
* Returns pointer to body entry node or NULL if an error occurs.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12GetBodyEntry(xmlNodePtr envNode, xmlSecSize pos) {
xmlNodePtr bodyNode;
xmlNodePtr cur;
xmlSecAssert2(envNode != NULL, NULL);
/* get Body node */
bodyNode = xmlSecSoap12GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap12GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
cur = xmlSecGetNextElementNode(bodyNode->children);
while((cur != NULL) && (pos > 0)) {
pos--;
cur = xmlSecGetNextElementNode(cur->next);
}
return(cur);
}
/**
* xmlSecSoap12GetFaultEntry:
* @envNode: the pointer to <soap:Envelope> node.
*
* Gets the Fault entry (if any).
*
* Returns pointer to Fault entry or NULL if it does not exist.
*/
EXPORT_C
xmlNodePtr
xmlSecSoap12GetFaultEntry(xmlNodePtr envNode) {
xmlNodePtr bodyNode;
xmlSecAssert2(envNode != NULL, NULL);
/* get Body node */
bodyNode = xmlSecSoap12GetBody(envNode);
if(bodyNode == NULL) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"xmlSecSoap12GetBody",
XMLSEC_ERRORS_R_XMLSEC_FAILED,
XMLSEC_ERRORS_NO_MESSAGE);
return(NULL);
}
return(xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap12Ns));
}
#endif /* XMLSEC_NO_SOAP */