Exemple #1
0
/**
 * \brief Add an URL policy file at the given URL
 *
 * Adds an URL policy file at the given URL to the list of managed URL policy files.
 * Policy files aren't loaded when adding, this is delayed until the policy file is actually needed.
 * Waits for mutex at start and releases mutex when finished
 * \param url The URL where the URL policy file resides
 * \return A pointer to the newly created URLPolicyFile object
 */
URLPolicyFile* SecurityManager::addURLPolicyFile(const URLInfo& url)
{
	RecMutex::Lock l(mutex);

	URLPolicyFile* file = new URLPolicyFile(url);
	if(file->isValid())
	{
		LOG(LOG_INFO, 
				_("SECURITY: Added URL policy file is valid, adding to URL policy file list (") << url << ")");
		pendingURLPFiles.insert(URLPFilePair(url.getHostname(), file));
	}

	return file;
}
Exemple #2
0
/**
 * \brief Add an URL policy file at the given URL
 *
 * Adds an URL policy file at the given URL to the list of managed URL policy files.
 * Policy files aren't loaded when adding, this is delayed until the policy file is actually needed.
 * Waits for mutex at start and releases mutex when finished
 * \param url The URL where the URL policy file resides
 * \return A pointer to the newly created URLPolicyFile object
 */
URLPolicyFile* SecurityManager::addURLPolicyFile(const URLInfo& url)
{
	sem_wait(&mutex);
	//-- Lock acquired
	
	URLPolicyFile* file = new URLPolicyFile(url);
	if(file->isValid())
	{
		LOG(LOG_NO_INFO, 
				_("SECURITY: Added URL policy file is valid, adding to URL policy file list (") << url << ")");
		pendingURLPFiles.insert(URLPFilePair(url.getHostname(), file));
	}
	
	//++ Release lock
	sem_post(&mutex);
	return file;
}
Exemple #3
0
/**
 * \brief Loads and parses an URLPolicy file
 *
 * Can only be called from within SecurityManager
 * Waits for mutex at start and releases mutex when finished
 * \see SecurityManager::loadURLPolicyFile()
 */
