~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/js/src/xpconnect/src/nsDispatchSupport.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 * ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Mozilla Public License Version
 
6
 * 1.1 (the "License"); you may not use this file except in compliance with
 
7
 * the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/MPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is the IDispatch implementation for XPConnect.
 
16
 *
 
17
 * The Initial Developer of the Original Code is
 
18
 * David Bradley.
 
19
 * Portions created by the Initial Developer are Copyright (C) 2002
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 * Alternatively, the contents of this file may be used under the terms of
 
25
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
26
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
27
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
28
 * of those above. If you wish to allow use of your version of this file only
 
29
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
30
 * use your version of this file under the terms of the MPL, indicate your
 
31
 * decision by deleting the provisions above and replace them with the notice
 
32
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
33
 * the provisions above, a recipient may use your version of this file under
 
34
 * the terms of any one of the MPL, the GPL or the LGPL.
 
35
 *
 
36
 * ***** END LICENSE BLOCK ***** */
 
37
 
 
38
/**
 
39
 * \file nsDispatchSupport.cpp
 
40
 * Contains the implementation for the nsDispatchSupport class
 
41
 * this is an XPCOM service
 
42
 */
 
43
 
 
44
#include "XPCPrivate.h"
 
45
 
 
46
#include "nsIActiveXSecurityPolicy.h"
 
47
 
 
48
static PRBool
 
49
ClassIsListed(HKEY hkeyRoot, const TCHAR *szKey, const CLSID &clsid, PRBool &listIsEmpty)
 
50
{
 
51
    // Test if the specified CLSID is found in the specified registry key
 
52
 
 
53
    listIsEmpty = PR_TRUE;
 
54
 
 
55
    CRegKey keyList;
 
56
    if(keyList.Open(hkeyRoot, szKey, KEY_READ) != ERROR_SUCCESS)
 
57
    {
 
58
        // Class is not listed, because there is no key to read!
 
59
        return PR_FALSE;
 
60
    }
 
61
 
 
62
    // Enumerate CLSIDs looking for this one
 
63
    int i = 0;
 
64
    do {
 
65
        USES_CONVERSION;
 
66
        TCHAR szCLSID[64];
 
67
        const DWORD kBufLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
 
68
        memset(szCLSID, 0, sizeof(szCLSID));
 
69
        if(::RegEnumKey(keyList, i, szCLSID, kBufLength) != ERROR_SUCCESS)
 
70
        {
 
71
            // End of list
 
72
            break;
 
73
        }
 
74
        ++i;
 
75
        listIsEmpty = PR_FALSE;
 
76
        szCLSID[kBufLength - 1] = TCHAR('\0');
 
77
        CLSID clsidToCompare = GUID_NULL;
 
78
        if(SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
 
79
            ::IsEqualCLSID(clsid, clsidToCompare))
 
80
        {
 
81
            // Class is listed
 
82
            return PR_TRUE;
 
83
        }
 
84
    } while(1);
 
85
 
 
86
    // Class not found
 
87
    return PR_FALSE;
 
88
}
 
89
 
 
90
static PRBool
 
91
ClassExists(const CLSID &clsid)
 
92
{
 
93
    // Test if there is a CLSID entry. If there isn't then obviously
 
94
    // the object doesn't exist.
 
95
    CRegKey key;
 
96
    if(key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) != ERROR_SUCCESS)
 
97
        return PR_FALSE; // Must fail if we can't even open this!
 
98
    
 
99
    LPOLESTR szCLSID = NULL;
 
100
    if(FAILED(StringFromCLSID(clsid, &szCLSID)))
 
101
        return PR_FALSE; // Can't allocate string from CLSID
 
102
 
 
103
    USES_CONVERSION;
 
104
    CRegKey keyCLSID;
 
105
    LONG lResult = keyCLSID.Open(key, W2CT(szCLSID), KEY_READ);
 
