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 : /*
7 : * Utility routines for checking content load/process policy settings,
8 : * and routines helpful for content policy implementors.
9 : *
10 : * XXXbz it would be nice if some of this stuff could be out-of-lined in
11 : * nsContentUtils. That would work for almost all the callers...
12 : */
13 :
14 : #ifndef __nsContentPolicyUtils_h__
15 : #define __nsContentPolicyUtils_h__
16 :
17 : #include "nsContentUtils.h"
18 : #include "nsIContentPolicy.h"
19 : #include "nsIContent.h"
20 : #include "nsIScriptSecurityManager.h"
21 : #include "nsIURI.h"
22 : #include "nsServiceManagerUtils.h"
23 :
24 : //XXXtw sadly, this makes consumers of nsContentPolicyUtils depend on widget
25 : #include "nsIDocument.h"
26 : #include "nsPIDOMWindow.h"
27 :
28 : class nsACString;
29 : class nsIPrincipal;
30 :
31 : #define NS_CONTENTPOLICY_CONTRACTID "@mozilla.org/layout/content-policy;1"
32 : #define NS_CONTENTPOLICY_CATEGORY "content-policy"
33 : #define NS_SIMPLECONTENTPOLICY_CATEGORY "simple-content-policy"
34 : #define NS_CONTENTPOLICY_CID \
35 : {0x0e3afd3d, 0xeb60, 0x4c2b, \
36 : { 0x96, 0x3b, 0x56, 0xd7, 0xc4, 0x39, 0xf1, 0x24 }}
37 :
38 : /**
39 : * Evaluates to true if val is ACCEPT.
40 : *
41 : * @param val the status returned from shouldProcess/shouldLoad
42 : */
43 : #define NS_CP_ACCEPTED(val) ((val) == nsIContentPolicy::ACCEPT)
44 :
45 : /**
46 : * Evaluates to true if val is a REJECT_* status
47 : *
48 : * @param val the status returned from shouldProcess/shouldLoad
49 : */
50 : #define NS_CP_REJECTED(val) ((val) != nsIContentPolicy::ACCEPT)
51 :
52 : // Offer convenient translations of constants -> const char*
53 :
54 : // convenience macro to reduce some repetative typing...
55 : // name is the name of a constant from this interface
56 : #define CASE_RETURN(name) \
57 : case nsIContentPolicy:: name : \
58 : return #name
59 :
60 : /**
61 : * Returns a string corresponding to the name of the response constant, or
62 : * "<Unknown Response>" if an unknown response value is given.
63 : *
64 : * The return value is static and must not be freed.
65 : *
66 : * @param response the response code
67 : * @return the name of the given response code
68 : */
69 : inline const char *
70 0 : NS_CP_ResponseName(int16_t response)
71 : {
72 0 : switch (response) {
73 0 : CASE_RETURN( REJECT_REQUEST );
74 0 : CASE_RETURN( REJECT_TYPE );
75 0 : CASE_RETURN( REJECT_SERVER );
76 0 : CASE_RETURN( REJECT_OTHER );
77 0 : CASE_RETURN( ACCEPT );
78 : default:
79 0 : return "<Unknown Response>";
80 : }
81 : }
82 :
83 : /**
84 : * Returns a string corresponding to the name of the content type constant, or
85 : * "<Unknown Type>" if an unknown content type value is given.
86 : *
87 : * The return value is static and must not be freed.
88 : *
89 : * @param contentType the content type code
90 : * @return the name of the given content type code
91 : */
92 : inline const char *
93 : NS_CP_ContentTypeName(uint32_t contentType)
94 : {
95 : switch (contentType) {
96 : CASE_RETURN( TYPE_OTHER );
97 : CASE_RETURN( TYPE_SCRIPT );
98 : CASE_RETURN( TYPE_IMAGE );
99 : CASE_RETURN( TYPE_STYLESHEET );
100 : CASE_RETURN( TYPE_OBJECT );
101 : CASE_RETURN( TYPE_DOCUMENT );
102 : CASE_RETURN( TYPE_SUBDOCUMENT );
103 : CASE_RETURN( TYPE_REFRESH );
104 : CASE_RETURN( TYPE_XBL );
105 : CASE_RETURN( TYPE_PING );
106 : CASE_RETURN( TYPE_XMLHTTPREQUEST );
107 : CASE_RETURN( TYPE_OBJECT_SUBREQUEST );
108 : CASE_RETURN( TYPE_DTD );
109 : CASE_RETURN( TYPE_FONT );
110 : CASE_RETURN( TYPE_MEDIA );
111 : CASE_RETURN( TYPE_WEBSOCKET );
112 : CASE_RETURN( TYPE_CSP_REPORT );
113 : CASE_RETURN( TYPE_XSLT );
114 : CASE_RETURN( TYPE_BEACON );
115 : CASE_RETURN( TYPE_FETCH );
116 : CASE_RETURN( TYPE_IMAGESET );
117 : CASE_RETURN( TYPE_WEB_MANIFEST );
118 : CASE_RETURN( TYPE_INTERNAL_SCRIPT );
119 : CASE_RETURN( TYPE_INTERNAL_WORKER );
120 : CASE_RETURN( TYPE_INTERNAL_SHARED_WORKER );
121 : CASE_RETURN( TYPE_INTERNAL_EMBED );
122 : CASE_RETURN( TYPE_INTERNAL_OBJECT );
123 : CASE_RETURN( TYPE_INTERNAL_FRAME );
124 : CASE_RETURN( TYPE_INTERNAL_IFRAME );
125 : CASE_RETURN( TYPE_INTERNAL_AUDIO );
126 : CASE_RETURN( TYPE_INTERNAL_VIDEO );
127 : CASE_RETURN( TYPE_INTERNAL_TRACK );
128 : CASE_RETURN( TYPE_INTERNAL_XMLHTTPREQUEST );
129 : CASE_RETURN( TYPE_INTERNAL_EVENTSOURCE );
130 : CASE_RETURN( TYPE_INTERNAL_SERVICE_WORKER );
131 : CASE_RETURN( TYPE_INTERNAL_SCRIPT_PRELOAD );
132 : CASE_RETURN( TYPE_INTERNAL_IMAGE );
133 : CASE_RETURN( TYPE_INTERNAL_IMAGE_PRELOAD );
134 : CASE_RETURN( TYPE_INTERNAL_IMAGE_FAVICON );
135 : CASE_RETURN( TYPE_INTERNAL_STYLESHEET );
136 : CASE_RETURN( TYPE_INTERNAL_STYLESHEET_PRELOAD );
137 : CASE_RETURN( TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS );
138 : default:
139 : return "<Unknown Type>";
140 : }
141 : }
142 :
143 : #undef CASE_RETURN
144 :
145 : /* Passes on parameters from its "caller"'s context. */
146 : #define CHECK_CONTENT_POLICY(action) \
147 : PR_BEGIN_MACRO \
148 : nsCOMPtr<nsIContentPolicy> policy = \
149 : do_GetService(NS_CONTENTPOLICY_CONTRACTID); \
150 : if (!policy) \
151 : return NS_ERROR_FAILURE; \
152 : \
153 : return policy-> action (contentType, contentLocation, requestOrigin, \
154 : context, mimeType, extra, originPrincipal, \
155 : decision); \
156 : PR_END_MACRO
157 :
158 : /* Passes on parameters from its "caller"'s context. */
159 : #define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy) \
160 : PR_BEGIN_MACRO \
161 : return _policy-> action (contentType, contentLocation, requestOrigin, \
162 : context, mimeType, extra, originPrincipal, \
163 : decision); \
164 : PR_END_MACRO
165 :
166 : /**
167 : * Check whether we can short-circuit this check and bail out. If not, get the
168 : * origin URI to use.
169 : *
170 : * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on
171 : * purpose */
172 : #define CHECK_PRINCIPAL_AND_DATA(action) \
173 : nsCOMPtr<nsIURI> requestOrigin; \
174 : PR_BEGIN_MACRO \
175 : if (originPrincipal) { \
176 : nsCOMPtr<nsIScriptSecurityManager> secMan = aSecMan; \
177 : if (!secMan) { \
178 : secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); \
179 : } \
180 : if (secMan) { \
181 : bool isSystem; \
182 : nsresult rv = secMan->IsSystemPrincipal(originPrincipal, \
183 : &isSystem); \
184 : NS_ENSURE_SUCCESS(rv, rv); \
185 : if (isSystem && contentType != nsIContentPolicy::TYPE_DOCUMENT) { \
186 : *decision = nsIContentPolicy::ACCEPT; \
187 : nsCOMPtr<nsINode> n = do_QueryInterface(context); \
188 : if (!n) { \
189 : nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(context);\
190 : n = win ? win->GetExtantDoc() : nullptr; \
191 : } \
192 : if (n) { \
193 : nsIDocument* d = n->OwnerDoc(); \
194 : if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() || \
195 : d->IsResourceDoc()) { \
196 : nsCOMPtr<nsIContentPolicy> dataPolicy = \
197 : do_GetService( \
198 : "@mozilla.org/data-document-content-policy;1"); \
199 : if (dataPolicy) { \
200 : nsContentPolicyType externalType = \
201 : nsContentUtils::InternalContentPolicyTypeToExternal(contentType);\
202 : dataPolicy-> action (externalType, contentLocation, \
203 : requestOrigin, context, \
204 : mimeType, extra, \
205 : originPrincipal, decision); \
206 : } \
207 : } \
208 : } \
209 : return NS_OK; \
210 : } \
211 : } \
212 : nsresult rv = originPrincipal->GetURI(getter_AddRefs(requestOrigin)); \
213 : NS_ENSURE_SUCCESS(rv, rv); \
214 : } \
215 : PR_END_MACRO
216 :
217 : /**
218 : * Alias for calling ShouldLoad on the content policy service. Parameters are
219 : * the same as nsIContentPolicy::shouldLoad, except for the originPrincipal
220 : * parameter, which should be non-null if possible, and the last two
221 : * parameters, which can be used to pass in pointer to some useful services if
222 : * the caller already has them. The origin URI to pass to shouldLoad will be
223 : * the URI of originPrincipal, unless originPrincipal is null (in which case a
224 : * null origin URI will be passed).
225 : */
226 : inline nsresult
227 210 : NS_CheckContentLoadPolicy(uint32_t contentType,
228 : nsIURI *contentLocation,
229 : nsIPrincipal *originPrincipal,
230 : nsISupports *context,
231 : const nsACString &mimeType,
232 : nsISupports *extra,
233 : int16_t *decision,
234 : nsIContentPolicy *policyService = nullptr,
235 : nsIScriptSecurityManager* aSecMan = nullptr)
236 : {
237 420 : CHECK_PRINCIPAL_AND_DATA(ShouldLoad);
238 23 : if (policyService) {
239 18 : CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad, policyService);
240 : }
241 5 : CHECK_CONTENT_POLICY(ShouldLoad);
242 : }
243 :
244 : /**
245 : * Alias for calling ShouldProcess on the content policy service. Parameters
246 : * are the same as nsIContentPolicy::shouldLoad, except for the originPrincipal
247 : * parameter, which should be non-null if possible, and the last two
248 : * parameters, which can be used to pass in pointer to some useful services if
249 : * the caller already has them. The origin URI to pass to shouldLoad will be
250 : * the URI of originPrincipal, unless originPrincipal is null (in which case a
251 : * null origin URI will be passed).
252 : */
253 : inline nsresult
254 0 : NS_CheckContentProcessPolicy(uint32_t contentType,
255 : nsIURI *contentLocation,
256 : nsIPrincipal *originPrincipal,
257 : nsISupports *context,
258 : const nsACString &mimeType,
259 : nsISupports *extra,
260 : int16_t *decision,
261 : nsIContentPolicy *policyService = nullptr,
262 : nsIScriptSecurityManager* aSecMan = nullptr)
263 : {
264 0 : CHECK_PRINCIPAL_AND_DATA(ShouldProcess);
265 0 : if (policyService) {
266 0 : CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess, policyService);
267 : }
268 0 : CHECK_CONTENT_POLICY(ShouldProcess);
269 : }
270 :
271 : #undef CHECK_CONTENT_POLICY
272 : #undef CHECK_CONTENT_POLICY_WITH_SERVICE
273 :
274 : /**
275 : * Helper function to get an nsIDocShell given a context.
276 : * If the context is a document or window, the corresponding docshell will be
277 : * returned.
278 : * If the context is a non-document DOM node, the docshell of its ownerDocument
279 : * will be returned.
280 : *
281 : * @param aContext the context to find a docshell for (can be null)
282 : *
283 : * @return a WEAK pointer to the docshell, or nullptr if it could
284 : * not be obtained
285 : *
286 : * @note As of this writing, calls to nsIContentPolicy::Should{Load,Process}
287 : * for TYPE_DOCUMENT and TYPE_SUBDOCUMENT pass in an aContext that either
288 : * points to the frameElement of the window the load is happening in
289 : * (in which case NS_CP_GetDocShellFromContext will return the parent of the
290 : * docshell the load is happening in), or points to the window the load is
291 : * happening in (in which case NS_CP_GetDocShellFromContext will return
292 : * the docshell the load is happening in). It's up to callers to QI aContext
293 : * and handle things accordingly if they want the docshell the load is
294 : * happening in. These are somewhat odd semantics, and bug 466687 has been
295 : * filed to consider improving them.
296 : */
297 : inline nsIDocShell*
298 35 : NS_CP_GetDocShellFromContext(nsISupports *aContext)
299 : {
300 35 : if (!aContext) {
301 13 : return nullptr;
302 : }
303 :
304 44 : nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aContext);
305 :
306 22 : if (!window) {
307 : // our context might be a document (which also QIs to nsIDOMNode), so
308 : // try that first
309 36 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(aContext);
310 18 : if (!doc) {
311 : // we were not a document after all, get our ownerDocument,
312 : // hopefully
313 20 : nsCOMPtr<nsIContent> content = do_QueryInterface(aContext);
314 10 : if (content) {
315 10 : doc = content->OwnerDoc();
316 : }
317 : }
318 :
319 18 : if (doc) {
320 18 : if (doc->GetDisplayDocument()) {
321 0 : doc = doc->GetDisplayDocument();
322 : }
323 :
324 18 : window = doc->GetWindow();
325 : }
326 : }
327 :
328 22 : if (!window) {
329 0 : return nullptr;
330 : }
331 :
332 22 : return window->GetDocShell();
333 : }
334 :
335 : #endif /* __nsContentPolicyUtils_h__ */
|