DOM Document with a Site Object (C++ Code Listing)

 

This topic contains the source code listing for the DOMWithSiteObj project, which implements an XML DOM document that contains a site object (a custom security manager component) that controls access to resources, here a local XML file.

The C/C++ source code in the files listed below performs the following actions:

  1. Creates an IXMLDomDocument object.

  2. Creates a site object and sets the Secure Base URL, Zone Map, and Action Map on the object.

  3. Sets the safety options on the IXMLDomDocument object.

  4. Sets the site object on the IXMLDomDocument object.

  5. Calls the load method on the IXMLDomDocument object, specifying the path to the local XML file, sample.xml.

When run, the load action fails with an “Access is denied” error because the secure base URL is set to www.microsoft.com and the zone map is set to URLZONE_INTERNET. It fails because security options are set for the DOM document, and these disallow moving from the Internet Zone to the Local Machine Zone. If the site object was not set, then loading the local XML file would succeed.

System_CAPS_ICON_note.jpg Note

the following C/C++ code uses smart pointers, which are represented by the _COM_SMARTPTR_TYPEDEF macro and the _com_ptr_t type.

#include "stdafx.h"  
#include <comdef.h>  
#include <objsafe.h>  
#include <string>  
using namespace std;  
#include <msxml6.h>  
#include "msxml2.h"  
#include "SiteImpl.h"  
  
#pragma comment( lib, "msxml6.lib")  
  
_COM_SMARTPTR_TYPEDEF(IObjectSafety, __uuidof(IObjectSafety));  
_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument2, __uuidof(IXMLDOMDocument2));  
_COM_SMARTPTR_TYPEDEF(IXMLDOMParseError, __uuidof(IXMLDOMParseError));  
  
// CLSIDs for MSXML objects (varies with MSXML version).  
#define DOMCLSID CLSID_DOMDocument60  
  
// Helper function that puts output in stdout.  
void dprintf( char* format, ...)  
{  
    va_list args;  
    int len;  
    char* buffer;  
  
    va_start(args, format);  
    len = _vscprintf(format, args) // _vscprintf does not count  
                               + 1; // terminating '\0'  
    buffer = (char*)malloc(len * sizeof(char));  
    vsprintf_s(buffer, len, format, args);  
    puts(buffer);  
    free(buffer);  
}  
  
// Prepares the security manager object.  
IUnknownPtr CreateSecureSite(ZONEMAP* pZoneMap, int nZoneMapCount, ACTIONMAP* pActionMap, int nActionMapCount, LPCWSTR secureBaseURL)  
{  
    if (secureBaseURL == NULL)  
    {  
        dprintf("\nNo secureBaseURL, returning NULL for CreateSecureSite\r\n");  
        return NULL;  
    }  
  
    // Create the Site object.  
    CSiteImpl * pSite = new CSiteImpl(secureBaseURL);  
  
    // Set the Zone and Action maps.  
    pSite->SetZoneMap(pZoneMap, nZoneMapCount);  
    pSite->SetActionMap(pActionMap, nActionMapCount);  
  
    IUnknownPtr pSitePtr(pSite);  
    return pSitePtr;  
}  
  
// Sets the safety options on the DOM object and   
// sets the Site object on the DOM object.   
HRESULT SetSecurityAndSite(IUnknownPtr pObj, IUnknownPtr pSite)  
{  
    HRESULT hr;  
  
    // Set the safety options on the DOM object.  
    IObjectSafetyPtr pObjectSafety(pObj);  
    if (pObjectSafety != NULL)  
    {  
        DWORD dwSafetyOpt = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;  
        hr = pObjectSafety->SetInterfaceSafetyOptions(IID_IUnknown, dwSafetyOpt, dwSafetyOpt);  
        if(FAILED(hr))  
        {  
            return hr;  
        }  
    }  
  
    // Set the site object on the DOM object.  
    if (pSite != NULL)  
    {  
        IObjectWithSitePtr pObjectWithSite(pObj);  
        if (pObjectWithSite != NULL)  
        {  
            hr = pObjectWithSite->SetSite(pSite);  
            if (FAILED(hr))  
            {  
                return hr;  
            }  
        }  
    }  
    return S_OK;  
}  
  