106
    CoTaskMemFree(szCLSID);
 
107
    if(lResult != ERROR_SUCCESS)
 
108
        return PR_FALSE; // Class doesn't exist
 
109
 
 
110
    return PR_TRUE;
 
111
}
 
112
 
 
113
static PRBool
 
114
ClassImplementsCategory(const CLSID &clsid, const CATID &catid, PRBool &bClassExists)
 
115
{
 
116
    bClassExists = ClassExists(clsid);
 
117
    // Non existent classes won't implement any category...
 
118
    if(!bClassExists)
 
119
        return PR_FALSE;
 
120
 
 
121
    // CLSID exists, so try checking what categories it implements
 
122
    bClassExists = PR_TRUE;
 
123
    CComPtr<ICatInformation> catInfo;
 
124
    HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
 
125
        CLSCTX_INPROC_SERVER, __uuidof(ICatInformation), (LPVOID*) &catInfo);
 
126
    if(catInfo == NULL)
 
127
        return PR_FALSE; // Must fail if we can't open the category manager
 
128
    
 
129
    // See what categories the class implements
 
130
    CComPtr<IEnumCATID> enumCATID;
 
131
    if(FAILED(catInfo->EnumImplCategoriesOfClass(clsid, &enumCATID)))
 
132
        return PR_FALSE; // Can't enumerate classes in category so fail
 
133
 
 
134
    // Search for matching categories
 
135
    BOOL bFound = FALSE;
 
136
    CATID catidNext = GUID_NULL;
 
137
    while(enumCATID->Next(1, &catidNext, NULL) == S_OK)
 
138
    {
 
139
        if(::IsEqualCATID(catid, catidNext))
 
140
            return PR_TRUE; // Match
 
141
    }
 
142
    return PR_FALSE;
 
143
}
 
144
 
 
145
nsDispatchSupport* nsDispatchSupport::mInstance = nsnull;
 
146
 
 
147
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDispatchSupport, nsIDispatchSupport)
 
148
 
 
149
nsDispatchSupport::nsDispatchSupport()
 
150
{
 
151
    /* member initializers and constructor code */
 
152
}
 
153
 
 
154
nsDispatchSupport::~nsDispatchSupport()
 
155
{
 
156
    /* destructor code */
 
157
}
 
158
 
 
159
/**
 
160
 * Converts a COM variant to a jsval
 
161
 * @param comvar the variant to convert
 
162
 * @param val pointer to the jsval to receive the value
 
163
 * @return nsresult
 
164
 */
 
165
NS_IMETHODIMP nsDispatchSupport::COMVariant2JSVal(VARIANT * comvar, jsval *val)
 
166
{
 
167
    XPCCallContext ccx(NATIVE_CALLER);
 
168
    nsresult retval;
 
169
    XPCDispConvert::COMToJS(ccx, *comvar, *val, retval);
 
170
    return retval;
 
171
}
 
172
 
 
173
/**
 
174
 * Converts a jsval to a COM variant
 
175
 * @param val the jsval to be converted
 
176
 * @param comvar pointer to the variant to receive the value
 
177
 * @return nsresult
 
178
 */
 
179
NS_IMETHODIMP nsDispatchSupport::JSVal2COMVariant(jsval val, VARIANT * comvar)
 
180
{
 
181
    XPCCallContext ccx(NATIVE_CALLER);
 
182
    nsresult retval;
 
183
    XPCDispConvert::JSToCOM(ccx, val, *comvar, retval);
 
184
    return retval;
 
185
}
 
186
 
 
187
/* boolean isClassSafeToHost (in nsCIDRef clsid, out boolean classExists); */
 
188
NS_IMETHODIMP nsDispatchSupport::IsClassSafeToHost(JSContext * cx,
 
189
                                                   const nsCID & cid,
 
190
                                                   PRBool ignoreException, 
 
191
                                                   PRBool *classExists, 
 
192
                                                   PRBool *aResult)
 
