Back to index

lightning-sunbird  0.9+nobinonly
nsDispatchSupport.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the IDispatch implementation for XPConnect.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * David Bradley.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00044 #include "XPCPrivate.h"
00045 
00046 #include "nsIActiveXSecurityPolicy.h"
00047 
00048 static PRBool
00049 ClassIsListed(HKEY hkeyRoot, const TCHAR *szKey, const CLSID &clsid, PRBool &listIsEmpty)
00050 {
00051     // Test if the specified CLSID is found in the specified registry key
00052 
00053     listIsEmpty = PR_TRUE;
00054 
00055     CRegKey keyList;
00056     if(keyList.Open(hkeyRoot, szKey, KEY_READ) != ERROR_SUCCESS)
00057     {
00058         // Class is not listed, because there is no key to read!
00059         return PR_FALSE;
00060     }
00061 
00062     // Enumerate CLSIDs looking for this one
00063     int i = 0;
00064     do {
00065         USES_CONVERSION;
00066         TCHAR szCLSID[64];
00067         const DWORD kBufLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
00068         memset(szCLSID, 0, sizeof(szCLSID));
00069         if(::RegEnumKey(keyList, i, szCLSID, kBufLength) != ERROR_SUCCESS)
00070         {
00071             // End of list
00072             break;
00073         }
00074         ++i;
00075         listIsEmpty = PR_FALSE;
00076         szCLSID[kBufLength - 1] = TCHAR('\0');
00077         CLSID clsidToCompare = GUID_NULL;
00078         if(SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
00079             ::IsEqualCLSID(clsid, clsidToCompare))
00080         {
00081             // Class is listed
00082             return PR_TRUE;
00083         }
00084     } while(1);
00085 
00086     // Class not found
00087     return PR_FALSE;
00088 }
00089 
00090 static PRBool
00091 ClassExists(const CLSID &clsid)
00092 {
00093     // Test if there is a CLSID entry. If there isn't then obviously
00094     // the object doesn't exist.
00095     CRegKey key;
00096     if(key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) != ERROR_SUCCESS)
00097         return PR_FALSE; // Must fail if we can't even open this!
00098     
00099     LPOLESTR szCLSID = NULL;
00100     if(FAILED(StringFromCLSID(clsid, &szCLSID)))
00101         return PR_FALSE; // Can't allocate string from CLSID
00102 
00103     USES_CONVERSION;
00104     CRegKey keyCLSID;
00105     LONG lResult = keyCLSID.Open(key, W2CT(szCLSID), KEY_READ);
00106     CoTaskMemFree(szCLSID);
00107     if(lResult != ERROR_SUCCESS)
00108         return PR_FALSE; // Class doesn't exist
00109 
00110     return PR_TRUE;
00111 }
00112 
00113 static PRBool
00114 ClassImplementsCategory(const CLSID &clsid, const CATID &catid, PRBool &bClassExists)
00115 {
00116     bClassExists = ClassExists(clsid);
00117     // Non existent classes won't implement any category...
00118     if(!bClassExists)
00119         return PR_FALSE;
00120 
00121     // CLSID exists, so try checking what categories it implements
00122     bClassExists = PR_TRUE;
00123     CComPtr<ICatInformation> catInfo;
00124     HRESULT hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
00125         CLSCTX_INPROC_SERVER, __uuidof(ICatInformation), (LPVOID*) &catInfo);
00126     if(catInfo == NULL)
00127         return PR_FALSE; // Must fail if we can't open the category manager
00128     
00129     // See what categories the class implements
00130     CComPtr<IEnumCATID> enumCATID;
00131     if(FAILED(catInfo->EnumImplCategoriesOfClass(clsid, &enumCATID)))
00132         return PR_FALSE; // Can't enumerate classes in category so fail
00133 
00134     // Search for matching categories
00135     BOOL bFound = FALSE;
00136     CATID catidNext = GUID_NULL;
00137     while(enumCATID->Next(1, &catidNext, NULL) == S_OK)
00138     {
00139         if(::IsEqualCATID(catid, catidNext))
00140             return PR_TRUE; // Match
00141     }
00142     return PR_FALSE;
00143 }
00144 
00145 nsDispatchSupport* nsDispatchSupport::mInstance = nsnull;
00146 
00147 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDispatchSupport, nsIDispatchSupport)
00148 
00149 nsDispatchSupport::nsDispatchSupport()
00150 {
00151     /* member initializers and constructor code */
00152 }
00153 
00154 nsDispatchSupport::~nsDispatchSupport()
00155 {
00156     /* destructor code */
00157 }
00158 
00165 NS_IMETHODIMP nsDispatchSupport::COMVariant2JSVal(VARIANT * comvar, jsval *val)
00166 {
00167     XPCCallContext ccx(NATIVE_CALLER);
00168     nsresult retval;
00169     XPCDispConvert::COMToJS(ccx, *comvar, *val, retval);
00170     return retval;
00171 }
00172 
00179 NS_IMETHODIMP nsDispatchSupport::JSVal2COMVariant(jsval val, VARIANT * comvar)
00180 {
00181     XPCCallContext ccx(NATIVE_CALLER);
00182     nsresult retval;
00183     XPCDispConvert::JSToCOM(ccx, val, *comvar, retval);
00184     return retval;
00185 }
00186 
00187 /* boolean isClassSafeToHost (in nsCIDRef clsid, out boolean classExists); */
00188 NS_IMETHODIMP nsDispatchSupport::IsClassSafeToHost(JSContext * cx,
00189                                                    const nsCID & cid,
00190                                                    PRBool ignoreException, 
00191                                                    PRBool *classExists, 
00192                                                    PRBool *aResult)
00193 {
00194     NS_ENSURE_ARG_POINTER(aResult);
00195     NS_ENSURE_ARG_POINTER(classExists);
00196 
00197     *aResult = PR_FALSE;
00198 
00199     CLSID clsid = XPCDispnsCID2CLSID(cid);
00200 
00201     // Ask security manager if it's ok to create this object
00202     XPCCallContext ccx(JS_CALLER, cx);
00203     nsIXPCSecurityManager* sm =
00204             ccx.GetXPCContext()->GetAppropriateSecurityManager(
00205                         nsIXPCSecurityManager::HOOK_CREATE_INSTANCE);
00206     *aResult = !sm ||
00207         NS_SUCCEEDED(sm->CanCreateInstance(ccx, cid));
00208 
00209     if(!*aResult)
00210     {
00211         if (ignoreException)
00212             JS_ClearPendingException(ccx);
00213         *classExists = PR_TRUE;
00214         return NS_OK;
00215     }
00216     *classExists = ClassExists(clsid);
00217 
00218     // Test the Internet Explorer black list
00219     const TCHAR kIEControlsBlacklist[] = _T("SOFTWARE\\Microsoft\\Internet Explorer\\ActiveX Compatibility");
00220     CRegKey keyExplorer;
00221     if(keyExplorer.Open(HKEY_LOCAL_MACHINE,
00222         kIEControlsBlacklist, KEY_READ) == ERROR_SUCCESS)
00223     {
00224         LPOLESTR szCLSID = NULL;
00225         ::StringFromCLSID(clsid, &szCLSID);
00226         if(szCLSID)
00227         {
00228             CRegKey keyCLSID;
00229             USES_CONVERSION;
00230             if(keyCLSID.Open(keyExplorer, W2T(szCLSID), KEY_READ) == ERROR_SUCCESS)
00231             {
00232                 DWORD dwType = REG_DWORD;
00233                 DWORD dwFlags = 0;
00234                 DWORD dwBufSize = sizeof(dwFlags);
00235                 if(::RegQueryValueEx(keyCLSID, _T("Compatibility Flags"),
00236                     NULL, &dwType, (LPBYTE) &dwFlags, &dwBufSize) == ERROR_SUCCESS)
00237                 {
00238                     // Documented flags for this reg key
00239                     const DWORD kKillBit = 0x00000400; // MS Knowledge Base 240797
00240                     if(dwFlags & kKillBit)
00241                     {
00242                         ::CoTaskMemFree(szCLSID);
00243                         *aResult = PR_FALSE;
00244                         return NS_OK;
00245                     }
00246                 }
00247             }
00248             ::CoTaskMemFree(szCLSID);
00249         }
00250     }
00251 
00252     *aResult = PR_TRUE;
00253     return NS_OK;
00254 }
00255 
00256 /* boolean isClassMarkedSafeForScripting (in nsCIDRef clsid, out boolean classExists); */
00257 NS_IMETHODIMP nsDispatchSupport::IsClassMarkedSafeForScripting(const nsCID & cid, PRBool *classExists, PRBool *aResult)
00258 {
00259     NS_ENSURE_ARG_POINTER(aResult);
00260     NS_ENSURE_ARG_POINTER(classExists);
00261     // Test the category the object belongs to
00262     CLSID clsid = XPCDispnsCID2CLSID(cid);
00263     *aResult = ClassImplementsCategory(clsid, CATID_SafeForScripting, *classExists);
00264     return NS_OK;
00265 }
00266 
00267 /* boolean isObjectSafeForScripting (in voidPtr theObject, in nsIIDRef iid); */
00268 NS_IMETHODIMP nsDispatchSupport::IsObjectSafeForScripting(void * theObject, const nsIID & id, PRBool *aResult)
00269 {
00270     NS_ENSURE_ARG_POINTER(theObject);
00271     NS_ENSURE_ARG_POINTER(aResult);
00272 
00273     // Test if the object implements IObjectSafety and is marked safe for scripting
00274     IUnknown *pObject = (IUnknown *) theObject;
00275     IID iid = XPCDispIID2IID(id);
00276 
00277     // Ask the control if its safe for scripting
00278     CComQIPtr<IObjectSafety> objectSafety = pObject;
00279     if(!objectSafety)
00280     {
00281         *aResult = PR_TRUE;
00282         return NS_OK;
00283     }
00284 
00285     DWORD dwSupported = 0; // Supported options (mask)
00286     DWORD dwEnabled = 0;   // Enabled options
00287 
00288     // Assume scripting via IDispatch
00289     if(FAILED(objectSafety->GetInterfaceSafetyOptions(
00290             iid, &dwSupported, &dwEnabled)))
00291     {
00292         // Interface is not safe or failure.
00293         *aResult = PR_FALSE;
00294         return NS_OK;
00295     }
00296 
00297     // Test if safe for scripting
00298     if(!(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
00299     {
00300         // Object says it is not set to be safe, but supports unsafe calling,
00301         // try enabling it and asking again.
00302 
00303         if(!(dwSupported & INTERFACESAFE_FOR_UNTRUSTED_CALLER) ||
00304             FAILED(objectSafety->SetInterfaceSafetyOptions(
00305                 iid, INTERFACESAFE_FOR_UNTRUSTED_CALLER, INTERFACESAFE_FOR_UNTRUSTED_CALLER)) ||
00306             FAILED(objectSafety->GetInterfaceSafetyOptions(
00307                 iid, &dwSupported, &dwEnabled)) ||
00308             !(dwEnabled & dwSupported) & INTERFACESAFE_FOR_UNTRUSTED_CALLER)
00309         {
00310             *aResult = PR_FALSE;
00311             return NS_OK;
00312         }
00313     }
00314 
00315     *aResult = PR_TRUE;
00316     return NS_OK;
00317 }
00318 
00319 static const PRUint32 kDefaultHostingFlags =
00320     nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_NOTHING;
00321 
00322 /* unsigned long getHostingFlags (in string aContext); */
00323 NS_IMETHODIMP nsDispatchSupport::GetHostingFlags(const char *aContext, PRUint32 *aResult)
00324 {
00325     NS_ENSURE_ARG_POINTER(aResult);
00326 
00327     // Ask the activex security policy what the hosting flags are
00328     nsresult rv;
00329     nsCOMPtr<nsIActiveXSecurityPolicy> securityPolicy =
00330         do_GetService(NS_IACTIVEXSECURITYPOLICY_CONTRACTID, &rv);
00331     if(NS_SUCCEEDED(rv) && securityPolicy)
00332         return securityPolicy->GetHostingFlags(aContext, aResult);
00333     
00334     // No policy so use the defaults
00335     *aResult = kDefaultHostingFlags;
00336     return NS_OK;
00337 }
00338 
00339 nsDispatchSupport* nsDispatchSupport::GetSingleton()
00340 {
00341     if(!mInstance)
00342     {
00343         mInstance = new nsDispatchSupport;
00344         NS_IF_ADDREF(mInstance);
00345     }
00346     NS_IF_ADDREF(mInstance);
00347     return mInstance;
00348 }