wstring GetErrorMessage(IUnknownPtr pUnk, REFIID refiid)  
{  
    HRESULT hr;  
    wstring result;  
    IErrorInfoPtr pErrorInfo = NULL;  
    hr = GetErrorInfo(0, &pErrorInfo);  
    if (hr != S_OK)  
    {  
        return result;  
    }  
  
    BSTR bstrMessage;  
    hr = pErrorInfo->GetDescription(&bstrMessage);  
  
    _bstr_t bsMessage(bstrMessage, true);  
  
    result = (LPCWSTR)bsMessage;  
  
    return result;  
}  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    IXMLDOMDocument *pXMLDom=NULL;  
    IXMLDOMParseError *pXMLErr=NULL;  
    BSTR bstr = NULL;  
    HRESULT hr;  
  
    CoInitialize(NULL);  
    // Create an action map.  
    ACTIONMAP actionMap[] =  
    {  
        ACTIONMAP(URLZONE_INTERNET, URLACTION_CROSS_DOMAIN_DATA, URLPOLICY_ALLOW),  
    };  
    int nActionMapCount = sizeof(actionMap) / sizeof(ACTIONMAP);  
    // Create a site object.  
    IUnknownPtr pSite = CreateSecureSite(NULL, 0, actionMap, nActionMapCount, L"www.microsoft.com");  
    // Create a DOM object.  
    IXMLDOMDocument2 *pDOMDocument = NULL;  
    hr = CoCreateInstance(DOMCLSID, NULL, CLSCTX_INPROC, IID_IXMLDOMDocument2, (LPVOID *)&pDOMDocument);  
    if (FAILED(hr))  
    {  
        wstring msg = GetErrorMessage(pDOMDocument, IID_IUnknown);  
        dprintf("%s (%s, %d)\n", (LPCSTR)msg.c_str(), __FILE__, __LINE__);  
        goto clean;  
    }  
  
    // Tell the DOM object to be secure and set the site object on the DOM object.  
    hr = SetSecurityAndSite(pDOMDocument, pSite);  
    if (FAILED(hr))  
    {  
        wstring msg = GetErrorMessage(pSite, IID_IUnknown);  
        dprintf("%s (%s, %d)\n", (LPCSTR)msg.c_str(), __FILE__, __LINE__);  
        goto clean;  
    }  
  
    VARIANT_BOOL bSuccess;  
    // The most common properties that are set on the DOM object.   
    pDOMDocument->put_async(VARIANT_FALSE);  
    pDOMDocument->put_resolveExternals( VARIANT_TRUE );  
    pDOMDocument->put_validateOnParse(VARIANT_FALSE );  
  
    dprintf("Calling load on sample.xml.\r\n");  
  
    // Load the file.  
    pDOMDocument->load(variant_t("sample.xml"), &bSuccess);  
  
    if (bSuccess!=VARIANT_TRUE)   
    {  
        hr = pDOMDocument->get_parseError(&pXMLErr);  
        if (FAILED(hr))  
        {  
            wstring msg = GetErrorMessage(pDOMDocument, IID_IUnknown);  
            dprintf("%s (%s, %d)\n", (LPCSTR)msg.c_str(), __FILE__, __LINE__);  
            goto clean;  
        }  
        hr = pXMLErr->get_reason(&bstr);  
        if (FAILED(hr))  
        {  
            wstring msg = GetErrorMessage(pXMLErr, IID_IUnknown);  
            dprintf("%s (%s, %d)\n", (LPCSTR)msg.c_str(), __FILE__, __LINE__);  
            goto clean;  
        }  
        dprintf("Failed to load DOM from sample.xml. %S\n",bstr);  
        goto clean;  
    }  
    hr = pDOMDocument->get_xml(&bstr);  
    if (FAILED(hr))  
    {  
        wstring msg = GetErrorMessage(pDOMDocument, IID_IUnknown);  
        dprintf("%s (%s, %d)\n", (LPCSTR)msg.c_str(), __FILE__, __LINE__);  
        goto clean;  
    }  
    dprintf("XML DOM loaded from sample.xml:\n%S\n",bstr);  
  
clean:  
    if (bstr) SysFreeString(bstr);  
  
    CoUninitialize();  
    return 0;  
}  
  

#include <string>  
using namespace std;  
  
typedef struct _ZONEMAP  
{  
    wstring _url;  
    DWORD _zoneIndex;  
    BOOL _fullCompare;  
  
    _ZONEMAP(wstring url, DWORD zoneIndex, BOOL fullCompare)  
        : _url(url), _zoneIndex(zoneIndex), _fullCompare(fullCompare)  
    {  
    }  
} ZONEMAP;  
  
typedef struct _ACTIONMAP  
{  
    DWORD _zoneIndex;  
    DWORD _action;  
    BYTE _policy;  
  
    _ACTIONMAP(DWORD zoneIndex, DWORD action, BYTE policy)  
        : _zoneIndex(zoneIndex), _action(action), _policy(policy)  
    {  
    }  
  
} ACTIONMAP;  
  
class CSiteImpl : public IServiceProvider, public IInternetSecurityManager, IOleClientSite  
{  
  
private:  
    ULONG _ulRefs;  
    wstring _secureBaseURL;  
  
