Fix test for bug #32625
[gnash.git] / libbase / URLAccessManager.cpp
blobda258efb9f95f4de68b18118e8c6b5366ab9e027
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // 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 namespace gnash {
36 namespace URLAccessManager {
38 /// Possible access policies for URLs
39 enum AccessPolicy {
41 /// Forbid access
42 BLOCK,
44 /// Allow access
45 GRANT
48 const char*
49 accessPolicyString(AccessPolicy policy)
51 switch(policy)
53 case BLOCK:
54 return "BLOCKED";
55 case GRANT:
56 return "GRANTED";
57 default:
58 return "UNKNOWN";
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
75 static bool
76 host_check_blackwhite_lists(const std::string& host)
78 using std::vector;
79 using std::string;
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)"),
91 host);
92 return true;
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)"),
98 host);
100 return false;
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)"),
111 host);
112 return false;
115 log_security(_("Load from host %s granted (default)"), host);
116 return true;
119 static bool
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;
133 return true;
136 /// Return true if we allow load of the local resource, false otherwise.
138 static bool
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());
150 return false;
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();
159 i!=e; ++i)
161 const std::string& dir = *i;
162 if ( pathIsUnderDir(path, dir) )
164 log_security(_("Load of file %s granted (under local sandbox %s)"),
165 path, dir);
166 return true;
170 // TODO: dump local sandboxes here ? (or maybe send the info to the GUI properties
171 // view
172 log_security(_("Load of file %s forbidden (not under local sandboxes)"),
173 path);
174 return false;
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
182 ///
183 static bool
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);
204 // Get hostname
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
226 // no dot is found
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)"),
235 host);
236 return false;
239 if ( check_localhost && hostname != host ) {
240 log_security(_("Load from host %s forbidden (not on the local host)"),
241 host);
242 return false;
245 return host_check_blackwhite_lists(host);
249 bool
250 allowHost(const std::string& host)
252 if (host.size() == 0) {
253 return true;
255 return host_check(host);
258 bool
259 allowXMLSocket(const std::string& host, short port)
261 if (port < 1024) {
262 log_security("Attempt to connect to disallowed port %s", port);
263 return false;
265 return allowHost(host);
269 bool
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"));
285 return false;
287 return local_check(url.path(), baseurl);
289 return host_check(host);
293 } // AccessManager
294 } // namespace gnash