summaryrefslogtreecommitdiff
path: root/src/soap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soap.c')
-rw-r--r--src/soap.c1322
1 files changed, 1322 insertions, 0 deletions
diff --git a/src/soap.c b/src/soap.c
new file mode 100644
index 00000000..3757e1ad
--- /dev/null
+++ b/src/soap.c
@@ -0,0 +1,1322 @@
+/**
+ * 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>
+ */
+#include "globals.h"
+
+#ifndef XMLSEC_NO_SOAP
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/tree.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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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 */
+
+