2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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
36 namespace URLAccessManager
{
38 /// Possible access policies for URLs
49 accessPolicyString(AccessPolicy policy
)
62 // The default AccessPolicy when prompting user is not possible
63 // (this happens when input is not a tty, at the moment)
64 //static AccessPolicy defaultAccessPolicy = GRANT;
66 /// A cache of AccessPolicy defined for URLs
67 typedef std::map
<std::string
, AccessPolicy
> AccessPolicyCache
;
69 /// A global AccessPolicyCache
70 static AccessPolicyCache policyCache
;
72 // check host against black/white lists
73 // return true if we allow load from host, false otherwise
74 // it is assumed localhost/localdomain was already checked
76 host_check_blackwhite_lists(const std::string
& host
)
81 RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
84 const std::vector
<std::string
>& whitelist
= rcfile
.getWhiteList();
85 if (!whitelist
.empty()) {
86 // TODO: case-insensitive matching ?
87 std::vector
<std::string
>::const_iterator it
=
88 std::find(whitelist
.begin(), whitelist
.end(), host
);
89 if (it
!= whitelist
.end()) {
90 log_security(_("Load from host %s granted (whitelisted)"),
95 // if there is a whitelist, anything NOT listed is denied
96 log_security(_("Load from host %s forbidden "
97 "(not in non-empty whitelist)"),
103 const std::vector
<std::string
>& blacklist
= rcfile
.getBlackList();
105 // TODO: case-insensitive matching ?
106 std::vector
<std::string
>::const_iterator it
=
107 std::find(blacklist
.begin(), blacklist
.end(), host
);
109 if (it
!= blacklist
.end()) {
110 log_security(_("Load from host %s forbidden (blacklisted)"),
115 log_security(_("Load from host %s granted (default)"), host
);
120 pathIsUnderDir(const std::string
& path
, const std::string
& dir
)
122 size_t dirLen
= dir
.length();
123 if ( dirLen
> path
.length() ) return false; // can't contain it, right ?
125 // Path must be equal to dir for the whole dir length
127 // TODO: this is pretty lame, can do better with some normalization
128 // we'd need a generic splitPathInComponents.. maybe as a static
129 // public method of gnash::URL ?
131 if ( path
.compare(0, dirLen
, dir
) ) return false;
136 /// Return true if we allow load of the local resource, false otherwise.
139 local_check(const std::string
& path
, const URL
& baseUrl
)
141 // GNASH_REPORT_FUNCTION;
143 assert( ! path
.empty() );
145 // Don't allow local access if starting movie is a network resource.
146 if (baseUrl
.protocol() != "file") {
147 log_security(_("Load of file %s forbidden"
148 " (starting url %s is not a local resource)"),
149 path
, baseUrl
.str());
153 RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
155 typedef RcInitFile::PathList PathList
;
156 const PathList
& sandbox
= rcfile
.getLocalSandboxPath();
158 for (PathList::const_iterator i
=sandbox
.begin(), e
=sandbox
.end();
161 const std::string
& dir
= *i
;
162 if ( pathIsUnderDir(path
, dir
) )
164 log_security(_("Load of file %s granted (under local sandbox %s)"),
170 // TODO: dump local sandboxes here ? (or maybe send the info to the GUI properties
172 log_security(_("Load of file %s forbidden (not under local sandboxes)"),
178 /// Return true if we allow load from host, false otherwise.
180 /// This function will check for localhost/localdomain (if requested)
181 /// and finally call host_check_blackwhitelists
184 host_check(const std::string
& host
)
186 // GNASH_REPORT_FUNCTION;
188 //log_security("Checking security of host: %s", host.c_str());
190 assert( ! host
.empty() );
192 RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
194 bool check_domain
= rcfile
.useLocalDomain();
195 bool check_localhost
= rcfile
.useLocalHost();
197 // Don't bother gettin hostname if we're not going to need it
198 if ( ! ( check_domain
|| check_localhost
) )
200 return host_check_blackwhite_lists(host
);
207 #define MAXHOSTNAMELEN 200
208 char name
[MAXHOSTNAMELEN
];
209 if (::gethostname(name
, MAXHOSTNAMELEN
) == -1)
211 // FIXME: strerror is NOT thread-safe
212 log_error(_("gethostname failed: %s"), std::strerror(errno
));
213 return host_check_blackwhite_lists(host
);
215 // From GETHOSTNAME(2):
216 // In case the NUL-terminated hostname does not fit,
217 // no error is returned, but the hostname is truncated. It is unspecified
218 // whether the truncated hostname will be NUL-terminated.
219 name
[MAXHOSTNAMELEN
- 1] = '\0'; // unlikely, still worth making sure...
221 // ok, let's use std::strings... we're a C++ program after all !
222 std::string
hostname(name
); // the hostname
223 std::string domainname
; // the domainname
225 // Split hostname/domainname or take it all as an hostname if
227 std::string::size_type dotloc
= hostname
.find('.', 0);
228 if ( dotloc
!= std::string::npos
) {
229 domainname
= hostname
.substr(dotloc
+1);
230 hostname
.erase(dotloc
);
233 if ( check_domain
&& domainname
!= host
) {
234 log_security(_("Load from host %s forbidden (not in the local domain)"),
239 if ( check_localhost
&& hostname
!= host
) {
240 log_security(_("Load from host %s forbidden (not on the local host)"),
245 return host_check_blackwhite_lists(host
);
250 allowHost(const std::string
& host
)
252 if (host
.size() == 0) {
255 return host_check(host
);
259 allowXMLSocket(const std::string
& host
, short port
)
262 log_security("Attempt to connect to disallowed port %s", port
);
265 return allowHost(host
);
270 allow(const URL
& url
, const URL
& baseurl
)
272 log_security(_("Checking security of URL '%s'"), url
);
274 // We might reintroduce use of an AccessPolicy cache
276 std::string host
= url
.hostname();
278 // Local resources can be accessed only if they are
279 // in a directory listed as local sandbox
280 if (host
.size() == 0)
282 if (url
.protocol() != "file")
284 log_error(_("Network connection without hostname requested"));
287 return local_check(url
.path(), baseurl
);
289 return host_check(host
);