diff options
Diffstat (limited to 'src/soap.c')
-rw-r--r-- | src/soap.c | 1322 |
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 */ + + |