Exemplo n.º 1
0
/*!
	@brief Retrieves a work unit from the controller.
	
	@param wu Object to store the work unit in
	@param alglist List of algorithms supported
	
	@return True if a work unit was successfully retrieved, false if no work is available
 */
bool ControllerLink::GetWorkUnit(WorkUnit& wu, const vector<string>& alglist)
{
	//Initialize default values
	wu.m_bCracked.clear();
	wu.m_hashvalues.clear();
	wu.m_hashids.clear();
	wu.m_collisions.clear();
	
	//Generate algorithm list
	string algs = "";
	for(unsigned int i=0; i<alglist.size(); i++)
	{
		if(i != 0)
			algs += ",";
		algs += alglist[i];
	}
	
	//Format our request
	string request = g_server + "agents/getwu?version=3.2&hostname=" + g_hostname + "&type=" + m_type + "&num=" + m_num + "&accept-algorithms=" + algs;
		
	//Send to the server
	string recvdata;
	curl_easy_reset(m_pCurl);
	curl_easy_setopt(m_pCurl, CURLOPT_NOPROGRESS, 1);
	curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, curlwritecallback);
	curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &recvdata);
	curl_easy_setopt(m_pCurl, CURLOPT_URL, request.c_str());
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, 0);		//TODO: control this by command line arg
	if(0 != curl_easy_perform(m_pCurl))
		ThrowError("libcurl error");
		
	//Parse XML
	XmlParser* parser = NULL;
	try
	{
		parser = new XmlParser(recvdata);
	}
	catch(std::string err)
	{
		cerr << "Failed to parse work unit! Expected well formed XML, got:" << endl;
		string str = recvdata.substr(0, 256);
		cerr << str.c_str() << endl;
		return false;
	}
	
	//Process it
	const XmlNode* pRoot = parser->GetRoot();
	if(pRoot == NULL)
	{
		cerr << "Failed to parse work (no root node):" << endl;
		string str = recvdata.substr(0, 256);
		cerr << str.c_str() << endl;
		return false;
	}
	if(pRoot->GetType() == "workunit")
	{
		//Work unit, process it
		//TODO: Add more sanity checking (e.g. can only have one of each tag other than <hash> per work unit)
		for(unsigned int i=0; i<pRoot->GetChildCount(); i++)
		{
			//Skip the node if it's not a tag
			const XmlNode* pNode = pRoot->GetChildNode(i);
			if(pNode->GetNodeType() != XmlNode::NODETYPE_TAG)
				continue;
				
			//Must have one and only one child
			if(pNode->GetChildCount() != 1)
				continue;
				
			//Get the item
			string type = pNode->GetType();
			
			//Get the child and validate it
			const XmlNode* pData = pNode->GetChildNode(0);
			if(pData->GetNodeType() != XmlNode::NODETYPE_TEXT)
				continue;
				
			//Get the value
			string txt = pData->GetBody();
			
			//Process it
			if(type == "id")
				wu.m_id = txt;
			else if(type == "algorithm")
				wu.m_algorithm = txt;
			else if(type == "charset")
			{
				//Decode the character set
				wu.m_charset = "";
				for(unsigned int j=0; j<txt.length(); j++)
				{
					char code = txt[j];
					switch(code)
					{
					case 'a':
						wu.m_charset += "abcdefghijklmnopqrstuvwxyz";
						break;
					case 'A':
						wu.m_charset += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
						break;
					case '1':
						wu.m_charset += "1234567890";
						break;
					case '!':
						wu.m_charset += "!@_-?#$";
						break;
					case '>':
						wu.m_charset += "`~%^&*()=+[]\\{}|;':\",./<>";
						break;
					case 's':
						wu.m_charset += ' ';
						break;
					case 'n':
						wu.m_charset += '\n';
						break;
					default:
						string err = "Unrecognized charset abbreviation in work unit: ";
						err += code;
						ThrowCustomError(err.c_str());
					}
				}
			}
			else if(type == "hash")
			{			
				//Save hash ID
				for(unsigned int i=0; i<pNode->GetAttributeCount(); i++)
				{
					if(pNode->GetAttributeName(i) == "id")
					{
						unsigned int id;
						sscanf(pNode->GetAttributeValue(i).c_str(), "%u", &id);
						wu.m_hashids.push_back(id);
						wu.m_collisions.push_back("");
					}
				}

				//Decode (algorithm must come first)
				//TODO: Verify this is indeed the case
				unsigned char* salt = new unsigned char[16];
				unsigned char* hash = new unsigned char[256];
				DecodeHash(wu.m_algorithm, txt, wu.m_hashlen, hash, salt);
				wu.m_hashvalues.push_back(hash);
				wu.m_salts.push_back(salt);
				wu.m_bCracked.push_back(false);
			}
			else if(type == "start")
			{
				wu.m_start = txt;
				if(txt.length() >= MAX_BASEN_LENGTH - 1)
				{
					string err = "Start guess too long: ";
					err += txt;
					ThrowError(err.c_str());
				}
			}
			else if(type == "end")
			{
				wu.m_end = txt;
				if(txt.length() >= MAX_BASEN_LENGTH - 1)
					ThrowError("End guess too long");
			}
			else
				ThrowCustomError("Unknown tag type in work unit");
		}		
		delete parser;
		return true;
	}
	else if(pRoot->GetType() == "nowork")
	{
		//Look up attributes, see if they have a reason
		for(unsigned int i=0; i<pRoot->GetAttributeCount(); i++)
		{
			if(pRoot->GetAttributeName(i) == "reason")
			{
				string s = pRoot->GetAttributeValue(i);
				if(s == "idle")
				{
					//No action needed
				}
				else if(s == "version")
				{
					cerr << "Warning: no work available because controller is running a different protocol version" << endl;
				}
				break;
			}
		}
				
		delete parser;
		return false;
	}
	else
	{
		cerr << "Warning: Invalid work unit (expected <nowork> or <workunit>, found <" << pRoot->GetType().c_str() << ">)" << endl;
		cerr << "Original message: " << recvdata;
		return false;
	}
}