Update with current status
[gnash.git] / libbase / URLAccessManager.cpp
bloba6c31d5d9afe2e8f5b9e15ea4a93cba978ef7f63
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
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.
9 //
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.
14 //
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"
20 #include "URL.h"
21 #include "log.h"
22 #include "StringPredicates.h"
23 #include "rc.h" // for rcfile
24 #include "GnashSystemNetHeaders.h"
26 #include <cerrno>
27 #include <algorithm> // for find / find_if
28 #include <cstring> // for strerror
29 #include <cstdio>
30 #include <map>
31 #include <string>
32 #include <vector>
33 #include <cassert>
35 // Android fails to define this constant
36 #ifndef MAXHOSTNAMELEN
37 # define MAXHOSTNAMELEN 256
38 #endif
40 namespace gnash {
41 namespace URLAccessManager {
43 /// Possible access policies for URLs
44 enum AccessPolicy {
46 /// Forbid access
47 BLOCK,
49 /// Allow access
50 GRANT
53 const char*
54 accessPolicyString(AccessPolicy policy)
56 switch(policy)
58 case BLOCK:
59 return "BLOCKED";
60 case GRANT:
61 return "GRANTED";
62 default:
63 return "UNKNOWN";
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
80 static bool
81 host_check_blackwhite_lists(const std::string& host)
83 using std::vector;
84 using std::string;
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)"),
96 host);
97 return true;
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)"),
103 host);
105 return false;
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)"),
116 host);
117 return false;
120 log_security(_("Load from host %s granted (default)"), host);
121 return true;
124 static bool
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;
138 return true;
141 /// Return true if we allow load of the local resource, false otherwise.
143 static bool
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());
155 return false;
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)"),
168 path, dir);
169 return true;
173 // TODO: dump local sandboxes here ? (or maybe send the info to the GUI properties
174 // view
175 log_security(_("Load of file %s forbidden (not under local sandboxes)"),
176 path);
177 return false;
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
185 ///
186 static bool
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);
207 // Get hostname
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
229 // no dot is found
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)"),
238 host);
239 return false;
242 if ( check_localhost && hostname != host ) {
243 log_security(_("Load from host %s forbidden (not on the local host)"),
244 host);
245 return false;
248 return host_check_blackwhite_lists(host);
252 bool
253 allowHost(const std::string& host)
255 if (host.size() == 0) {
256 return true;
258 return host_check(host);
261 bool
262 allowXMLSocket(const std::string& host, short port)
264 if (port < 1024) {
265 log_security(_("Attempt to connect to disallowed port %s"), port);
266 return false;
268 return allowHost(host);
272 bool
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"));
288 return false;
290 return local_check(url.path(), baseurl);
292 return host_check(host);
296 } // AccessManager
297 } // namespace gnash