    // IInternetSecurityManager  
    ZONEMAP* _pZoneMap;  
    int _nZoneMapCount;  
    ACTIONMAP* _pActionMap;  
    int _nActionMapCount;  
  
public:  
    CSiteImpl(LPCWSTR secureBaseURL);  
    virtual ~CSiteImpl();  
  
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);  
    ULONG STDMETHODCALLTYPE AddRef();  
    ULONG STDMETHODCALLTYPE Release();  
  
    // IServiceProvider  
    HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void** ppv);  
  
    // IDispatch  
    HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) { return E_NOTIMPL; }  
    HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo,LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }  
    HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid,DISPID *rgDispId) { return E_NOTIMPL; }  
    HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember,   
    REFIID riid, LCID lcid, WORD wFlags,   
    DISPPARAMS *pDispParams, VARIANT *pVarResult,   
    EXCEPINFO *pExcepInfo, UINT *puArgErr) { return E_NOTIMPL; }  
  
    // IOleClientSite  
    virtual HRESULT STDMETHODCALLTYPE SaveObject() { return E_NOTIMPL; }  
    virtual HRESULT STDMETHODCALLTYPE GetMoniker(DWORD dwAssign,DWORD dwWhichMoniker, IMoniker** ppmk);  
    virtual HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer**) { return E_NOTIMPL; }  
    virtual HRESULT STDMETHODCALLTYPE ShowObject() { return E_NOTIMPL; }  
    virtual HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL) { return E_NOTIMPL; }  
    virtual HRESULT STDMETHODCALLTYPE RequestNewObjectLayout(){ return E_NOTIMPL; }  
  
    // IInternetSecurityManager  
public:  
    void SetZoneMap(ZONEMAP* pZoneMap, int count) { _pZoneMap = pZoneMap; _nZoneMapCount = count; }  
    void SetActionMap(ACTIONMAP* pActionMap, int count) { _pActionMap = pActionMap; _nActionMapCount = count; }  
  
    HRESULT STDMETHODCALLTYPE SetSecuritySite(  
        IInternetSecurityMgrSite* pSite)  
    {  
        return INET_E_DEFAULT_ACTION;  
    }  
  
    HRESULT STDMETHODCALLTYPE GetSecuritySite(  
        IInternetSecurityMgrSite** ppSite)  
    {  
        return INET_E_DEFAULT_ACTION;  
    }  
  
    virtual HRESULT STDMETHODCALLTYPE MapUrlToZone(  
        LPCWSTR pwszUrl,  
        DWORD *pdwZone,  
        DWORD dwFlags);  
  
    virtual HRESULT STDMETHODCALLTYPE GetSecurityId(  
        LPCWSTR pwszUrl,  
        BYTE *pbSecurityId,  
        DWORD *pcbSecurityId,  
        DWORD_PTR dwReserved)  
    {  
        return INET_E_DEFAULT_ACTION;  
    }  
  
    virtual HRESULT STDMETHODCALLTYPE ProcessUrlAction(  
        LPCWSTR pwszUrl,  
        DWORD dwAction,  
        BYTE* pPolicy,  
        DWORD cbPolicy,  
        BYTE* pContext,  
        DWORD cbContext,  
        DWORD dwFlags,  
        DWORD dwReserved);  
  
    virtual HRESULT STDMETHODCALLTYPE QueryCustomPolicy(  
        LPCWSTR pwszUrl,  
        REFGUID guidKey,  
        BYTE** ppPolicy,  
        DWORD* pcbPolicy,  
        BYTE* pContext,  
        DWORD cbContext,  
        DWORD dwReserved)  
    {  
        return INET_E_DEFAULT_ACTION;  
    }  
  
    virtual HRESULT STDMETHODCALLTYPE SetZoneMapping(  
        DWORD dwZone,  
        LPCWSTR lpszPattern,  
        DWORD dwFlags)  
    {  
        return INET_E_DEFAULT_ACTION;  
    }  
  
    virtual HRESULT STDMETHODCALLTYPE GetZoneMappings(  
        DWORD dwZone,  
        IEnumString** ppenumString,  
        DWORD dwFlags)  
    {  
        return INET_E_DEFAULT_ACTION;  
    }  
};  
  

#include "stdafx.h"  
#include <comdef.h>  
#include "SiteImpl.h"  
  
#pragma comment( lib, "urlmon.lib")  
  
//////////////////////////////////////////////////////////////////////  
// Construction/Destruction  
//////////////////////////////////////////////////////////////////////  
  
CSiteImpl::CSiteImpl(LPCWSTR secureBaseURL)  
{  
    _ulRefs = 0;  
    _secureBaseURL = secureBaseURL;  
  
    _pZoneMap = NULL;  
    _pActionMap = NULL;  
    _nZoneMapCount = 0;  
    _nActionMapCount = 0;  
}  
  
