Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "xpcpublic.h"
7 : #include "nsString.h"
8 : #include "nsIObjectOutputStream.h"
9 : #include "nsIObjectInputStream.h"
10 : #include "nsJSPrincipals.h"
11 : #include "plstr.h"
12 : #include "nsXPIDLString.h"
13 : #include "nsCOMPtr.h"
14 : #include "nsIServiceManager.h"
15 : #include "nsMemory.h"
16 : #include "nsStringBuffer.h"
17 :
18 : #include "mozilla/dom/StructuredCloneTags.h"
19 : // for mozilla::dom::workers::kJSPrincipalsDebugToken
20 : #include "mozilla/dom/workers/Workers.h"
21 : #include "mozilla/ipc/BackgroundUtils.h"
22 :
23 : using namespace mozilla;
24 : using namespace mozilla::ipc;
25 :
26 : NS_IMETHODIMP_(MozExternalRefCountType)
27 15122 : nsJSPrincipals::AddRef()
28 : {
29 15122 : MOZ_ASSERT(NS_IsMainThread());
30 15122 : NS_PRECONDITION(int32_t(refcount) >= 0, "illegal refcnt");
31 15122 : nsrefcnt count = ++refcount;
32 15122 : NS_LOG_ADDREF(this, count, "nsJSPrincipals", sizeof(*this));
33 15122 : return count;
34 : }
35 :
36 : NS_IMETHODIMP_(MozExternalRefCountType)
37 13145 : nsJSPrincipals::Release()
38 : {
39 13145 : MOZ_ASSERT(NS_IsMainThread());
40 13145 : NS_PRECONDITION(0 != refcount, "dup release");
41 13145 : nsrefcnt count = --refcount;
42 13145 : NS_LOG_RELEASE(this, count, "nsJSPrincipals");
43 13145 : if (count == 0) {
44 177 : delete this;
45 : }
46 :
47 13145 : return count;
48 : }
49 :
50 : /* static */ bool
51 0 : nsJSPrincipals::Subsume(JSPrincipals *jsprin, JSPrincipals *other)
52 : {
53 : bool result;
54 0 : nsresult rv = nsJSPrincipals::get(jsprin)->Subsumes(nsJSPrincipals::get(other), &result);
55 0 : return NS_SUCCEEDED(rv) && result;
56 : }
57 :
58 : /* static */ void
59 0 : nsJSPrincipals::Destroy(JSPrincipals *jsprin)
60 : {
61 : // The JS runtime can call this method during the last GC when
62 : // nsScriptSecurityManager is destroyed. So we must not assume here that
63 : // the security manager still exists.
64 :
65 0 : nsJSPrincipals *nsjsprin = nsJSPrincipals::get(jsprin);
66 :
67 : // We need to destroy the nsIPrincipal. We'll do this by adding
68 : // to the refcount and calling release
69 :
70 : #ifdef NS_BUILD_REFCNT_LOGGING
71 : // The refcount logging considers AddRef-to-1 to indicate creation,
72 : // so trick it into thinking it's otherwise, but balance the
73 : // Release() we do below.
74 0 : nsjsprin->refcount++;
75 0 : nsjsprin->AddRef();
76 0 : nsjsprin->refcount--;
77 : #else
78 : nsjsprin->refcount++;
79 : #endif
80 0 : nsjsprin->Release();
81 0 : }
82 :
83 : #ifdef DEBUG
84 :
85 : // Defined here so one can do principals->dump() in the debugger
86 : JS_PUBLIC_API(void)
87 0 : JSPrincipals::dump()
88 : {
89 0 : if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
90 0 : nsAutoCString str;
91 0 : nsresult rv = static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str);
92 0 : fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this),
93 0 : NS_SUCCEEDED(rv) ? str.get() : "(unknown)");
94 0 : } else if (debugToken == dom::workers::kJSPrincipalsDebugToken) {
95 0 : fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
96 : } else {
97 : fprintf(stderr,
98 : "!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: "
99 : "actual=0x%x expected=0x%x\n",
100 0 : this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN));
101 : }
102 0 : }
103 :
104 : #endif
105 :
106 : /* static */ bool
107 0 : nsJSPrincipals::ReadPrincipals(JSContext* aCx, JSStructuredCloneReader* aReader,
108 : JSPrincipals** aOutPrincipals)
109 : {
110 : uint32_t tag;
111 : uint32_t unused;
112 0 : if (!JS_ReadUint32Pair(aReader, &tag, &unused)) {
113 0 : return false;
114 : }
115 :
116 0 : if (!(tag == SCTAG_DOM_NULL_PRINCIPAL ||
117 0 : tag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
118 0 : tag == SCTAG_DOM_CONTENT_PRINCIPAL ||
119 0 : tag == SCTAG_DOM_EXPANDED_PRINCIPAL)) {
120 0 : xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
121 0 : return false;
122 : }
123 :
124 0 : return ReadKnownPrincipalType(aCx, aReader, tag, aOutPrincipals);
125 : }
126 :
127 : static bool
128 1 : ReadSuffixAndSpec(JSStructuredCloneReader* aReader,
129 : OriginAttributes& aAttrs,
130 : nsACString& aSpec)
131 : {
132 : uint32_t suffixLength, specLength;
133 1 : if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
134 0 : return false;
135 : }
136 :
137 2 : nsAutoCString suffix;
138 1 : if (!suffix.SetLength(suffixLength, fallible)) {
139 0 : return false;
140 : }
141 :
142 1 : if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
143 0 : return false;
144 : }
145 :
146 1 : if (!aAttrs.PopulateFromSuffix(suffix)) {
147 0 : return false;
148 : }
149 :
150 1 : if (!aSpec.SetLength(specLength, fallible)) {
151 0 : return false;
152 : }
153 :
154 1 : if (!JS_ReadBytes(aReader, aSpec.BeginWriting(), specLength)) {
155 0 : return false;
156 : }
157 :
158 1 : return true;
159 : }
160 :
161 : static bool
162 1 : ReadPrincipalInfo(JSStructuredCloneReader* aReader,
163 : uint32_t aTag,
164 : PrincipalInfo& aInfo)
165 : {
166 1 : if (aTag == SCTAG_DOM_SYSTEM_PRINCIPAL) {
167 0 : aInfo = SystemPrincipalInfo();
168 1 : } else if (aTag == SCTAG_DOM_NULL_PRINCIPAL) {
169 0 : OriginAttributes attrs;
170 0 : nsAutoCString spec;
171 0 : if (!ReadSuffixAndSpec(aReader, attrs, spec)) {
172 0 : return false;
173 : }
174 0 : aInfo = NullPrincipalInfo(attrs, spec);
175 1 : } else if (aTag == SCTAG_DOM_EXPANDED_PRINCIPAL) {
176 : uint32_t length, unused;
177 0 : if (!JS_ReadUint32Pair(aReader, &length, &unused)) {
178 0 : return false;
179 : }
180 :
181 0 : ExpandedPrincipalInfo expanded;
182 :
183 0 : for (uint32_t i = 0; i < length; i++) {
184 : uint32_t tag;
185 0 : if (!JS_ReadUint32Pair(aReader, &tag, &unused)) {
186 0 : return false;
187 : }
188 :
189 0 : PrincipalInfo sub;
190 0 : if (!ReadPrincipalInfo(aReader, tag, sub)) {
191 0 : return false;
192 : }
193 0 : expanded.whitelist().AppendElement(sub);
194 : }
195 :
196 0 : aInfo = expanded;
197 1 : } else if (aTag == SCTAG_DOM_CONTENT_PRINCIPAL) {
198 2 : OriginAttributes attrs;
199 2 : nsAutoCString spec;
200 1 : if (!ReadSuffixAndSpec(aReader, attrs, spec)) {
201 0 : return false;
202 : }
203 :
204 1 : aInfo = ContentPrincipalInfo(attrs, void_t(), spec);
205 : } else {
206 0 : MOZ_CRASH("unexpected principal structured clone tag");
207 : }
208 :
209 1 : return true;
210 : }
211 :
212 : /* static */ bool
213 1 : nsJSPrincipals::ReadKnownPrincipalType(JSContext* aCx,
214 : JSStructuredCloneReader* aReader,
215 : uint32_t aTag,
216 : JSPrincipals** aOutPrincipals)
217 : {
218 1 : MOZ_ASSERT(aTag == SCTAG_DOM_NULL_PRINCIPAL ||
219 : aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
220 : aTag == SCTAG_DOM_CONTENT_PRINCIPAL ||
221 : aTag == SCTAG_DOM_EXPANDED_PRINCIPAL);
222 :
223 1 : if (NS_WARN_IF(!NS_IsMainThread())) {
224 0 : xpc::Throw(aCx, NS_ERROR_UNCATCHABLE_EXCEPTION);
225 0 : return false;
226 : }
227 :
228 2 : PrincipalInfo info;
229 1 : if (!ReadPrincipalInfo(aReader, aTag, info)) {
230 0 : return false;
231 : }
232 :
233 : nsresult rv;
234 2 : nsCOMPtr<nsIPrincipal> prin = PrincipalInfoToPrincipal(info, &rv);
235 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
236 0 : xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
237 0 : return false;
238 : }
239 :
240 1 : *aOutPrincipals = get(prin.forget().take());
241 1 : return true;
242 : }
243 :
244 : static bool
245 1 : WriteSuffixAndSpec(JSStructuredCloneWriter* aWriter,
246 : const OriginAttributes& aAttrs,
247 : const nsCString& aSpec)
248 : {
249 2 : nsAutoCString suffix;
250 1 : aAttrs.CreateSuffix(suffix);
251 :
252 2 : return JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) &&
253 2 : JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
254 3 : JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length());
255 : }
256 :
257 : static bool
258 1 : WritePrincipalInfo(JSStructuredCloneWriter* aWriter, const PrincipalInfo& aInfo)
259 : {
260 1 : if (aInfo.type() == PrincipalInfo::TNullPrincipalInfo) {
261 0 : const NullPrincipalInfo& nullInfo = aInfo;
262 0 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0) &&
263 0 : WriteSuffixAndSpec(aWriter, nullInfo.attrs(), nullInfo.spec());
264 : }
265 1 : if (aInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
266 0 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_SYSTEM_PRINCIPAL, 0);
267 : }
268 1 : if (aInfo.type() == PrincipalInfo::TExpandedPrincipalInfo) {
269 0 : const ExpandedPrincipalInfo& expanded = aInfo;
270 0 : if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_EXPANDED_PRINCIPAL, 0) ||
271 0 : !JS_WriteUint32Pair(aWriter, expanded.whitelist().Length(), 0)) {
272 0 : return false;
273 : }
274 :
275 0 : for (uint32_t i = 0; i < expanded.whitelist().Length(); i++) {
276 0 : if (!WritePrincipalInfo(aWriter, expanded.whitelist()[i])) {
277 0 : return false;
278 : }
279 : }
280 0 : return true;
281 : }
282 :
283 1 : MOZ_ASSERT(aInfo.type() == PrincipalInfo::TContentPrincipalInfo);
284 1 : const ContentPrincipalInfo& cInfo = aInfo;
285 2 : return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL, 0) &&
286 2 : WriteSuffixAndSpec(aWriter, cInfo.attrs(), cInfo.spec());
287 : }
288 :
289 : bool
290 1 : nsJSPrincipals::write(JSContext* aCx, JSStructuredCloneWriter* aWriter)
291 : {
292 2 : PrincipalInfo info;
293 1 : if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(this, &info)))) {
294 0 : xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
295 0 : return false;
296 : }
297 :
298 1 : return WritePrincipalInfo(aWriter, info);
299 : }
|