>From 4a54e5d3b708734e2526dee20143928d55e8960b Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Thu, 27 Oct 2011 20:30:45 +0400
Subject: [PATCH 1/1] Block attempt to modify namespace definition with setAttribute()

---
 dlls/msxml3/element.c      |   20 ++++++++-
 dlls/msxml3/tests/domdoc.c |   99 +++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 106 insertions(+), 13 deletions(-)

diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c
index 6cd3a6d..834f39b 100644
--- a/dlls/msxml3/element.c
+++ b/dlls/msxml3/element.c
@@ -1097,8 +1097,8 @@ static HRESULT WINAPI domelem_setAttribute(
     BSTR name, VARIANT value)
 {
     domelem *This = impl_from_IXMLDOMElement( iface );
+    xmlChar *xml_name, *xml_value, *local, *prefix;
     xmlNodePtr element;
-    xmlChar *xml_name, *xml_value;
     HRESULT hr;
     VARIANT var;
 
@@ -1119,7 +1119,23 @@ static HRESULT WINAPI domelem_setAttribute(
     xml_name = xmlchar_from_wchar( name );
     xml_value = xmlchar_from_wchar( V_BSTR(&var) );
 
-    if(!xmlSetNsProp(element, NULL,  xml_name, xml_value))
+    if ((local = xmlSplitQName2(xml_name, &prefix)))
+    {
+        static const xmlChar* xmlnsA = (const xmlChar*)"xmlns";
+        xmlNsPtr ns = NULL;
+
+        /* it's not allowed to modify existing namespace definition */
+        if (xmlStrEqual(prefix, xmlnsA))
+            ns = xmlSearchNs(element->doc, element, local);
+
+        xmlFree(prefix);
+        xmlFree(local);
+
+        if (ns)
+            return xmlStrEqual(ns->href, xml_value) ? S_OK : E_INVALIDARG;
+    }
+
+    if (!xmlSetNsProp(element, NULL, xml_name, xml_value))
         hr = E_FAIL;
 
     heap_free(xml_value);
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 0acfa25..62ccb4e 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -6995,19 +6995,22 @@ static void test_testTransforms(void)
 
 static void test_Namespaces(void)
 {
+    static const CHAR szNamespacesXML[] =
+        "<?xml version=\"1.0\"?>\n"
+        "<XMI xmi.version=\"1.1\" xmlns:Model=\"http://omg.org/mof.Model/1.3\">"
+        "  <XMI.content>"
+        "    <Model:Package name=\"WinePackage\" />"
+        "  </XMI.content>"
+        "</XMI>";
+
     IXMLDOMDocument *doc;
-    IXMLDOMNode *pNode;
+    IXMLDOMElement *elem;
+    IXMLDOMNode *node;
     IXMLDOMNode *pNode2 = NULL;
     VARIANT_BOOL bSucc;
+    VARIANT var;
     HRESULT hr;
     BSTR str;
-    static  const CHAR szNamespacesXML[] =
-"<?xml version=\"1.0\"?>\n"
-"<XMI xmi.version=\"1.1\" xmlns:Model=\"http://omg.org/mof.Model/1.3\">"
-"  <XMI.content>"
-"    <Model:Package name=\"WinePackage\" />"
-"  </XMI.content>"
-"</XMI>";
 
     doc = create_document(&IID_IXMLDOMDocument);
     if (!doc) return;
@@ -7016,11 +7019,11 @@ static void test_Namespaces(void)
     ok(hr == S_OK, "ret %08x\n", hr );
     ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n");
 
-    hr = IXMLDOMDocument_selectSingleNode(doc, _bstr_("//XMI.content"), &pNode );
+    hr = IXMLDOMDocument_selectSingleNode(doc, _bstr_("//XMI.content"), &node );
     ok(hr == S_OK, "ret %08x\n", hr );
     if(hr == S_OK)
     {
-        hr = IXMLDOMNode_get_firstChild( pNode, &pNode2 );
+        hr = IXMLDOMNode_get_firstChild( node, &pNode2 );
         ok( hr == S_OK, "ret %08x\n", hr );
         ok( pNode2 != NULL, "pNode2 == NULL\n");
 
@@ -7050,11 +7053,85 @@ static void test_Namespaces(void)
         SysFreeString(str);
 
         IXMLDOMNode_Release(pNode2);
-        IXMLDOMNode_Release(pNode);
+        IXMLDOMNode_Release(node);
     }
 
     IXMLDOMDocument_Release(doc);
 
+    /* create on element and try to alter namespace after that */
+    doc = create_document(&IID_IXMLDOMDocument);
+    if (!doc) return;
+
+    V_VT(&var) = VT_I2;
+    V_I2(&var) = NODE_ELEMENT;
+
+    hr = IXMLDOMDocument_createNode(doc, var, _bstr_("ns:elem"), _bstr_("ns/uri"), &node);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMDocument_appendChild(doc, node, NULL);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &elem);
+    EXPECT_HR(hr, S_OK);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = _bstr_("ns/uri2");
+
+    hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var);
+    EXPECT_HR(hr, E_INVALIDARG);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = _bstr_("ns/uri");
+
+    hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMElement_get_xml(elem, &str);
+    EXPECT_HR(hr, S_OK);
+    ok(!lstrcmpW(str, _bstr_("<ns:elem xmlns:ns=\"ns/uri\"/>")), "got element %s\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMElement_Release(elem);
+    IXMLDOMDocument_Release(doc);
+
+    /* create on element and try to alter namespace after that */
+    doc = create_document_version(60, &IID_IXMLDOMDocument);
+    if (!doc) return;
+
+    V_VT(&var) = VT_I2;
+    V_I2(&var) = NODE_ELEMENT;
+
+    hr = IXMLDOMDocument_createNode(doc, var, _bstr_("ns:elem"), _bstr_("ns/uri"), &node);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMDocument_appendChild(doc, node, NULL);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &elem);
+    EXPECT_HR(hr, S_OK);
+
+    /* try same prefix, different uri */
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = _bstr_("ns/uri2");
+
+    hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var);
+    EXPECT_HR(hr, E_INVALIDARG);
+
+    /* try same prefix and uri */
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = _bstr_("ns/uri");
+
+    hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMElement_get_xml(elem, &str);
+    EXPECT_HR(hr, S_OK);
+    ok(!lstrcmpW(str, _bstr_("<ns:elem xmlns:ns=\"ns/uri\"/>")), "got element %s\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMElement_Release(elem);
+    IXMLDOMDocument_Release(doc);
+
     free_bstrs();
 }
 
-- 
1.5.6.5

