Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: msxml3: Ignore UseInlineSchema property. msxml: Add support for user-defined functions in msxsl:script blocks.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/msxml3/domdoc.c | 11 +- dlls/msxml3/msxml_private.h | 30 +++ dlls/msxml3/node.c | 417 +++++++++++++++++++++++++++++- dlls/msxml3/selection.c | 25 +- dlls/msxml3/xmldoc.c | 27 -- libs/xslt/libxslt/xsltInternals.h | 3 + 6 files changed, 478 insertions(+), 35 deletions(-)
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 8407f914c4f..b53203b9bb2 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -3792,14 +3792,19 @@ HRESULT dom_document_create(MSXML_VERSION version, void **ppObj) return hr; }
-IUnknown* create_domdoc( xmlNodePtr document ) +IUnknown* create_domdoc( xmlNodePtr node ) { + xmlDocPtr doc = (xmlDocPtr)node; IUnknown *obj = NULL; HRESULT hr;
- TRACE("(%p)\n", document); + TRACE("(%p)\n", node);
- hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj); + if (!doc->_private) + xmldoc_init(doc, MSXML6); + xmldoc_add_ref(doc); + + hr = get_domdoc_from_xmldoc(doc, (IXMLDOMDocument3**)&obj); if (FAILED(hr)) return NULL;
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 63d85d3590e..9709f8247ab 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -21,14 +21,43 @@ #ifndef __MSXML_PRIVATE__ #define __MSXML_PRIVATE__
+#include <stdbool.h> + #include "dispex.h"
#include "wine/list.h"
+#include <libxml/xpath.h> + #include "msxml_dispex.h"
extern const CLSID * DOMDocument_version(MSXML_VERSION v);
+static inline bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) +{ + size_t new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return true; + + max_capacity = ~(SIZE_T)0 / size; + if (count > max_capacity) + return false; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = realloc(*elements, new_capacity * size))) + return false; + + *elements = new_elements; + *capacity = new_capacity; + return true; +}
/* The XDR datatypes (urn:schemas-microsoft-com:datatypes) * These are actually valid for XSD schemas as well @@ -139,6 +168,7 @@ extern IUnknown *create_doc_fragment( xmlNodePtr ); extern IUnknown *create_doc_entity_ref( xmlNodePtr ); extern IUnknown *create_doc_type( xmlNodePtr ); extern HRESULT create_selection( xmlNodePtr, xmlChar*, IXMLDOMNodeList** ); +extern HRESULT create_selection_from_nodeset( xmlXPathObjectPtr, IXMLDOMNodeList ** ); extern HRESULT create_enumvariant( IUnknown*, BOOL, const struct enumvariant_funcs*, IEnumVARIANT**); extern HRESULT create_dom_implementation(IXMLDOMImplementation **obj);
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index 5a3238edca8..23d496b64c9 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -33,6 +33,8 @@ #include <libxslt/xsltutils.h> #include <libxslt/xsltInternals.h> #include <libxslt/documents.h> +#include <libxslt/extensions.h> +#include <libxslt/xsltInternals.h>
#include "windef.h" #include "winbase.h" @@ -40,6 +42,7 @@ #include "winnls.h" #include "ole2.h" #include "msxml6.h" +#include <activscp.h>
#include "msxml_private.h"
@@ -1477,6 +1480,396 @@ failed: return doc; }
+#ifdef _WIN64 + +#define IActiveScriptParse_Release IActiveScriptParse64_Release +#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew +#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText + +#else + +#define IActiveScriptParse_Release IActiveScriptParse32_Release +#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew +#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText + +#endif + +struct xsl_scripts +{ + struct + { + IActiveScript *script; + const xmlChar *uri; + } *entries; + size_t count; + size_t capacity; +}; + +static IActiveScript *xpath_msxsl_script_get_script(xmlXPathParserContextPtr ctxt, const xmlChar *uri) +{ + xsltTransformContextPtr xslt_ctxt = xsltXPathGetTransformContext(ctxt); + struct xsl_scripts *scripts = xslt_ctxt->userData; + + for (size_t i = 0; i < scripts->count; ++i) + { + if (xmlStrEqual(scripts->entries[i].uri, uri)) + return scripts->entries[i].script; + } + + return NULL; +} + +static HRESULT xpath_create_nodelist_from_set(xmlNodeSetPtr set, bool needs_copy, IXMLDOMNodeList **ret) +{ + xmlNodeSet _copy = { 0 }; + xmlXPathObjectPtr obj; + HRESULT hr; + + if (needs_copy) + { + _copy.nodeTab = xmlMalloc(set->nodeNr * sizeof(*set->nodeTab)); + _copy.nodeNr = set->nodeNr; + _copy.nodeMax = set->nodeNr; + for (int i = 0; i < set->nodeNr; ++i) + _copy.nodeTab[i] = xmlCopyNode(set->nodeTab[i], 1); + set = &_copy; + } + + obj = xmlXPathNewNodeSetList(set); + hr = create_selection_from_nodeset(obj, ret); + xmlFree(_copy.nodeTab); + + return hr; +} + +static void xpath_msxsl_script_function(xmlXPathParserContextPtr ctxt, int nargs) +{ + xsltTransformContextPtr xslt_ctxt = xsltXPathGetTransformContext(ctxt); + xmlXPathContextPtr xpath = ((struct _xsltTransformContext *)xslt_ctxt)->xpathCtxt; + DISPPARAMS params = { 0 }; + IActiveScript *script; + VARIANT *args = NULL; + IDispatch *disp; + VARIANT result; + DISPID dispid; + HRESULT hr; + BSTR name; + + TRACE("%s:%s\n", xpath->functionURI, xpath->function); + + script = xpath_msxsl_script_get_script(ctxt, xpath->functionURI); + if (!script) + { + WARN("Couldn't find a script for %s.\n", xpath->functionURI); + return; + } + + if (FAILED(IActiveScript_GetScriptDispatch(script, NULL, &disp))) + return; + + name = bstr_from_xmlChar(xpath->function); + hr = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + SysFreeString(name); + if (FAILED(hr)) + { + WARN("Couldn't find %s function.\n", xpath->function); + IDispatch_Release(disp); + return; + } + + if (nargs) + { + args = calloc(nargs, sizeof(*args)); + + for (int i = 0; i < nargs; ++i) + { + xmlXPathObjectType obj_type = XPATH_UNDEFINED; + xmlXPathObjectPtr obj = NULL; + xmlChar *s; + + /* Since we don't want to impose expectations on argument types, + first inspect actual type on stack, and then pop with corresponding function. */ + if (ctxt->valueNr > 0) + { + obj = ctxt->valueTab[ctxt->valueNr - 1]; + obj_type = obj->type; + } + + switch (obj_type) + { + case XPATH_XSLT_TREE: + case XPATH_NODESET: + { + xmlNodeSetPtr nodeset = xmlXPathPopNodeSet(ctxt); + IXMLDOMNodeList *nodelist; + + hr = xpath_create_nodelist_from_set(nodeset, obj_type == XPATH_XSLT_TREE, &nodelist); + + V_VT(&args[i]) = VT_DISPATCH; + V_DISPATCH(&args[i]) = (IDispatch *)nodelist; + break; + } + case XPATH_STRING: + s = xmlXPathPopString(ctxt); + V_VT(&args[i]) = VT_BSTR; + V_BSTR(&args[i]) = bstr_from_xmlChar(s); + xmlFree(s); + break; + case XPATH_NUMBER: + V_VT(&args[i]) = VT_R8; + V_R8(&args[i]) = xmlXPathPopNumber(ctxt); + break; + case XPATH_BOOLEAN: + V_VT(&args[i]) = VT_BOOL; + V_BOOL(&args[i]) = xmlXPathPopBoolean(ctxt) ? VARIANT_TRUE : VARIANT_FALSE; + break; + default: + FIXME("Unexpected XPath (%s) value type %d.\n", xpath->function, obj->type); + return; + } + } + + params.rgvarg = args; + params.cArgs = nargs; + } + + VariantInit(&result); + hr = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, ¶ms, &result, NULL, NULL); + if (FAILED(hr)) + WARN("User script Invoke() failed %#lx, function %s.\n", hr, xpath->function); + + if (args) + { + for (int i = 0; i < nargs; ++i) + VariantClear(&args[i]); + free(args); + } + + switch (V_VT(&result)) + { + case VT_BSTR: + { + xmlChar *s = xmlchar_from_wchar(V_BSTR(&result)); + xmlXPathReturnString(ctxt, s); + break; + } + case VT_BOOL: + xmlXPathReturnBoolean(ctxt, !!V_BOOL(&result)); + break; + case VT_INT: + case VT_I1: + case VT_UI1: + case VT_I2: + case VT_UI2: + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_R8: + VariantChangeType(&result, &result, 0, VT_R8); + xmlXPathReturnNumber(ctxt, V_R8(&result)); + break; + case VT_EMPTY: + xmlXPathReturnEmptyString(ctxt); + break; + default: + FIXME("Unexpected return value %s.\n", debugstr_variant(&result)); + xmlXPathReturnEmptyString(ctxt); + } + + IDispatch_Release(disp); + VariantClear(&result); +} + +static HRESULT WINAPI msxsl_script_site_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **obj) +{ + if (IsEqualGUID(&IID_IUnknown, riid) + || IsEqualGUID(&IID_IActiveScriptSite, riid)) + { + *obj = iface; + IActiveScriptSite_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI msxsl_script_site_AddRef(IActiveScriptSite *iface) +{ + return 2; +} + +static ULONG WINAPI msxsl_script_site_Release(IActiveScriptSite *iface) +{ + return 1; +} + +static HRESULT WINAPI msxsl_script_site_GetLCID(IActiveScriptSite *iface, LCID *lcid) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI msxsl_script_site_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR name, + DWORD mask, IUnknown **item, ITypeInfo **typeinfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI msxsl_script_site_GetDocVersionString(IActiveScriptSite *iface, BSTR *version) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI msxsl_script_site_OnScriptTerminate(IActiveScriptSite *iface, + const VARIANT *result, const EXCEPINFO *ei) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI msxsl_script_site_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE state) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI msxsl_script_site_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *script_error) +{ + return S_OK; +} + +static HRESULT WINAPI msxsl_script_site_OnEnterScript(IActiveScriptSite *iface) +{ + return S_OK; +} + +static HRESULT WINAPI msxsl_script_site_OnLeaveScript(IActiveScriptSite *iface) +{ + return S_OK; +} + +static const IActiveScriptSiteVtbl msxsl_script_site_vtbl = +{ + msxsl_script_site_QueryInterface, + msxsl_script_site_AddRef, + msxsl_script_site_Release, + msxsl_script_site_GetLCID, + msxsl_script_site_GetItemInfo, + msxsl_script_site_GetDocVersionString, + msxsl_script_site_OnScriptTerminate, + msxsl_script_site_OnStateChange, + msxsl_script_site_OnScriptError, + msxsl_script_site_OnEnterScript, + msxsl_script_site_OnLeaveScript +}; + +static IActiveScriptSite msxsl_script_site = { &msxsl_script_site_vtbl }; + +static void node_transform_bind_scripts(xsltTransformContextPtr ctxt, + xmlDocPtr sheet, struct xsl_scripts *scripts) +{ + xmlNodePtr root, child, node; + xmlNsPtr ns; + + root = xmlDocGetRootElement(sheet); + for (node = root->children; node; node = node->next) + { + if (xmlStrEqual(node->name, BAD_CAST "script") + && node->ns + && xmlStrEqual(node->ns->prefix, BAD_CAST "msxsl") + && xmlStrEqual(node->ns->href, BAD_CAST "urn:schemas-microsoft-com:xslt")) + { + child = node->children; + + if (child && child->type == XML_CDATA_SECTION_NODE) + { + IActiveScript *active_script; + xmlChar *language, *prefix; + IActiveScriptParse *parser; + TYPEATTR *typeattr; + BSTR text, progid; + IDispatch *disp; + ITypeInfo *ti; + CLSID clsid; + HRESULT hr; + + if (!(prefix = xmlGetProp(node, BAD_CAST "implements-prefix"))) + { + WARN("msxsl:script without 'implements-prefix'.\n"); + continue; + } + + if (!(ns = xmlSearchNs(sheet, node, prefix))) + { + WARN("Couldn't locate script element namespace for "%s".\n", debugstr_a((char *)prefix)); + continue; + } + + if (!(language = xmlGetProp(node, BAD_CAST "language"))) + language = BAD_CAST "javascript"; + + progid = bstr_from_xmlChar(language); + if (FAILED(hr = CLSIDFromProgID(progid, &clsid))) + WARN("Unknown engine progid %s.\n", debugstr_w(progid)); + SysFreeString(progid); + if (FAILED(hr)) + return; + + if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, + &IID_IActiveScript, (void **)&active_script))) + { + WARN("Failed to create a script engine instance, hr %#lx.\n", hr); + continue; + } + + IActiveScript_QueryInterface(active_script, &IID_IActiveScriptParse, (void **)&parser); + IActiveScript_SetScriptSite(active_script, &msxsl_script_site); + IActiveScriptParse_InitNew(parser); + IActiveScript_SetScriptState(active_script, SCRIPTSTATE_STARTED); + + text = bstr_from_xmlChar(child->content); + hr = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + IActiveScriptParse_Release(parser); + SysFreeString(text); + if (FAILED(hr)) + { + WARN("Failed to parse script for the namespace %s, hr %#lx.\n", prefix, hr); + IActiveScript_Release(active_script); + continue; + } + + IActiveScript_GetScriptDispatch(active_script, NULL, &disp); + IDispatch_GetTypeInfo(disp, 0, LOCALE_USER_DEFAULT, &ti); + + ITypeInfo_GetTypeAttr(ti, &typeattr); + + for (int i = 0; i < typeattr->cFuncs; ++i) + { + FUNCDESC *funcdesc; + xmlChar *func_name; + BSTR name; + + ITypeInfo_GetFuncDesc(ti, i, &funcdesc); + ITypeInfo_GetDocumentation(ti, funcdesc->memid, &name, NULL, NULL, NULL); + func_name = xmlchar_from_wchar(name); + + xsltRegisterExtFunction(ctxt, func_name, ns->href, xpath_msxsl_script_function); + + SysFreeString(name); + free(func_name); + } + + IDispatch_Release(disp); + ITypeInfo_Release(ti); + + array_reserve((void **)&scripts->entries, &scripts->capacity, scripts->count + 1, sizeof(*scripts->entries)); + + scripts->entries[scripts->count].script = active_script; + scripts->entries[scripts->count].uri = ns->href; + scripts->count++; + } + } + } +} + HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, BSTR *p, ISequentialStream *stream, const struct xslprocessor_params *params) { @@ -1496,7 +1889,9 @@ HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, xsltSS = xsltParseStylesheetDoc(sheet_doc); if (xsltSS) { + struct xsl_scripts scripts = { 0 }; const char **xslparams = NULL; + xsltTransformContextPtr ctxt; xmlDocPtr result; unsigned int i;
@@ -1515,21 +1910,35 @@ HRESULT node_transform_node_params(const xmlnode *This, IXMLDOMNode *stylesheet, xslparams[i] = NULL; }
+ ctxt = xsltNewTransformContext(xsltSS, This->node->doc); + + node_transform_bind_scripts(ctxt, sheet_doc, &scripts); + ctxt->userData = &scripts; + if (xslparams) { - xsltTransformContextPtr ctxt = xsltNewTransformContext(xsltSS, This->node->doc); - /* push parameters to user context */ xsltQuoteUserParams(ctxt, xslparams); result = xsltApplyStylesheetUser(xsltSS, This->node->doc, NULL, NULL, NULL, ctxt); - xsltFreeTransformContext(ctxt);
for (i = 0; i < params->count*2; i++) free((char*)xslparams[i]); free(xslparams); } else - result = xsltApplyStylesheet(xsltSS, This->node->doc, NULL); + { + result = xsltApplyStylesheetUser(xsltSS, This->node->doc, NULL, NULL, NULL, ctxt); + } + + for (size_t i = 0; i < scripts.count; ++i) + { + if (scripts.entries[i].script) + IActiveScript_Release(scripts.entries[i].script); + } + free(scripts.entries); + + ctxt->userData = NULL; + xsltFreeTransformContext(ctxt);
if (result) { diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c index 21441f314ce..e752f59b347 100644 --- a/dlls/msxml3/selection.c +++ b/dlls/msxml3/selection.c @@ -169,7 +169,8 @@ static ULONG WINAPI domselection_Release( if ( ref == 0 ) { xmlXPathFreeObject(This->result); - xmldoc_release(This->node->doc); + if (This->node) + xmldoc_release(This->node->doc); if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant); free(This); } @@ -833,3 +834,25 @@ cleanup: xmlXPathFreeContext(ctxt); return hr; } + +HRESULT create_selection_from_nodeset(xmlXPathObjectPtr nodeset, IXMLDOMNodeList **out) +{ + domselection *obj; + + TRACE("%p, %p.\n", nodeset, out); + + *out = NULL; + + if (!(obj = calloc(1, sizeof(*obj)))) + return E_OUTOFMEMORY; + + obj->IXMLDOMSelection_iface.lpVtbl = &domselection_vtbl; + obj->ref = 1; + init_dispex(&obj->dispex, (IUnknown *)&obj->IXMLDOMSelection_iface, &domselection_dispex); + + obj->result = nodeset; + + *out = (IXMLDOMNodeList *)&obj->IXMLDOMSelection_iface; + + return S_OK; +} diff --git a/dlls/msxml3/xmldoc.c b/dlls/msxml3/xmldoc.c index 93674bf06e8..125d041c8f8 100644 --- a/dlls/msxml3/xmldoc.c +++ b/dlls/msxml3/xmldoc.c @@ -22,7 +22,6 @@ #define COBJMACROS
#include <stdarg.h> -#include <stdbool.h> #include <libxml/parser.h>
#include "windef.h" @@ -300,32 +299,6 @@ struct parse_context } dtd; };
-static bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) -{ - size_t new_capacity, max_capacity; - void *new_elements; - - if (count <= *capacity) - return true; - - max_capacity = ~(SIZE_T)0 / size; - if (count > max_capacity) - return false; - - new_capacity = max(4, *capacity); - while (new_capacity < count && new_capacity <= max_capacity / 2) - new_capacity *= 2; - if (new_capacity < count) - new_capacity = max_capacity; - - if (!(new_elements = realloc(*elements, new_capacity * size))) - return false; - - *elements = new_elements; - *capacity = new_capacity; - return true; -} - static HRESULT text_buffer_append(struct buffer *buffer, const WCHAR *chars, int count) { if (!count) diff --git a/libs/xslt/libxslt/xsltInternals.h b/libs/xslt/libxslt/xsltInternals.h index be50678c4b6..a187802558f 100644 --- a/libs/xslt/libxslt/xsltInternals.h +++ b/libs/xslt/libxslt/xsltInternals.h @@ -1799,6 +1799,9 @@ struct _xsltTransformContext { xsltNewLocaleFunc newLocale; xsltFreeLocaleFunc freeLocale; xsltGenSortKeyFunc genSortKey; + + /* Wine extension */ + void *userData; };
/**
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/msxml3/domdoc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index b53203b9bb2..f35daff5f6d 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -3184,7 +3184,8 @@ static HRESULT WINAPI domdoc_setProperty( wcsicmp(p, L"AllowXsltScript") == 0 || wcsicmp(p, L"NormalizeAttributeValues") == 0 || wcsicmp(p, L"AllowDocumentFunction") == 0 || - wcsicmp(p, L"MaxElementDepth") == 0) + wcsicmp(p, L"MaxElementDepth") == 0 || + wcsicmp(p, L"UseInlineSchema") == 0) { /* Ignore */ FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
Jacek Caban (@jacek) commented about dlls/msxml3/node.c:
WARN("Couldn't locate script element namespace for \"%s\".\n", debugstr_a((char *)prefix));continue;}if (!(language = xmlGetProp(node, BAD_CAST "language")))language = BAD_CAST "javascript";progid = bstr_from_xmlChar(language);if (FAILED(hr = CLSIDFromProgID(progid, &clsid)))WARN("Unknown engine progid %s.\n", debugstr_w(progid));SysFreeString(progid);if (FAILED(hr))return;if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,&IID_IActiveScript, (void **)&active_script)))
t looks a bit suspicious. In cases like this, the usual behavior would be to create one engine per script language and share it between all scripts in the same context (and using the same language). Creating a script engine is expensive, and you generally want scripts in the same context to be able to call each other freely and access each other’s properties.
(In more complex hosts, like MSHTML, we also need to allow cross-language access between scripts written in different languages, but that’s probably not a concern here.)
This should probably use `INTERFACE_USES_SECURITY_MANAGER` and propagate `QueryService(SID_SInternetHostSecurityManager)` when appropriate, likely based on `IObjectWithSite`. Otherwise, unsafe scripts could use this to bypass the security manager. For example, a webpage could create an XML document and then run xpath with a malicious script; if that script isn’t subject to the security manager, it could freely create objects like `Scripting.FileSystemObject`.
On Wed Nov 26 11:10:14 2025 +0000, Jacek Caban wrote:
This should probably use `INTERFACE_USES_SECURITY_MANAGER` and propagate `QueryService(SID_SInternetHostSecurityManager)` when appropriate, likely based on `IObjectWithSite`. Otherwise, unsafe scripts could use this to bypass the security manager. For example, a webpage could create an XML document and then run xpath with a malicious script; if that script isn’t subject to the security manager, it could freely create objects like `Scripting.FileSystemObject`.
Do we have an example of how this works?
On Wed Nov 26 10:54:49 2025 +0000, Jacek Caban wrote:
t looks a bit suspicious. In cases like this, the usual behavior would be to create one engine per script language and share it between all scripts in the same context (and using the same language). Creating a script engine is expensive, and you generally want scripts in the same context to be able to call each other freely and access each other’s properties. (In more complex hosts, like MSHTML, we also need to allow cross-language access between scripts written in different languages, but that’s probably not a concern here.)
They are all in separate contexts, script can't call functions from another msxsl:script block. You can have two functions of the same name in separate blocks, and use one or another in xslt using specific namespace, as ns:func1 or ns2:func1.
On Wed Nov 26 11:10:14 2025 +0000, Nikolay Sivov wrote:
Do we have an example of how this works?
Not not exactly like that, but we do have various implementations of separate bits. domdoc already supports `IObjectSafety`, so it could simply propagate those flags to the script engine during initialization. For the script site, it would need to implement `IServiceProvider` and likely just forward queries to the site set via `IObjectWithSite`.
Since script engines are pluggable, it should be possible to write a test using a custom script engine to see how MSXML interacts with it. We have some tests like that, but I'm not sure how practical that is here.
On Wed Nov 26 11:21:29 2025 +0000, Nikolay Sivov wrote:
They are all in separate contexts, script can't call functions from another msxsl:script block. You can have two functions of the same name in separate blocks, and use one or another in xslt using specific namespace, as ns:func1 or ns2:func1.
Makes sense then, thanks.
On Wed Nov 26 11:39:39 2025 +0000, Jacek Caban wrote:
Not not exactly like that, but we do have various implementations of separate bits. domdoc already supports `IObjectSafety`, so it could simply propagate those flags to the script engine during initialization. For the script site, it would need to implement `IServiceProvider` and likely just forward queries to the site set via `IObjectWithSite`. Since script engines are pluggable, it should be possible to write a test using a custom script engine to see how MSXML interacts with it. We have some tests like that, but I'm not sure how practical that is here.
BTW, if you want to see this running under a security manager, you can use something like the [attached](/uploads/fc0b343d05757a5ce01d5c860b7cc0d7/test.html) document in Wine `iexplore.exe`. It’s an empty page, but you’ll see the additional initialization done by the security manager in msxml logs.