2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
3 * 2007 Pekka Lampila <pekka.lampila@iki.fi>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
27 #include "swfdec_policy_file.h"
28 #include "swfdec_resource.h"
29 #include "swfdec_as_strings.h"
30 #include "swfdec_debug.h"
31 #include "swfdec_internal.h"
32 #include "swfdec_loader_internal.h"
33 #include "swfdec_player_internal.h"
34 #include "swfdec_sandbox.h"
35 #include "swfdec_xml.h"
36 #include "swfdec_xml_node.h"
38 typedef struct _SwfdecPolicyFileRequest SwfdecPolicyFileRequest
;
39 struct _SwfdecPolicyFileRequest
{
40 SwfdecURL
* from
; /* URL we are supposed to check */
41 SwfdecURL
* url
; /* URL we are supposed to check */
42 SwfdecPolicyFunc func
; /* function to call when we know if access is (not) allowed */
43 gpointer data
; /* data to pass to func */
47 swfdec_policy_file_request_free (SwfdecPolicyFileRequest
*request
)
49 swfdec_url_free (request
->from
);
50 swfdec_url_free (request
->url
);
51 g_slice_free (SwfdecPolicyFileRequest
, request
);
54 /*** PARSING THE FILE ***/
57 swfdec_policy_file_parse (SwfdecPolicyFile
*file
, const char *text
)
62 g_return_if_fail (SWFDEC_IS_POLICY_FILE (file
));
63 g_return_if_fail (text
!= NULL
);
65 /* FIXME: the sandboxes are a HACK */
66 swfdec_sandbox_use (SWFDEC_MOVIE (file
->player
->priv
->roots
->data
)->resource
->sandbox
);
67 xml
= swfdec_xml_new_no_properties (SWFDEC_AS_CONTEXT (file
->player
), text
, TRUE
);
68 swfdec_sandbox_unuse (SWFDEC_MOVIE (file
->player
->priv
->roots
->data
)->resource
->sandbox
);
71 SWFDEC_ERROR ("failed to create an XML object for crossdomain policy");
75 if (SWFDEC_XML_NODE (xml
)->type
!= SWFDEC_XML_NODE_ELEMENT
) {
76 SWFDEC_LOG ("empty crossdomain policy file");
80 for (i
= 0; i
< swfdec_xml_node_num_children (SWFDEC_XML_NODE (xml
)); i
++) {
81 SwfdecXmlNode
*node_cdp
=
82 swfdec_xml_node_get_child (SWFDEC_XML_NODE (xml
), i
);
84 if (node_cdp
->type
!= SWFDEC_XML_NODE_ELEMENT
)
87 if (g_ascii_strcasecmp (node_cdp
->name
, "cross-domain-policy") != 0)
90 for (j
= 0; j
< swfdec_xml_node_num_children (node_cdp
); j
++) {
91 SwfdecXmlNode
*node_aaf
= swfdec_xml_node_get_child (node_cdp
, j
);
93 GPatternSpec
*pattern
;
96 if (node_aaf
->type
!= SWFDEC_XML_NODE_ELEMENT
)
99 if (g_ascii_strcasecmp (node_aaf
->name
, "allow-access-from") != 0)
102 // FIXME: secure attribute?
104 value
= swfdec_xml_node_get_attribute (node_aaf
, SWFDEC_AS_STR_domain
);
108 if (strchr (value
, '?') != NULL
) {
109 SWFDEC_WARNING ("'?' in allowed domain attribute for %s", value
);
113 value_lower
= g_ascii_strdown (value
, -1);
114 pattern
= g_pattern_spec_new (value_lower
);
115 g_free (value_lower
);
117 file
->allowed_hosts
= g_slist_prepend (file
->allowed_hosts
, pattern
);
122 /*** SWFDEC_STREAM_TARGET ***/
124 static SwfdecPlayer
*
125 swfdec_policy_file_target_get_player (SwfdecStreamTarget
*target
)
127 return SWFDEC_POLICY_FILE (target
)->player
;
131 swfdec_policy_file_finished_loading (SwfdecPolicyFile
*file
, const char *text
)
133 SwfdecPlayerPrivate
*priv
;
134 SwfdecPolicyFile
*next
;
137 swfdec_stream_set_target (file
->stream
, NULL
);
141 swfdec_policy_file_parse (file
, text
);
143 priv
= file
->player
->priv
;
144 link
= g_list_find (priv
->loading_policy_files
, file
);
145 next
= link
->next
? link
->next
->data
: NULL
;
146 priv
->loading_policy_files
= g_list_delete_link (priv
->loading_policy_files
, link
);
147 priv
->policy_files
= g_slist_prepend (priv
->policy_files
, file
);
149 next
->requests
= g_slist_concat (next
->requests
, file
->requests
);
153 for (walk
= file
->requests
; walk
; walk
= walk
->next
) {
154 SwfdecPolicyFileRequest
*request
= walk
->data
;
155 gboolean allow
= swfdec_player_allow_now (file
->player
, request
->from
, request
->url
);
156 request
->func (file
->player
, allow
, request
->data
);
157 swfdec_policy_file_request_free (request
);
159 g_slist_free (file
->requests
);
161 file
->requests
= NULL
;
165 swfdec_policy_file_target_open (SwfdecStreamTarget
*target
,
166 SwfdecStream
*stream
)
168 if (SWFDEC_IS_SOCKET (stream
)) {
169 SwfdecBuffer
*buffer
= swfdec_buffer_new_static (
170 "<policy-file-request/>", 23);
171 swfdec_socket_send (SWFDEC_SOCKET (stream
), buffer
);
176 swfdec_policy_file_target_error (SwfdecStreamTarget
*target
,
177 SwfdecStream
*stream
)
179 SwfdecPolicyFile
*file
= SWFDEC_POLICY_FILE (target
);
181 swfdec_policy_file_finished_loading (file
, NULL
);
185 swfdec_policy_file_target_close (SwfdecStreamTarget
*target
,
186 SwfdecStream
*stream
)
188 SwfdecPolicyFile
*file
= SWFDEC_POLICY_FILE (target
);
191 text
= swfdec_buffer_queue_pull_text (swfdec_stream_get_queue (stream
), 8);
194 SWFDEC_ERROR ("couldn't get text from crossdomain policy file %s",
195 swfdec_url_get_url (file
->load_url
));
197 swfdec_policy_file_finished_loading (file
, text
);
202 swfdec_policy_file_stream_target_init (SwfdecStreamTargetInterface
*iface
)
204 iface
->get_player
= swfdec_policy_file_target_get_player
;
205 iface
->open
= swfdec_policy_file_target_open
;
206 iface
->close
= swfdec_policy_file_target_close
;
207 iface
->error
= swfdec_policy_file_target_error
;
210 /*** SWFDEC_POLICY_FILE ***/
212 G_DEFINE_TYPE_WITH_CODE (SwfdecPolicyFile
, swfdec_policy_file
, G_TYPE_OBJECT
,
213 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_STREAM_TARGET
, swfdec_policy_file_stream_target_init
))
216 swfdec_policy_file_dispose (GObject
*object
)
218 SwfdecPolicyFile
*file
= SWFDEC_POLICY_FILE (object
);
221 swfdec_stream_set_target (file
->stream
, NULL
);
222 g_object_unref (file
->stream
);
224 g_slist_foreach (file
->requests
, (GFunc
) swfdec_policy_file_request_free
, NULL
);
225 g_slist_free (file
->requests
);
226 file
->requests
= NULL
;
228 g_assert (file
->requests
== NULL
);
230 swfdec_url_free (file
->load_url
);
231 swfdec_url_free (file
->url
);
233 G_OBJECT_CLASS (swfdec_policy_file_parent_class
)->dispose (object
);
237 swfdec_policy_file_class_init (SwfdecPolicyFileClass
*klass
)
239 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
241 object_class
->dispose
= swfdec_policy_file_dispose
;
245 swfdec_policy_file_init (SwfdecPolicyFile
*policy_file
)
250 swfdec_policy_file_new (SwfdecPlayer
*player
, const SwfdecURL
*url
)
252 SwfdecPolicyFile
*file
;
254 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
255 g_return_val_if_fail (url
!= NULL
, NULL
);
257 file
= g_object_new (SWFDEC_TYPE_POLICY_FILE
, NULL
);
258 file
->player
= player
;
259 file
->load_url
= swfdec_url_copy (url
);
260 file
->url
= swfdec_url_new_parent (url
);
261 if (swfdec_url_has_protocol (url
, "xmlsocket")) {
262 file
->stream
= SWFDEC_STREAM (swfdec_player_create_socket (player
,
263 swfdec_url_get_host (url
), swfdec_url_get_port (url
)));
265 file
->stream
= SWFDEC_STREAM (swfdec_player_load (player
,
266 swfdec_url_get_url (url
), NULL
));
268 swfdec_stream_set_target (file
->stream
, SWFDEC_STREAM_TARGET (file
));
269 player
->priv
->loading_policy_files
=
270 g_list_prepend (player
->priv
->loading_policy_files
, file
);
276 swfdec_policy_file_is_loading (SwfdecPolicyFile
*file
)
278 g_return_val_if_fail (SWFDEC_IS_POLICY_FILE (file
), FALSE
);
280 return file
->stream
!= NULL
;
284 swfdec_policy_file_allow (SwfdecPolicyFile
*file
, const SwfdecURL
*from
, const SwfdecURL
*url
)
289 const char *hostname
;
291 g_return_val_if_fail (SWFDEC_IS_POLICY_FILE (file
), FALSE
);
292 g_return_val_if_fail (from
!= NULL
, FALSE
);
293 g_return_val_if_fail (url
!= NULL
, FALSE
);
295 /* first check if the policy file is allowing the following url */
296 if (!swfdec_url_is_parent (file
->url
, url
))
299 /* then try to find the from url in the allowed hosts */
300 hostname
= swfdec_url_get_host (from
);
301 /* This is a hack that simplifies the following code. As the pattern can not
302 * contain any ?, the only pattern that matches the string "?" is the pattern
305 if (hostname
== NULL
)
307 len
= strlen (hostname
);
308 emantsoh
= g_utf8_strreverse (hostname
, len
);
309 for (walk
= file
->allowed_hosts
; walk
; walk
= walk
->next
) {
310 GPatternSpec
*pattern
= walk
->data
;
311 if (g_pattern_match (pattern
, len
, hostname
, emantsoh
)) {
323 swfdec_player_allow_now (SwfdecPlayer
*player
, const SwfdecURL
*from
, const SwfdecURL
*url
)
327 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
328 g_return_val_if_fail (url
!= NULL
, FALSE
);
330 for (walk
= player
->priv
->policy_files
; walk
; walk
= walk
->next
) {
331 if (swfdec_policy_file_allow (walk
->data
, from
, url
))
338 swfdec_player_allow_or_load (SwfdecPlayer
*player
, const SwfdecURL
*from
,
339 const SwfdecURL
*url
, const SwfdecURL
*crossdomain
, SwfdecPolicyFunc func
, gpointer data
)
341 SwfdecPlayerPrivate
*priv
;
342 SwfdecPolicyFileRequest
*request
;
343 SwfdecPolicyFile
*file
;
345 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
346 g_return_if_fail (url
!= NULL
);
347 g_return_if_fail (func
);
349 if (swfdec_player_allow_now (player
, from
, url
)) {
350 func (player
, TRUE
, data
);
354 swfdec_policy_file_new (player
, crossdomain
);
357 if (priv
->loading_policy_files
== NULL
) {
358 func (player
, FALSE
, data
);
361 request
= g_slice_new (SwfdecPolicyFileRequest
);
362 request
->from
= swfdec_url_copy (from
);
363 request
->url
= swfdec_url_copy (url
);
364 request
->func
= func
;
365 request
->data
= data
;
367 file
= priv
->loading_policy_files
->data
;
368 file
->requests
= g_slist_append (file
->requests
, request
);