void URLPolicyFile::load()
{
	//TODO: support download timeout handling
	
	//Invalid URLPolicyFile or already loaded, ignore this call
	if(!isValid() || isLoaded())
		return;
	//We only try loading once, if something goes wrong, valid will be set to 'invalid'
	loaded = true;

	URLPolicyFile* master = getMasterPolicyFile();

	Mutex::Lock l(mutex);
	//Check if this file is allowed/ignored by the master policy file
	if(!isMaster())
	{
		//Load master policy file if not loaded yet
		getSys()->securityManager->loadPolicyFile(master);
		//Master policy file found and valid and has a site-control entry
		if(master->isValid() && master->getSiteControl() != NULL)
		{
			PolicySiteControl::METAPOLICY permittedPolicies = master->getSiteControl()->getPermittedPolicies();
			//For all types: master-only, none
			if(permittedPolicies == PolicySiteControl::MASTER_ONLY ||	permittedPolicies == PolicySiteControl::NONE)
				ignore = true;
			//Only for FTP: by-ftp-filename
			else if(subtype == FTP && permittedPolicies == PolicySiteControl::BY_FTP_FILENAME && 
					url.getPathFile() != "crossdomain.xml")
				ignore = true;
		}
	}

	//No caching needed for this download, we don't expect very big files
	Downloader* downloader=getSys()->downloadManager->download(url, false, NULL);

	//Wait until the file is fetched
	downloader->waitForTermination();
	if(downloader->hasFailed())
		valid = false;

	//If files are redirected, we use the new URL as the file's URL
	if(isValid() && downloader->isRedirected())
	{
		URLInfo newURL(downloader->getURL());
		if(url.getHostname() != newURL.getHostname())
		{
			LOG(LOG_INFO, _("SECURITY: Policy file was redirected to other domain, marking invalid"));
			valid = false;
		}
		url = newURL;
		LOG(LOG_INFO, _("SECURITY: Policy file was redirected"));
	}

	//Policy files must have on of the following content-types to be valid:
	//text/*, application/xml or application/xhtml+xml
	tiny_string contentType = downloader->getHeader("content-type");
	if(isValid() && (subtype == HTTP || subtype == HTTPS) && 
			contentType.substr(0, 5) != "text/" &&
			contentType != "application/xml" &&
			contentType != "application/xhtml+xml")
	{
		LOG(LOG_INFO, _("SECURITY: Policy file has an invalid content-type, marking invalid"));
		valid = false;
	}

	//One more check from the master file: see if the content-type is OK 
	//if site-control specifies by-content-type
	if(isValid() && !isMaster())
	{
		//If the site-control policy of the master policy file is by-content-type, only policy files with
		//content-type = text/x-cross-domain-policy are allowed.
		if(master->isValid() && master->getSiteControl() != NULL &&
				(subtype == HTTP || subtype == HTTPS) &&
				master->getSiteControl()->getPermittedPolicies() == PolicySiteControl::BY_CONTENT_TYPE &&
				contentType != "text/x-cross-domain-policy")
		{
			LOG(LOG_INFO, _("SECURITY: Policy file content-type isn't strict, marking invalid"));
			ignore = true;
		}
	}

	//We've checked the master file to see of we need to ignore this file. (not the case)
	//Now let's parse this file. A HTTP 404 results in a failed download.
	if(isValid() && !isIgnored())
	{
		istream s(downloader);
		size_t bufLength = downloader->getLength();
		uint8_t* buf=new uint8_t[bufLength];
		//TODO: avoid this useless copy
		s.read((char*)buf,bufLength);

		//We're done with the downloader, lets destroy ASAP
		getSys()->downloadManager->destroy(downloader);

		CrossDomainPolicy::POLICYFILESUBTYPE parserSubtype = CrossDomainPolicy::NONE;
		if(subtype == HTTP)
			parserSubtype = CrossDomainPolicy::HTTP;
		else if(subtype == HTTPS)
			parserSubtype = CrossDomainPolicy::HTTPS;
		else if(subtype == FTP)
			parserSubtype = CrossDomainPolicy::FTP;
		CrossDomainPolicy parser(buf, bufLength, CrossDomainPolicy::URL, parserSubtype, isMaster());
		CrossDomainPolicy::ELEMENT elementType = parser.getNextElement();

		while(elementType != CrossDomainPolicy::END && elementType != CrossDomainPolicy::INVALID)
		{
			if(elementType == CrossDomainPolicy::SITE_CONTROL)
			{
				siteControl = new PolicySiteControl(this, parser.getPermittedPolicies());
				//No more parsing is needed if this site-control entry specifies that
				//no policy files are allowed
				if(isMaster() &&
						siteControl->getPermittedPolicies() == PolicySiteControl::NONE)
					break;
			}
			else if(elementType == CrossDomainPolicy::ALLOW_ACCESS_FROM)
				//URL policy files don't use to-ports
				allowAccessFrom.push_back(new PolicyAllowAccessFrom(this, 
							parser.getDomain(), "", parser.getSecure(), parser.getSecureSpecified()));
			else if(elementType == CrossDomainPolicy::ALLOW_HTTP_REQUEST_HEADERS_FROM)
				allowHTTPRequestHeadersFrom.push_back(new PolicyAllowHTTPRequestHeadersFrom(this, 
							parser.getDomain(), parser.getHeaders(),
							parser.getSecure(), parser.getSecureSpecified()));

			elementType = parser.getNextElement();
		}

		delete[] buf;

		//The last element was INVALID
		if(elementType == CrossDomainPolicy::INVALID)
			valid = false;

		if(isMaster())
		{
			//Set siteControl to the default value if it isn't set before and we are a master file
			if(siteControl == NULL)
				siteControl = new PolicySiteControl(this, "");

			//Ignore this file if the site control policy is "none"
			if(siteControl->getPermittedPolicies() == PolicySiteControl::NONE)
				ignore = true;
			//by-ftp-filename only applies to FTP
			if((subtype == HTTP || subtype == HTTPS) && 
					siteControl->getPermittedPolicies() == PolicySiteControl::BY_FTP_FILENAME)
				valid = false;
			//by-content-type only applies to HTTP(S)
			else if(subtype == FTP && 
					siteControl->getPermittedPolicies() == PolicySiteControl::BY_CONTENT_TYPE)
				valid = false;
		}
	}
	else
	{
		//Failed to download the file, marking this file as invalid
		valid = false;
		getSys()->downloadManager->destroy(downloader);
	}
}
Exemple #4
0
/**
 * \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;
}