1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,340 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "base/basictypes.h" 1.10 + 1.11 +#include "nsAboutProtocolHandler.h" 1.12 +#include "nsIURI.h" 1.13 +#include "nsIAboutModule.h" 1.14 +#include "nsString.h" 1.15 +#include "nsNetCID.h" 1.16 +#include "nsAboutProtocolUtils.h" 1.17 +#include "nsError.h" 1.18 +#include "nsNetUtil.h" 1.19 +#include "nsIObjectInputStream.h" 1.20 +#include "nsIObjectOutputStream.h" 1.21 +#include "nsAutoPtr.h" 1.22 +#include "nsIWritablePropertyBag2.h" 1.23 + 1.24 +static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID); 1.25 +static NS_DEFINE_CID(kNestedAboutURICID, NS_NESTEDABOUTURI_CID); 1.26 + 1.27 +static bool IsSafeForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) { 1.28 + uint32_t flags; 1.29 + nsresult rv = aModule->GetURIFlags(aURI, &flags); 1.30 + NS_ENSURE_SUCCESS(rv, false); 1.31 + 1.32 + return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0; 1.33 +} 1.34 +//////////////////////////////////////////////////////////////////////////////// 1.35 + 1.36 +NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler) 1.37 + 1.38 +//////////////////////////////////////////////////////////////////////////////// 1.39 +// nsIProtocolHandler methods: 1.40 + 1.41 +NS_IMETHODIMP 1.42 +nsAboutProtocolHandler::GetScheme(nsACString &result) 1.43 +{ 1.44 + result.AssignLiteral("about"); 1.45 + return NS_OK; 1.46 +} 1.47 + 1.48 +NS_IMETHODIMP 1.49 +nsAboutProtocolHandler::GetDefaultPort(int32_t *result) 1.50 +{ 1.51 + *result = -1; // no port for about: URLs 1.52 + return NS_OK; 1.53 +} 1.54 + 1.55 +NS_IMETHODIMP 1.56 +nsAboutProtocolHandler::GetProtocolFlags(uint32_t *result) 1.57 +{ 1.58 + *result = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD; 1.59 + return NS_OK; 1.60 +} 1.61 + 1.62 +NS_IMETHODIMP 1.63 +nsAboutProtocolHandler::NewURI(const nsACString &aSpec, 1.64 + const char *aCharset, // ignore charset info 1.65 + nsIURI *aBaseURI, 1.66 + nsIURI **result) 1.67 +{ 1.68 + *result = nullptr; 1.69 + nsresult rv; 1.70 + 1.71 + // Use a simple URI to parse out some stuff first 1.72 + nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv); 1.73 + if (NS_FAILED(rv)) return rv; 1.74 + 1.75 + rv = url->SetSpec(aSpec); 1.76 + if (NS_FAILED(rv)) { 1.77 + return rv; 1.78 + } 1.79 + 1.80 + // Unfortunately, people create random about: URIs that don't correspond to 1.81 + // about: modules... Since those URIs will never open a channel, might as 1.82 + // well consider them unsafe for better perf, and just in case. 1.83 + bool isSafe = false; 1.84 + 1.85 + nsCOMPtr<nsIAboutModule> aboutMod; 1.86 + rv = NS_GetAboutModule(url, getter_AddRefs(aboutMod)); 1.87 + if (NS_SUCCEEDED(rv)) { 1.88 + isSafe = IsSafeForUntrustedContent(aboutMod, url); 1.89 + } 1.90 + 1.91 + if (isSafe) { 1.92 + // We need to indicate that this baby is safe. Use an inner URI that 1.93 + // no one but the security manager will see. Make sure to preserve our 1.94 + // path, in case someone decides to hardcode checks for particular 1.95 + // about: URIs somewhere. 1.96 + nsAutoCString spec; 1.97 + rv = url->GetPath(spec); 1.98 + NS_ENSURE_SUCCESS(rv, rv); 1.99 + 1.100 + spec.Insert("moz-safe-about:", 0); 1.101 + 1.102 + nsCOMPtr<nsIURI> inner; 1.103 + rv = NS_NewURI(getter_AddRefs(inner), spec); 1.104 + NS_ENSURE_SUCCESS(rv, rv); 1.105 + 1.106 + nsSimpleNestedURI* outer = new nsNestedAboutURI(inner, aBaseURI); 1.107 + NS_ENSURE_TRUE(outer, NS_ERROR_OUT_OF_MEMORY); 1.108 + 1.109 + // Take a ref to it in the COMPtr we plan to return 1.110 + url = outer; 1.111 + 1.112 + rv = outer->SetSpec(aSpec); 1.113 + NS_ENSURE_SUCCESS(rv, rv); 1.114 + } 1.115 + 1.116 + // We don't want to allow mutation, since it would allow safe and 1.117 + // unsafe URIs to change into each other... 1.118 + NS_TryToSetImmutable(url); 1.119 + url.swap(*result); 1.120 + return NS_OK; 1.121 +} 1.122 + 1.123 +NS_IMETHODIMP 1.124 +nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) 1.125 +{ 1.126 + NS_ENSURE_ARG_POINTER(uri); 1.127 + 1.128 + // about:what you ask? 1.129 + nsCOMPtr<nsIAboutModule> aboutMod; 1.130 + nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod)); 1.131 + 1.132 + nsAutoCString path; 1.133 + nsresult rv2 = NS_GetAboutModuleName(uri, path); 1.134 + if (NS_SUCCEEDED(rv2) && path.EqualsLiteral("srcdoc")) { 1.135 + // about:srcdoc is meant to be unresolvable, yet is included in the 1.136 + // about lookup tables so that it can pass security checks when used in 1.137 + // a srcdoc iframe. To ensure that it stays unresolvable, we pretend 1.138 + // that it doesn't exist. 1.139 + rv = NS_ERROR_FACTORY_NOT_REGISTERED; 1.140 + } 1.141 + 1.142 + if (NS_SUCCEEDED(rv)) { 1.143 + // The standard return case: 1.144 + rv = aboutMod->NewChannel(uri, result); 1.145 + if (NS_SUCCEEDED(rv)) { 1.146 + // If this URI is safe for untrusted content, enforce that its 1.147 + // principal be based on the channel's originalURI by setting the 1.148 + // owner to null. 1.149 + // Note: this relies on aboutMod's newChannel implementation 1.150 + // having set the proper originalURI, which probably isn't ideal. 1.151 + if (IsSafeForUntrustedContent(aboutMod, uri)) { 1.152 + (*result)->SetOwner(nullptr); 1.153 + } 1.154 + 1.155 + nsRefPtr<nsNestedAboutURI> aboutURI; 1.156 + nsresult rv2 = uri->QueryInterface(kNestedAboutURICID, 1.157 + getter_AddRefs(aboutURI)); 1.158 + if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) { 1.159 + nsCOMPtr<nsIWritablePropertyBag2> writableBag = 1.160 + do_QueryInterface(*result); 1.161 + if (writableBag) { 1.162 + writableBag-> 1.163 + SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"), 1.164 + aboutURI->GetBaseURI()); 1.165 + } 1.166 + } 1.167 + } 1.168 + return rv; 1.169 + } 1.170 + 1.171 + // mumble... 1.172 + 1.173 + if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) { 1.174 + // This looks like an about: we don't know about. Convert 1.175 + // this to an invalid URI error. 1.176 + rv = NS_ERROR_MALFORMED_URI; 1.177 + } 1.178 + 1.179 + return rv; 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP 1.183 +nsAboutProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) 1.184 +{ 1.185 + // don't override anything. 1.186 + *_retval = false; 1.187 + return NS_OK; 1.188 +} 1.189 + 1.190 +//////////////////////////////////////////////////////////////////////////////// 1.191 +// Safe about protocol handler impl 1.192 + 1.193 +NS_IMPL_ISUPPORTS(nsSafeAboutProtocolHandler, nsIProtocolHandler) 1.194 + 1.195 +// nsIProtocolHandler methods: 1.196 + 1.197 +NS_IMETHODIMP 1.198 +nsSafeAboutProtocolHandler::GetScheme(nsACString &result) 1.199 +{ 1.200 + result.AssignLiteral("moz-safe-about"); 1.201 + return NS_OK; 1.202 +} 1.203 + 1.204 +NS_IMETHODIMP 1.205 +nsSafeAboutProtocolHandler::GetDefaultPort(int32_t *result) 1.206 +{ 1.207 + *result = -1; // no port for moz-safe-about: URLs 1.208 + return NS_OK; 1.209 +} 1.210 + 1.211 +NS_IMETHODIMP 1.212 +nsSafeAboutProtocolHandler::GetProtocolFlags(uint32_t *result) 1.213 +{ 1.214 + *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT; 1.215 + return NS_OK; 1.216 +} 1.217 + 1.218 +NS_IMETHODIMP 1.219 +nsSafeAboutProtocolHandler::NewURI(const nsACString &aSpec, 1.220 + const char *aCharset, // ignore charset info 1.221 + nsIURI *aBaseURI, 1.222 + nsIURI **result) 1.223 +{ 1.224 + nsresult rv; 1.225 + 1.226 + nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv); 1.227 + if (NS_FAILED(rv)) return rv; 1.228 + 1.229 + rv = url->SetSpec(aSpec); 1.230 + if (NS_FAILED(rv)) { 1.231 + return rv; 1.232 + } 1.233 + 1.234 + NS_TryToSetImmutable(url); 1.235 + 1.236 + *result = nullptr; 1.237 + url.swap(*result); 1.238 + return rv; 1.239 +} 1.240 + 1.241 +NS_IMETHODIMP 1.242 +nsSafeAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) 1.243 +{ 1.244 + *result = nullptr; 1.245 + return NS_ERROR_NOT_AVAILABLE; 1.246 +} 1.247 + 1.248 +NS_IMETHODIMP 1.249 +nsSafeAboutProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval) 1.250 +{ 1.251 + // don't override anything. 1.252 + *_retval = false; 1.253 + return NS_OK; 1.254 +} 1.255 + 1.256 +//////////////////////////////////////////////////////////// 1.257 +// nsNestedAboutURI implementation 1.258 +NS_INTERFACE_MAP_BEGIN(nsNestedAboutURI) 1.259 + if (aIID.Equals(kNestedAboutURICID)) 1.260 + foundInterface = static_cast<nsIURI*>(this); 1.261 + else 1.262 +NS_INTERFACE_MAP_END_INHERITING(nsSimpleNestedURI) 1.263 + 1.264 +// nsISerializable 1.265 +NS_IMETHODIMP 1.266 +nsNestedAboutURI::Read(nsIObjectInputStream* aStream) 1.267 +{ 1.268 + nsresult rv = nsSimpleNestedURI::Read(aStream); 1.269 + if (NS_FAILED(rv)) return rv; 1.270 + 1.271 + bool haveBase; 1.272 + rv = aStream->ReadBoolean(&haveBase); 1.273 + if (NS_FAILED(rv)) return rv; 1.274 + 1.275 + if (haveBase) { 1.276 + nsCOMPtr<nsISupports> supports; 1.277 + rv = aStream->ReadObject(true, getter_AddRefs(supports)); 1.278 + if (NS_FAILED(rv)) return rv; 1.279 + 1.280 + mBaseURI = do_QueryInterface(supports, &rv); 1.281 + if (NS_FAILED(rv)) return rv; 1.282 + } 1.283 + 1.284 + return NS_OK; 1.285 +} 1.286 + 1.287 +NS_IMETHODIMP 1.288 +nsNestedAboutURI::Write(nsIObjectOutputStream* aStream) 1.289 +{ 1.290 + nsresult rv = nsSimpleNestedURI::Write(aStream); 1.291 + if (NS_FAILED(rv)) return rv; 1.292 + 1.293 + rv = aStream->WriteBoolean(mBaseURI != nullptr); 1.294 + if (NS_FAILED(rv)) return rv; 1.295 + 1.296 + if (mBaseURI) { 1.297 + // A previous iteration of this code wrote out mBaseURI as nsISupports 1.298 + // and then read it in as nsIURI, which is non-kosher when mBaseURI 1.299 + // implements more than just a single line of interfaces and the 1.300 + // canonical nsISupports* isn't the one a static_cast<> of mBaseURI 1.301 + // would produce. For backwards compatibility with existing 1.302 + // serializations we continue to write mBaseURI as nsISupports but 1.303 + // switch to reading it as nsISupports, with a post-read QI to get to 1.304 + // nsIURI. 1.305 + rv = aStream->WriteCompoundObject(mBaseURI, NS_GET_IID(nsISupports), 1.306 + true); 1.307 + if (NS_FAILED(rv)) return rv; 1.308 + } 1.309 + 1.310 + return NS_OK; 1.311 +} 1.312 + 1.313 +// nsSimpleURI 1.314 +/* virtual */ nsSimpleURI* 1.315 +nsNestedAboutURI::StartClone(nsSimpleURI::RefHandlingEnum aRefHandlingMode) 1.316 +{ 1.317 + // Sadly, we can't make use of nsSimpleNestedURI::StartClone here. 1.318 + // However, this function is expected to exactly match that function, 1.319 + // aside from the "new ns***URI()" call. 1.320 + NS_ENSURE_TRUE(mInnerURI, nullptr); 1.321 + 1.322 + nsCOMPtr<nsIURI> innerClone; 1.323 + nsresult rv = aRefHandlingMode == eHonorRef ? 1.324 + mInnerURI->Clone(getter_AddRefs(innerClone)) : 1.325 + mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone)); 1.326 + 1.327 + if (NS_FAILED(rv)) { 1.328 + return nullptr; 1.329 + } 1.330 + 1.331 + nsNestedAboutURI* url = new nsNestedAboutURI(innerClone, mBaseURI); 1.332 + url->SetMutable(false); 1.333 + 1.334 + return url; 1.335 +} 1.336 + 1.337 +// nsIClassInfo 1.338 +NS_IMETHODIMP 1.339 +nsNestedAboutURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) 1.340 +{ 1.341 + *aClassIDNoAlloc = kNestedAboutURICID; 1.342 + return NS_OK; 1.343 +}