193
{
 
194
    NS_ENSURE_ARG_POINTER(aResult);
 
195
    NS_ENSURE_ARG_POINTER(classExists);
 
196
 
 
197
    *aResult = PR_FALSE;
 
198
 
 
199
    CLSID clsid = XPCDispnsCID2CLSID(cid);
 
200
 
 
201
    // Ask security manager if it's ok to create this object
 
202
    XPCCallContext ccx(JS_CALLER, cx);
 
203
    nsIXPCSecurityManager* sm =
 
204
            ccx.GetXPCContext()->GetAppropriateSecurityManager(
 
205
                        nsIXPCSecurityManager::HOOK_CREATE_INSTANCE);
 
206
    *aResult = !sm ||
 
207
        NS_SUCCEEDED(sm->CanCreateInstance(ccx, cid));
 
208
 
 
209
    if(!*aResult)
 
210
    {
 
211
        if (ignoreException)
 
212
            JS_ClearPendingException(ccx);
 
213
        *classExists = PR_TRUE;
 
214
        return NS_OK;
 
215
    }
 
216
    *classExists = ClassExists(clsid);
 
217
 
 
218
    // Test the Internet Explorer black list
 
219
    const TCHAR kIEControlsBlacklist[] = _T("SOFTWARE\\Microsoft\\Internet Explorer\\ActiveX Compatibility");
 
220
    CRegKey keyExplorer;
 
221
    if(keyExplorer.Open(HKEY_LOCAL_MACHINE,
 
222
        kIEControlsBlacklist, KEY_READ) == ERROR_SUCCESS)
 
223
    {
 
224
        LPOLESTR szCLSID = NULL;
 
225
        ::StringFromCLSID(clsid, &szCLSID);
 
226
        if(szCLSID)
 
227
        {
 
228
            CRegKey keyCLSID;
 
229
            USES_CONVERSION;
 
230
            if(keyCLSID.Open(keyExplorer, W2T(szCLSID), KEY_READ) == ERROR_SUCCESS)
 
231
            {
 
232
                DWORD dwType = REG_DWORD;
 
233
                DWORD dwFlags = 0;
 
234
                DWORD dwBufSize = sizeof(dwFlags);
 
235
                if(::RegQueryValueEx(keyCLSID, _T("Compatibility Flags"),
 
236
                    NULL, &dwType, (LPBYTE) &dwFlags, &dwBufSize) == ERROR_SUCCESS)
 
237
                {
 
238
                    // Documented flags for this reg key
 
239
                    const DWORD kKillBit = 0x00000400; // MS Knowledge Base 240797
 
240
                    if(dwFlags & kKillBit)
 
241
                    {
 
242
                        ::CoTaskMemFree(szCLSID);
 
243
                        *aResult = PR_FALSE;
 
244
                        return NS_OK;
 
245
                    }
 
246
                }
 
247
            }
 
248
            ::CoTaskMemFree(szCLSID);
 
249
        }
 
250
    }
 
251
 
 
252
    *aResult = PR_TRUE;
 
253
    return NS_OK;
 
254
}
 
255
 
 
256
/* boolean isClassMarkedSafeForScripting (in nsCIDRef clsid, out boolean classExists); */
 
257
NS_IMETHODIMP nsDispatchSupport::IsClassMarkedSafeForScripting(const nsCID & cid, PRBool *classExists, PRBool *aResult)
 
258
{
 
259
    NS_ENSURE_ARG_POINTER(aResult);
 
260
    NS_ENSURE_ARG_POINTER(classExists);
 
261
    // Test the category the object belongs to
 
262
    CLSID clsid = XPCDispnsCID2CLSID(cid);
 
263
    *aResult = ClassImplementsCategory(clsid, CATID_SafeForScripting, *classExists);
 
264
    return NS_OK;
 
265
}
 