CSiteImpl::~CSiteImpl()  
{  
}  
  
HRESULT CSiteImpl::QueryInterface(REFIID riid, void** ppv)  
{  
    HRESULT hr = S_OK;  
  
    if (riid == IID_IUnknown || riid == IID_IServiceProvider)  
    {  
        *ppv = static_cast<IServiceProvider*>(this);  
    }  
    else if (riid == IID_IOleClientSite)  
    {  
        *ppv = static_cast<IOleClientSite*>(this);  
    }  
    else if (riid == IID_IInternetSecurityManager)  
    {  
        *ppv = static_cast<IInternetSecurityManager*>(this);  
    }  
    else  
    {  
        *ppv = NULL;  
        return E_NOINTERFACE;  
    }  
  
    AddRef();  
    return S_OK;  
}  
  
ULONG CSiteImpl::AddRef()  
{  
    return ++_ulRefs;  
}  
  
ULONG CSiteImpl::Release()  
{  
    ULONG ul = --_ulRefs;  
    if (0 == ul)  
        delete this;  
    return ul;  
}  
  
HRESULT CSiteImpl::QueryService(REFGUID guidService, REFIID riid, void ** ppv)  
{  
    return  QueryInterface(riid, ppv);  
}  
  
// Either URLMON or MSXML can trigger this method.   
// The implementation should be caller agnostic.   
// This method is used to determine the zone of the URL.   
// Further, MSXML will use this method to determine the zone of a referenced document.   
// It can then determine whether the referring document   
// is attempting to load a document that is in a different zone.  
HRESULT CSiteImpl::MapUrlToZone(LPCWSTR pwszUrl, DWORD *pdwZone, DWORD dwFlags)  
{  
    // Check if URL is in our map.  
    for (int i=0; i<_nZoneMapCount; i++)  
    {  
        ZONEMAP * p = &_pZoneMap[i];  
        wstring tempurl = pwszUrl;  
        if ((p->_fullCompare && p->_url == pwszUrl) ||  
             (!p->_fullCompare && tempurl.find(p->_url) == 0))  
        {  
            *pdwZone = p->_zoneIndex;  
            return S_OK;  
        }  
    }  
    return INET_E_DEFAULT_ACTION;  
}  
  
// Determines the policy for a specified security action.   
// URLMON triggers a call to this method whenever it encounters a security action   
// and needs to enlist a security manager to make a security-related decision   
// for that action.   
HRESULT CSiteImpl::ProcessUrlAction(  
                        LPCWSTR pwszUrl,  
                        DWORD dwAction,  
                        BYTE *pPolicy,  
                        DWORD cbPolicy,  
                        BYTE *pContext,  
                        DWORD cbContext,  
                        DWORD dwFlags,  
                        DWORD dwReserved)  
{  
    DWORD dwZone;  
    HRESULT hr = MapUrlToZone(pwszUrl, &dwZone, 0);  
    // The goal is that MapUrlToZone returns a Zone that   
    // either the custom security manager recognizes, or  
    // the default Internet Security Manager recognizes.   
    // (One of which should always be the case.)   
    // Thus we ALWAYS enter the ACTIONMAP for the custom security manager   
    // whenever a ProcessUrlAction is called.  
    if (hr == INET_E_DEFAULT_ACTION)  
    {  
        // The custom MapUrlToZone gets the zone  
        // from the default security manager.  
        IInternetSecurityManagerPtr pDefSecMgr = NULL;  
        hr = ::CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC, IID_IInternetSecurityManager, (LPVOID*)&pDefSecMgr);  
        if (hr == S_OK)  
            hr = pDefSecMgr->MapUrlToZone(pwszUrl, &dwZone, 0);  
    }  
    if (hr == S_OK)  
    {  
        for (int i=0; i<_nActionMapCount; i++)  
        {  
            ACTIONMAP* p = &_pActionMap[i];  
            if (p->_zoneIndex == dwZone && p->_action == dwAction)  
            {  
                *((DWORD*)pPolicy) = p->_policy;  
                if (p->_policy == URLPOLICY_ALLOW)  
                {  
                    return S_OK;  
                }  
                else  
                {  
                    return S_FALSE;  
                }  
            }  
        }  
    }  
    return INET_E_DEFAULT_ACTION;  
}  
// Returns the Secure Base URL to MSXML.  
HRESULT CSiteImpl::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk)  
{  
    return CreateURLMoniker(NULL, _secureBaseURL.c_str(), ppmk);  
}  
  

<sample>  
</sample>  
  

Building a Custom Internet Security Manager
Custom Internet Security Manager Examples

Show: