/** * \brief Checks URL policy files to see if the player is allowed access to the given UR * * Waits for mutex at start and releases mutex when finished * \param url The URL to evaluate * \param loadPendingPolicies Whether to load (and thus check) pending policies before evaluating * \return \c ALLOWED if allowed or otherwise \c NA_CROSSDOMAIN_POLICY */ SecurityManager::EVALUATIONRESULT SecurityManager::evaluatePoliciesURL(const URLInfo& url, bool loadPendingPolicies) { //This check doesn't apply to local files if(url.getProtocol() == "file" && sys->getOrigin().getProtocol() == "file") return ALLOWED; LOG(LOG_NO_INFO, _("SECURITY: Evaluating URL for cross domain policies:")); LOG(LOG_NO_INFO, _("SECURITY: --> URL: ") << url); LOG(LOG_NO_INFO, _("SECURITY: --> Origin: ") << sys->getOrigin()); //The URL has exactly the same domain name as the origin, always allowed if(url.getProtocol() == sys->getOrigin().getProtocol() && url.getHostname() == sys->getOrigin().getHostname()) { LOG(LOG_NO_INFO, _("SECURITY: Same hostname as origin, allowing")); return ALLOWED; } //Search for the policy files to check URLPFileList* files = searchURLPolicyFiles(url, loadPendingPolicies); sem_wait(&mutex); //-- Lock acquired //Check the policy files if(files != NULL) { URLPFileListConstIt it = files->begin(); for(; it != files->end(); ++it) { if((*it)->allowsAccessFrom(sys->getOrigin(), url)) { LOG(LOG_NO_INFO, _("SECURITY: ALLOWED: A policy file explicitly allowed access")); delete files; //++ Release lock sem_post(&mutex); return ALLOWED; } } } LOG(LOG_NO_INFO, _("SECURITY: DISALLOWED: No policy file explicitly allowed access")); delete files; //++ Release lock sem_post(&mutex); return NA_CROSSDOMAIN_POLICY; }
/** * \brief Checks URL policy files to see if the player is allowed access to the given UR * * Waits for mutex at start and releases mutex when finished * \param url The URL to evaluate * \param loadPendingPolicies Whether to load (and thus check) pending policies before evaluating * \return \c ALLOWED if allowed or otherwise \c NA_CROSSDOMAIN_POLICY */ SecurityManager::EVALUATIONRESULT SecurityManager::evaluatePoliciesURL(const URLInfo& url, bool loadPendingPolicies) { //This check doesn't apply to local files if(url.getProtocol() == "file" && getSys()->getOrigin().getProtocol() == "file") return ALLOWED; //Streaming from RTMP is always allowed (see //http://forums.adobe.com/thread/422391) if(url.isRTMP()) return ALLOWED; LOG(LOG_INFO, _("SECURITY: Evaluating URL for cross domain policies:")); LOG(LOG_INFO, _("SECURITY: --> URL: ") << url); LOG(LOG_INFO, _("SECURITY: --> Origin: ") << getSys()->getOrigin()); //The URL has exactly the same domain name as the origin, always allowed if(url.getProtocol() == getSys()->getOrigin().getProtocol() && url.getHostname() == getSys()->getOrigin().getHostname()) { LOG(LOG_INFO, _("SECURITY: Same hostname as origin, allowing")); return ALLOWED; } //Search for the policy files to check URLPFileList* files = searchURLPolicyFiles(url, loadPendingPolicies); RecMutex::Lock l(mutex); //Check the policy files if(files != NULL) { URLPFileListConstIt it = files->begin(); for(; it != files->end(); ++it) { if((*it)->allowsAccessFrom(getSys()->getOrigin(), url)) { LOG(LOG_INFO, _("SECURITY: ALLOWED: A policy file explicitly allowed access")); delete files; return ALLOWED; } } } LOG(LOG_INFO, _("SECURITY: DISALLOWED: No policy file explicitly allowed access")); delete files; return NA_CROSSDOMAIN_POLICY; }
/** * \brief Checks URL policy files to see if the player is allowed to send a given request header * as part of a request for the given URL * * Waits for mutex at start and releases mutex when finished * \param url The URL of the request to which the request header belongs * \param header The request header to evaluate * \param loadPendingPolicies Whether or not to load (and thus check) pending policy files * \return \c ALLOWED if allowed or otherwise \c NA_HEADER */ SecurityManager::EVALUATIONRESULT SecurityManager::evaluateHeader(const URLInfo& url, const tiny_string& header, bool loadPendingPolicies) { //This check doesn't apply to local files if(url.getProtocol() == "file" && getSys()->getOrigin().getProtocol() == "file") return ALLOWED; LOG(LOG_INFO, _("SECURITY: Evaluating header for cross domain policies ('") << header << "'):"); LOG(LOG_INFO, _("SECURITY: --> URL: ") << url); LOG(LOG_INFO, _("SECURITY: --> Origin: ") << getSys()->getOrigin()); string headerStrLower(header.raw_buf()); transform(headerStrLower.begin(), headerStrLower.end(), headerStrLower.begin(), ::tolower); string headerStr = headerStrLower; if(headerStr.find("_") != string::npos) headerStr.replace(headerStr.find("_"), 1, "-"); //Disallowed headers, in any case if(headerStr == "accept-charset" && headerStr == "accept-encoding" && headerStr == "accept-ranges" && headerStr == "age" && headerStr == "allow" && headerStr == "allowed" && headerStr == "authorization" && headerStr == "charge-to" && headerStr == "connect" && headerStr == "connection" && headerStr == "content-length" && headerStr == "content-location" && headerStr == "content-range" && headerStr == "cookie" && headerStr == "date" && headerStr == "delete" && headerStr == "etag" && headerStr == "expect" && headerStr == "get" && headerStr == "head" && headerStr == "host" && headerStr == "if-modified-since" && headerStr == "keep-alive" && headerStr == "last-modified" && headerStr == "location" && headerStr == "max-forwards" && headerStr == "options" && headerStr == "origin" && headerStr == "post" && headerStr == "proxy-authenticate" && headerStr == "proxy-authorization" && headerStr == "proxy-connection" && headerStr == "public" && headerStr == "put" && headerStr == "range" && headerStr == "referer" && headerStr == "request-range" && headerStr == "retry-after" && headerStr == "server" && headerStr == "te" && headerStr == "trace" && headerStr == "trailer" && headerStr == "transfer-encoding" && headerStr == "upgrade" && headerStr == "uri" && headerStr == "user-agent" && headerStr == "vary" && headerStr == "via" && headerStr == "warning" && headerStr == "www-authenticate" && headerStr == "x-flash-version") { LOG(LOG_INFO, _("SECURITY: DISALLOWED: Header is restricted")); return NA_HEADER; } //The URL has exactly the same domain name as the origin, always allowed if(url.getProtocol() == getSys()->getOrigin().getProtocol() && url.getHostname() == getSys()->getOrigin().getHostname()) { LOG(LOG_INFO, _("SECURITY: ALLOWED: Same hostname as origin")); return ALLOWED; } //Search for the policy files to check URLPFileList* files = searchURLPolicyFiles(url, loadPendingPolicies); RecMutex::Lock l(mutex); //Check the policy files if(files != NULL) { URLPFileListConstIt it = files->begin(); for(; it != files->end(); ++it) { if((*it)->allowsHTTPRequestHeaderFrom(getSys()->getOrigin(), url, headerStrLower)) { LOG(LOG_INFO, _("SECURITY: ALLOWED: A policy file explicitly allowed the header")); delete files; return ALLOWED; } } } LOG(LOG_INFO, _("SECURITY: DISALLOWED: No policy file explicitly allowed the header")); delete files; return NA_CROSSDOMAIN_POLICY; }
/** * \brief Search for URL policy files relevant to a given URL * * Searches the loaded URL policy file list for URL policy files that are relevant to a given URL. * If \c loadPendingPolicies is true, it search the pending URL policy files list next, * loading every relative policy file. * Waits for mutex at start and releases mutex when finished * \param url The URL that will be evaluated using the relevant policy files. * \param loadPendingPolicies Whether or not to load (and thus check) pending URL policy files. * \return An pointer to a newly created URLPFileList containing the relevant policy files. * This list needs to be deleted after use. */ URLPFileList* SecurityManager::searchURLPolicyFiles(const URLInfo& url, bool loadPendingPolicies) { URLPFileList* result = new URLPFileList; //Get or create the master policy file object URLInfo masterURL = url.goToURL("/crossdomain.xml"); URLPolicyFile* master = getURLPolicyFileByURL(masterURL); if(master == NULL) master = addURLPolicyFile(masterURL); if(loadPendingPolicies) getSys()->securityManager->loadPolicyFile(master); RecMutex::Lock l(mutex); //Check if the master policy file is loaded. //If another user-added relevant policy file is already loaded, //it's master will have already been loaded too (to check if it is allowed). //So IF any relevant policy file is loaded already, then the master will be too. if(master->isLoaded() && master->isValid()) { LOG(LOG_INFO, _("SECURITY: Master policy file is loaded and valid (") << url << ")"); PolicySiteControl::METAPOLICY siteControl = master->getSiteControl()->getPermittedPolicies(); //Master defines no policy files are allowed at all if(siteControl == PolicySiteControl::NONE) { LOG(LOG_INFO, _("SECURITY: DISALLOWED: Master policy file disallows policy files")); return NULL; } result->push_back(master); //Non-master policy files are allowed if(siteControl != PolicySiteControl::MASTER_ONLY) { LOG(LOG_INFO, _("SECURITY: Searching for loaded non-master policy files (") << loadedURLPFiles.count(url.getHostname()) << ")"); URLPFileMapConstItPair range = loadedURLPFiles.equal_range(url.getHostname()); URLPFileMapConstIt i = range.first; for(;i != range.second; ++i) { if((*i).second == master) continue; result->push_back((*i).second); } //And check the pending policy files next (if we are allowed to) if(loadPendingPolicies) { LOG(LOG_INFO, _("SECURITY: Searching for and loading pending non-master policy files (") << pendingURLPFiles.count(url.getHostname()) << ")"); while(true) { i=pendingURLPFiles.find(url.getHostname()); if(i==pendingURLPFiles.end()) break; result->push_back((*i).second); l.release(); getSys()->securityManager->loadPolicyFile((*i).second); //NOTE: loadPolicyFile() will change pendingURLPFiles, //erasing & moving to loadURLPFiles. Therefore, the //iterator i is now invalid. l.acquire(); } } } } return result; }