266
 
 
267
/* boolean isObjectSafeForScripting (in voidPtr theObject, in nsIIDRef iid); */
 
268
NS_IMETHODIMP nsDispatchSupport::IsObjectSafeForScripting(void * theObject, const nsIID & id, PRBool *aResult)
 
269
{
 
270
    NS_ENSURE_ARG_POINTER(theObject);
 
271
    NS_ENSURE_ARG_POINTER(aResult);
 
272
 
 
273
    // Test if the object implements IObjectSafety and is marked safe for scripting
 
274
    IUnknown *pObject = (IUnknown *) theObject;
 
275
    IID iid = XPCDispIID2IID(id);
 
276
 
 
277
    // Ask the control if its safe for scripting
 
278
    CComQIPtr<IObjectSafety> objectSafety = pObject;
 
279
    if(!objectSafety)
 
280
    {
 
281
        *aResult = PR_TRUE;
 
282
        return NS_OK;
 
283
    }
 
284
 
 
285
    DWORD dwSupported = 0; // Supported options (mask)
 
286
    DWORD dwEnabled = 0;   // Enabled options
 
287
 
 
288
    // Assume scripting via IDispatch
 
289
    if(FAILED(objectSafety->GetInterfaceSafetyOptions(
 
290
            iid, &dwSupported, &dwEnabled)))
 
291
    {
 
292
        // Interface is not safe or failure.
 
293
        *aResult = PR_FALSE;
 
294
        return NS_OK;
 
295
    }
 
296
 
 
297
    // Test if safe for scripting
 
298
    if(!(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
 
299
    {
 
300
        // Object says it is not set to be safe, but supports unsafe calling,
 
301
        // try enabling it and asking again.
 
302
 
 
303
        if(!(dwSupported & INTERFACESAFE_FOR_UNTRUSTED_CALLER) ||
 
304
            FAILED(objectSafety->SetInterfaceSafetyOptions(
 
305
                iid, INTERFACESAFE_FOR_UNTRUSTED_CALLER, INTERFACESAFE_FOR_UNTRUSTED_CALLER)) ||
 
306
            FAILED(objectSafety->GetInterfaceSafetyOptions(
 
307
                iid, &dwSupported, &dwEnabled)) ||
 
308
            !(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
 
309
        {
 
310
            *aResult = PR_FALSE;
 
311
            return NS_OK;
 
312
        }
 
313
    }
 
314
 
 
315
    *aResult = PR_TRUE;
 
316
    return NS_OK;
 
317
}
 
318
 
 
319
static const PRUint32 kDefaultHostingFlags =
 
320
    nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
 
321
 
 
322
/* unsigned long getHostingFlags (in string aContext); */
 
323
NS_IMETHODIMP nsDispatchSupport::GetHostingFlags(const char *aContext, PRUint32 *aResult)
 
324
{
 
325
    NS_ENSURE_ARG_POINTER(aResult);
 
326
 
 
327
    // Ask the activex security policy what the hosting flags are
 
328
    nsresult rv;
 
329
    nsCOMPtr<nsIActiveXSecurityPolicy> securityPolicy =
 
330
        do_GetService(NS_IACTIVEXSECURITYPOLICY_CONTRACTID, &rv);
 
331
    if(NS_SUCCEEDED(rv) && securityPolicy)
 
332
        return securityPolicy->GetHostingFlags(aContext, aResult);
 
333
    
 
334
    // No policy so use the defaults
 
335
    *aResult = kDefaultHostingFlags;
 
336
    return NS_OK;
 
337
}
 
338
 
 
339
nsDispatchSupport* nsDispatchSupport::GetSingleton()
 
340
{
 
341
    if(!mInstance)
 
342
    {
 
343
        mInstance = new nsDispatchSupport;
 
344
        NS_IF_ADDREF(mInstance);
 
345
    }
 
346
    NS_IF_ADDREF(mInstance);
 
347
    return mInstance;
 
348
}