diff -r 000000000000 -r e35f40988205 xmlsecurityengine/xmlsec/src/xmlsec_soap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xmlsecurityengine/xmlsec/src/xmlsec_soap.c Thu Dec 17 09:29:21 2009 +0200 @@ -0,0 +1,1347 @@ +/** + * 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 + * 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 +#include + +#include +#include + +#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/): + * + * + * + * + * + * + * + * + * + * + * + * Returns pointer to newly created 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 node. + * + * Gets the pointer to node (if necessary, the node + * is created). + * + * XML Schema (http://schemas.xmlsoap.org/soap/envelope/): + * + * + * + * + * + * + * + * + * + * Returns pointer to 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 node. + * @entryNode: the pointer to body entry node. + * + * Adds a new entry to 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 node. + * @faultCodeHref: the fault code QName href (must be known in th context of + * 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 entry to the @envNode. Note that only one + * entry is allowed. + * + * XML Schema (http://schemas.xmlsoap.org/soap/envelope/): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * 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 node. + * + * Validates node structure. + * + * Returns 1 if @envNode has a valid 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 node. + * + * Gets pointer to the node. + * + * Returns pointer to 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 node. + * + * Gets pointer to the node. + * + * Returns pointer to 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 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 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 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): + * + * + * + * + * + * + * + * + * + * + * Returns pointer to newly created 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 node. + * + * Gets the pointer to node (if necessary, the node + * is created). + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * + * + * + * + * + * + * + * + * Returns pointer to 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 node. + * @entryNode: the pointer to body entry node. + * + * Adds a new entry to node. + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * + * + * + * + * + * + * + * + * 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 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 entry to the @envNode. Note that only one + * entry is allowed. + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * 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 node. + * @subCodeHref: the subcode href. + * @subCodeName: the subcode name. + * + * Adds a new node to the node or the last node. + * + * Returns a pointer to the newly created 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 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 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 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 node. + * + * Validates node structure. + * + * Returns 1 if @envNode has a valid 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 node. + * + * Gets pointer to the node. + * + * Returns pointer to 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 node. + * + * Gets pointer to the node. + * + * Returns pointer to 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 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 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 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 */ + +