2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program 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
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "URLAccessManager.h"
22 #include "StringPredicates.h"
23 #include "rc.h" // for rcfile
24 #include "GnashSystemNetHeaders.h"
27 #include <algorithm> // for find / find_if
28 #include <cstring> // for strerror
35 // Android fails to define this constant
36 #ifndef MAXHOSTNAMELEN
37 # define MAXHOSTNAMELEN 256
41 namespace URLAccessManager
{
43 /// Possible access policies for URLs
54 accessPolicyString(AccessPolicy policy
)
67 // The default AccessPolicy when prompting user is not possible
68 // (this happens when input is not a tty, at the moment)
69 //static AccessPolicy defaultAccessPolicy = GRANT;
71 /// A cache of AccessPolicy defined for URLs
72 typedef std::map
<std::string
, AccessPolicy
> AccessPolicyCache
;
74 /// A global AccessPolicyCache
75 static AccessPolicyCache policyCache
;
77 // check host against black/white lists
78 // return true if we allow load from host, false otherwise
79 // it is assumed localhost/localdomain was already checked
81 host_check_blackwhite_lists(const std::string
& host
)
86 RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
89 const std::vector
<std::string
>& whitelist
= rcfile
.getWhiteList();
90 if (!whitelist
.empty()) {
91 // TODO: case-insensitive matching ?
92 std::vector
<std::string
>::const_iterator it
=
93 std::find(whitelist
.begin(), whitelist
.end(), host
);
94 if (it
!= whitelist
.end()) {
95 log_security(_("Load from host %s granted (whitelisted)"),
100 // if there is a whitelist, anything NOT listed is denied
101 log_security(_("Load from host %s forbidden "
102 "(not in non-empty whitelist)"),
108 const std::vector
<std::string
>& blacklist
= rcfile
.getBlackList();
110 // TODO: case-insensitive matching ?
111 std::vector
<std::string
>::const_iterator it
=
112 std::find(blacklist
.begin(), blacklist
.end(), host
);
114 if (it
!= blacklist
.end()) {
115 log_security(_("Load from host %s forbidden (blacklisted)"),
120 log_security(_("Load from host %s granted (default)"), host
);
125 pathIsUnderDir(const std::string
& path
, const std::string
& dir
)
127 size_t dirLen
= dir
.length();
128 if ( dirLen
> path
.length() ) return false; // can't contain it, right ?
130 // Path must be equal to dir for the whole dir length
132 // TODO: this is pretty lame, can do better with some normalization
133 // we'd need a generic splitPathInComponents.. maybe as a static
134 // public method of gnash::URL ?
136 if ( path
.compare(0, dirLen
, dir
) ) return false;
141 /// Return true if we allow load of the local resource, false otherwise.
144 local_check(const std::string
& path
, const URL
& baseUrl
)
146 // GNASH_REPORT_FUNCTION;
148 assert( ! path
.empty() );
150 // Don't allow local access if starting movie is a network resource.
151 if (baseUrl
.protocol() != "file") {
152 log_security(_("Load of file %s forbidden"
153 " (starting URL %s is not a local resource)"),
154 path
, baseUrl
.str());
158 RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
160 typedef RcInitFile::PathList PathList
;
161 const PathList
& sandbox
= rcfile
.getLocalSandboxPath();
163 for (const std::string
& dir
: sandbox
)
165 if ( pathIsUnderDir(path
, dir
) )
167 log_security(_("Load of file %s granted (under local sandbox %s)"),
173 // TODO: dump local sandboxes here ? (or maybe send the info to the GUI properties
175 log_security(_("Load of file %s forbidden (not under local sandboxes)"),
181 /// Return true if we allow load from host, false otherwise.
183 /// This function will check for localhost/localdomain (if requested)
184 /// and finally call host_check_blackwhitelists
187 host_check(const std::string
& host
)
189 // GNASH_REPORT_FUNCTION;
191 //log_security(_("Checking security of host: %s"), host.c_str());
193 assert( ! host
.empty() );
195 RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
197 bool check_domain
= rcfile
.useLocalDomain();
198 bool check_localhost
= rcfile
.useLocalHost();
200 // Don't bother gettin hostname if we're not going to need it
201 if ( ! ( check_domain
|| check_localhost
) )
203 return host_check_blackwhite_lists(host
);
210 // #define MAXHOSTNAMELEN 200
211 char name
[MAXHOSTNAMELEN
];
212 if (::gethostname(name
, MAXHOSTNAMELEN
) == -1)
214 // FIXME: strerror is NOT thread-safe
215 log_error(_("gethostname failed: %s"), std::strerror(errno
));
216 return host_check_blackwhite_lists(host
);
218 // From GETHOSTNAME(2):
219 // In case the NUL-terminated hostname does not fit,
220 // no error is returned, but the hostname is truncated. It is unspecified
221 // whether the truncated hostname will be NUL-terminated.
222 name
[MAXHOSTNAMELEN
- 1] = '\0'; // unlikely, still worth making sure...
224 // ok, let's use std::strings... we're a C++ program after all !
225 std::string
hostname(name
); // the hostname
226 std::string domainname
; // the domainname
228 // Split hostname/domainname or take it all as an hostname if
230 std::string::size_type dotloc
= hostname
.find('.', 0);
231 if ( dotloc
!= std::string::npos
) {
232 domainname
= hostname
.substr(dotloc
+1);
233 hostname
.erase(dotloc
);
236 if ( check_domain
&& domainname
!= host
) {
237 log_security(_("Load from host %s forbidden (not in the local domain)"),
242 if ( check_localhost
&& hostname
!= host
) {
243 log_security(_("Load from host %s forbidden (not on the local host)"),
248 return host_check_blackwhite_lists(host
);
253 allowHost(const std::string
& host
)
255 if (host
.size() == 0) {
258 return host_check(host
);
262 allowXMLSocket(const std::string
& host
, short port
)
265 log_security(_("Attempt to connect to disallowed port %s"), port
);
268 return allowHost(host
);
273 allow(const URL
& url
, const URL
& baseurl
)
275 log_security(_("Checking security of URL '%s'"), url
);
277 // We might reintroduce use of an AccessPolicy cache
279 std::string host
= url
.hostname();
281 // Local resources can be accessed only if they are
282 // in a directory listed as local sandbox
283 if (host
.size() == 0)
285 if (url
.protocol() != "file")
287 log_error(_("Network connection without hostname requested"));
290 return local_check(url
.path(), baseurl
);
292 return host_check(host
);