/** * \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 if the entry allows access from the given URL * * \param url The URL to check this entry against * \return \c true if this entry allows the given URL access, otherwise \c false */ bool PolicyAllowAccessFrom::allowsAccessFrom(const URLInfo& url) const { //TODO: resolve domain names using DNS before checking for a match? //See section 1.5.9 in specification //TODO: add check for to-ports and secure for SOCKET type policy files //Check if domains match if(!URLInfo::matchesDomain(domain, url.getHostname())) return false; //Check if the requesting URL is secure, if needed if(file->getType() == PolicyFile::URL && dynamic_cast<URLPolicyFile*>(file)->getSubtype() == URLPolicyFile::HTTPS && secure && url.getProtocol() != "https") return false; return true; }
/** * \brief Checks if the entry allows a given request header from a given URL * * \param url The URL to check this entry against * \param header The header to check this entry against * \return \c true if this entry allows the given URL to send the given request header, otherwise \c false */ bool PolicyAllowHTTPRequestHeadersFrom::allowsHTTPRequestHeaderFrom(const URLInfo& url, const string& header) const { if(file->getSubtype() != URLPolicyFile::HTTP && file->getSubtype() != URLPolicyFile::HTTPS) return false; //Check if domains match if(!URLInfo::matchesDomain(domain, url.getHostname())) return false; //Check if the requesting URL is secure, if needed if(file->getSubtype() == URLPolicyFile::HTTPS && secure && url.getProtocol() != "https") return false; //Check if the header is explicitly allowed bool headerFound = false; string expression; for(list<string*>::const_iterator i = headers.begin(); i != headers.end(); ++i) { expression = (**i); transform(expression.begin(), expression.end(), expression.begin(), ::tolower); if(expression == header || expression == "*") { headerFound = true; break; } //Match suffix wildcards else if(expression[expression.length()-1] == '*' && header.substr(0, expression.length()-1) == expression.substr(0, expression.length()-1)) { headerFound = true; break; } } if(!headerFound) return false; return true; }
/** * \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; }