Exemple #1
0
bool CUserInfoSession::OnStartSession (const SArchonMessage &Msg, DWORD dwTicket)

//	OnStartSession
//
//	Start

	{
	//	Send an Aeon message to get the user record

	CComplexArray *pPayload = new CComplexArray;
	pPayload->Insert(USERS_TABLE_NAME);
	pPayload->Insert(m_sUsernameKey);

	//	Send message

	ISessionHandler::SendMessageCommand(ADDRESS_AEON_COMMAND,
			MSG_AEON_GET_VALUE,
			GenerateAddress(PORT_CRYPTOSAUR_COMMAND),
			CDatum(pPayload),
			MESSAGE_TIMEOUT);

	//	Expect reply

	return true;
	}
Exemple #2
0
void CEsperEngine::SendMessageReplyOnWrite (CDatum dConnection, DWORD dwBytesTransferred, const SArchonMessage &OriginalMsg)

//	SendMessageReplyOnWrite
//
//	Reply with Esper.onWrite

	{
	CComplexArray *pPayload = new CComplexArray;
	pPayload->Insert(dwBytesTransferred);
	pPayload->Insert(dConnection);

	m_pProcess->SendMessageReply(MSG_ESPER_ON_WRITE, CDatum(pPayload), OriginalMsg);
	}
Exemple #3
0
bool CDatum::CreateFromAttributeList (const CAttributeList &Attribs, CDatum *retdDatum)

//	CreateFromAttributeList
//
//	Creates a datum from an attribute list

	{
	int i;

	TArray<CString> AllAttribs;
	Attribs.GetAll(&AllAttribs);

	if (AllAttribs.GetCount() == 0)
		{
		*retdDatum = CDatum();
		return true;
		}

	CComplexArray *pArray = new CComplexArray;
	for (i = 0; i < AllAttribs.GetCount(); i++)
		pArray->Insert(AllAttribs[i]);

	*retdDatum = CDatum(pArray);
	return true;
	}
Exemple #4
0
void CAeonEngine::MsgGetTables (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx)

//	MsgGetTables
//
//	Aeon.getTables

	{
	int i;

	if (!m_bReady)
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_NOT_READY, Msg);
		return;
		}

	//	Get a list of all tables

	TArray<CAeonTable *> AllTables;
	GetTables(&AllTables);

	//	Return an array of table descriptors

	CComplexArray *pArray = new CComplexArray;
	for (i = 0; i < AllTables.GetCount(); i++)
		{
		if (pSecurityCtx && !pSecurityCtx->IsNamespaceAccessible(AllTables[i]->GetName()))
			continue;

		pArray->Insert(AllTables[i]->GetDesc());
		}

	//	Reply

	SendMessageReply(MSG_AEON_RESULT_TABLES, CDatum(pArray), Msg);
	}
Exemple #5
0
void CEsperEngine::SendMessageReplyOnRead (CDatum dConnection, CString &sData, const SArchonMessage &OriginalMsg)

//	SendMessageReplyOnRead
//
//	Reply with Esper.onRead

	{
	int iDataLen = sData.GetLength();
	CDatum dData;
	CDatum::CreateStringFromHandoff(sData, &dData);

	CComplexArray *pPayload = new CComplexArray;
	pPayload->Insert(dData);
	pPayload->Insert((int)iDataLen);
	pPayload->Insert(dConnection);

	m_pProcess->SendMessageReply(MSG_ESPER_ON_READ, CDatum(pPayload), OriginalMsg);
	}
Exemple #6
0
CDatum CMnemosynthDb::GenerateEntry (int iCollectionIndex, const CString &sKey, SEntry *pEntry)

//	GenerateEntry
//
//	Generates an entry of the form:
//		0: collection index
//		1: key
//		2: value
//		3: sequence

	{
	CComplexArray *pArray = new CComplexArray;
	pArray->Insert(iCollectionIndex);
	pArray->Insert(sKey);
	pArray->Insert(pEntry->dValue);
	pArray->Insert((int)pEntry->dwSequence);

	return CDatum(pArray);
	}
Exemple #7
0
bool CArchonProcess::OnModuleStart (void)

//	OnModuleStart
//
//	Sends a message to central process telling it our status

	{
	//	If we're not the CentralModule then we need to send a message to
	//	this machine's Exarch telling it that we have started.

	if (!m_bCentralModule && !m_bConsoleMode)
		{
		//	Figure out the Mnemosynth sequence number for this endpoint at this
		//	point in time. We send it over to Exarch so that it waits until it
		//	synchronizes to that point before assuming that loading is complete.

		CString sEndpoint = CMnemosynthDb::GenerateEndpointName(GetMachineName(), GetModuleName());
		DWORD dwSeq = m_MnemosynthDb.GetSequence(sEndpoint);
		ASSERT(dwSeq != 0xffffffff);
		if (dwSeq == 0xffffffff)
			{
			Log(MSG_LOG_ERROR, ERR_UNABLE_TO_OPEN_MNEMOSYNTH);
			return false;
			}

		//	Compose the message

		CComplexArray *pArray = new CComplexArray;
		pArray->Insert(m_sName);
		pArray->Insert((int)dwSeq);

		if (!SendMessageCommand(ADDR_EXARCH_COMMAND, MSG_EXARCH_ON_MODULE_START, NULL_STR, 0, CDatum(pArray)))
			{
			Log(MSG_LOG_ERROR, ERR_UNABLE_TO_SEND_TO_EXARCH);
			return false;
			}
		}

	//	Done

	return true;
	}
Exemple #8
0
void CArchonProcess::ReportVolumeFailure (const CString &sFilespec, const CString &sOperation)

//	ReportVolumeFailure
//
//	And engine calls this method when it fails reading/writing to the given
//	filespec.

	{
	//	We log from here so that we transmit the module that ran into the problem.

	Log(MSG_LOG_ERROR, strPattern(ERR_DISK, sFilespec));

	//	Send a message to Exarch to check the volume.

	CComplexArray *pArray = new CComplexArray;
	pArray->Insert(sFilespec);
	if (!sOperation.IsEmpty())
		pArray->Insert(sOperation);

	SendMessageCommand(ADDR_EXARCH_COMMAND, MSG_EXARCH_REPORT_DISK_ERROR, NULL_STR, 0, CDatum(pArray));
	}
Exemple #9
0
bool CUserInfoSession::UpdateLoginFailure (void)

//	UpdateLoginFailure
//
//	Update the user record with the most recent failure

	{
	//	Set our state

	m_iState = stateWaitingForFailureUpdate;

	//	Mutate the record to set the login date

	CComplexStruct *pRecord = new CComplexStruct;
	pRecord->SetElement(FIELD_LOGIN_FAILURE_COUNT, CDatum((int)1));

	CComplexStruct *pMutation = new CComplexStruct;
	pMutation->SetElement(FIELD_LAST_LOGIN_FAILURE_ON, MUTATE_DATE_MODIFIED);
	pMutation->SetElement(FIELD_LOGIN_FAILURE_COUNT, MUTATE_INCREMENT);

	//	Create a payload

	CComplexArray *pPayload = new CComplexArray;
	pPayload->Insert(USERS_TABLE_NAME);
	pPayload->Insert(m_sUsernameKey);
	pPayload->Insert(CDatum(pRecord));
	pPayload->Insert(CDatum(pMutation));

	//	Send message

	ISessionHandler::SendMessageCommand(ADDRESS_AEON_COMMAND,
			MSG_AEON_MUTATE,
			GenerateAddress(PORT_CRYPTOSAUR_COMMAND),
			CDatum(pPayload),
			MESSAGE_TIMEOUT);

	//	Expect reply

	return true;
	}
Exemple #10
0
CDatum CMnemosynthDb::GenerateCollectionsArray (void)

//	GenerateCollectionsArray
//
//	Creates an array of collection names.
//
//	NOTE: Our callers rely on the fact that this includes all colelctions,
//	even ones with no entries.

	{
	int i;

	CComplexArray *pCollections = new CComplexArray;
	for (i = 0; i < m_Collections.GetCount(); i++)
		pCollections->Insert(m_Collections.GetKey(i));

	return CDatum(pCollections);
	}
Exemple #11
0
void CMnemosynthDb::GenerateDelta (TArray<SMnemosynthUpdate> *retUpdates, CDatum *retdLocalUpdates)

//	GenerateDelta
//
//	Generates a list of changes since the last time we called this

	{
	CSmartLock Lock(m_cs);

	int i, j;

	//	Edge conditions

	if (m_Endpoints.GetCount() == 0)
		{
		*retdLocalUpdates = CDatum();
		return;
		}

	//	If we are not the central module, then we only need to
	//	generate a list of updates made by our own endpoint
	//	(and send it to our central module).

	if (!m_pProcess->IsCentralModule())
		{
		if (GetLocalEndpoint().dwSeqRecv > GetLocalEndpoint().dwSeqSent)
			{
			SMnemosynthUpdate *pUpdate = retUpdates->Insert();
			pUpdate->sDestEndpoint = strPattern("%s/CentralModule", m_pProcess->GetMachineName());

			//	Generate a payload for our updates

			CComplexArray *pEntries = new CComplexArray;
			for (i = 0; i < m_Collections.GetCount(); i++)
				{
				const CString &sCollection = m_Collections.GetKey(i);
				SCollection *pCollection = &m_Collections[i];

				for (j = 0; j < pCollection->Entries.GetCount(); j++)
					{
					SEntry *pEntry = &pCollection->Entries[j];
					if (pEntry->dwOwnerID == 0 && pEntry->dwSequence > GetLocalEndpoint().dwSeqSent)
						{
						CDatum dEntry = GenerateEntry(i, pCollection->Entries.GetKey(j), pEntry);
						pEntries->Insert(dEntry);

						//	If this entry is Nil then we can deleted. (We don't
						//	need it as a deletion stub since we just composed
						//	the update. If this message gets lost we need to
						//	resend everything).

						if (pCollection->Entries.GetValue(j).dValue.IsNil())
							{
							pCollection->Entries.Delete(j);
							j--;
							}
						}
					}
				}

			//	Create the payload

			CComplexStruct *pPayload = new CComplexStruct;
			pPayload->SetElement(STR_COLLECTIONS, GenerateCollectionsArray());
			pPayload->SetElement(STR_ENDPOINT, GetLocalEndpoint().sName);
			pPayload->SetElement(STR_ENTRIES, CDatum(pEntries));
			pPayload->SetElement(FIELD_PROCESS_ID, CDatum(GetLocalEndpoint().dwProcessID));

			//	Add it

			CDatum dLocalUpdates = CDatum(pPayload);
			pUpdate->Payloads.Insert(dLocalUpdates);

			//	Return it

			*retdLocalUpdates = dLocalUpdates;
			}
		else
			*retdLocalUpdates = CDatum();
		}

	//	Otherwise, loop over all endpoints and generate a different
	//	update entry for each one that we need to handle

	else
		{
		bool bFullUpdateNeeded = false;
		for (i = 1; i < m_Endpoints.GetCount(); i++)
			if (m_Endpoints[i].bFullUpdate)
				{
				bFullUpdateNeeded = true;
				break;
				}

		//	Collections

		CDatum dCollections = GenerateCollectionsArray();

		//	We end up creating one or two arrays of deltas. The first
		//	array has all the changes since we last generated a delta
		//	(this is used for endpoints that we updated last time).
		//
		//	The second array has a full set of data (this is for new
		//	endpoints).

		TArray<CComplexArray *> UpdateEntries;
		TArray<CComplexArray *> FullEntries;
		TArray<CDatum> UpdatePayloads;
		TArray<CDatum> FullPayloads;

		UpdateEntries.InsertEmpty(m_Endpoints.GetCount());
		UpdatePayloads.InsertEmpty(m_Endpoints.GetCount());
		if (bFullUpdateNeeded)
			{
			FullEntries.InsertEmpty(m_Endpoints.GetCount());
			FullPayloads.InsertEmpty(m_Endpoints.GetCount());
			}

		for (i = 0; i < m_Endpoints.GetCount(); i++)
			{
			UpdateEntries[i] = new CComplexArray;

			CComplexStruct *pStruct = new CComplexStruct;
			pStruct->SetElement(STR_COLLECTIONS, dCollections);
			pStruct->SetElement(STR_ENDPOINT, m_Endpoints[i].sName);
			pStruct->SetElement(STR_ENTRIES, CDatum(UpdateEntries[i]));
			pStruct->SetElement(FIELD_PROCESS_ID, CDatum(m_Endpoints[i].dwProcessID));
			UpdatePayloads[i] = CDatum(pStruct);

			if (bFullUpdateNeeded)
				{
				FullEntries[i] = new CComplexArray;

				pStruct = new CComplexStruct;
				pStruct->SetElement(STR_COLLECTIONS, dCollections);
				pStruct->SetElement(STR_ENDPOINT, m_Endpoints[i].sName);
				pStruct->SetElement(STR_ENTRIES, CDatum(FullEntries[i]));
				pStruct->SetElement(FIELD_PROCESS_ID, CDatum(m_Endpoints[i].dwProcessID));
				FullPayloads[i] = CDatum(pStruct);
				}
			}

		//	Loop over all entries in the database and add them to the
		//	appropriate payload arrays

		for (i = 0; i < m_Collections.GetCount(); i++)
			{
			const CString &sCollection = m_Collections.GetKey(i);
			SCollection *pCollection = &m_Collections[i];

			for (j = 0; j < pCollection->Entries.GetCount(); j++)
				{
				SEntry *pEntry = &pCollection->Entries[j];

				//	Get the endpoint for the owner of this collection

				int iOwner = FindEndpointIndex(pEntry->dwOwnerID);
				if (iOwner == -1)
					continue;

				//	Add to the update array

				if (pEntry->dwSequence > m_Endpoints[iOwner].dwSeqSent)
					{
					CDatum dEntry = GenerateEntry(i, pCollection->Entries.GetKey(j), pEntry);
					UpdateEntries[iOwner]->Insert(dEntry);

#ifdef DEBUG_MNEMOSYNTH
					printf("[CMnemosynthDb::GenerateDelta]: Endpoint %s %x\n", (LPSTR)m_Endpoints[iOwner].sName, m_Endpoints[iOwner].dwSeqSent);
#endif
					}

				//	Add to full array, if necessary

				if (bFullUpdateNeeded)
					{
					//	Don't bother inserting Nil entries (since this is a full
					//	update).

					if (!pEntry->dValue.IsNil())
						{
						CDatum dEntry = GenerateEntry(i, pCollection->Entries.GetKey(j), pEntry);
						FullEntries[iOwner]->Insert(dEntry);
						}
					}

				//	If this entry is Nil then we can deleted. (We don't
				//	need it as a deletion stub since we just composed
				//	the update. If this message gets lost we need to
				//	resend everything).

				if (pEntry->dValue.IsNil())
					{
					pCollection->Entries.Delete(j);
					j--;
					}
				}
			}

		//	Now iterate over all destination endpoints

		for (i = 1; i < m_Endpoints.GetCount(); i++)
			{
			SEndpoint *pDestEndpoint = &m_Endpoints[i];

#ifdef DEBUG_MNEMOSYNTH
			printf("[CMnemosynthDb::GenerateDelta]: Composing for endpoint %s %s%s.\n", (LPSTR)pDestEndpoint->sName, (pDestEndpoint->bCentralModule ? "CentralModule " : ""), (pDestEndpoint->bLocalMachine ? "local" : ""));
#endif

			//	If this is a local module, then send it any updates
			//	for everything except itself

			if (pDestEndpoint->bLocalMachine && !pDestEndpoint->bCentralModule)
				{
				SMnemosynthUpdate *pUpdate = NULL;

				for (j = 0; j < m_Endpoints.GetCount(); j++)
					if (i != j)
						{
						//	If we have no update entries, then skip.

						if (!pDestEndpoint->bFullUpdate
								&& UpdatePayloads[j].GetElement(STR_ENTRIES).GetCount() == 0)
							continue;

						//	Add an update entry

						if (pUpdate == NULL)
							{
							pUpdate = retUpdates->Insert();
							pUpdate->sDestEndpoint = pDestEndpoint->sName;
							}

						if (pDestEndpoint->bFullUpdate)
							pUpdate->Payloads.Insert(FullPayloads[j]);
						else
							pUpdate->Payloads.Insert(UpdatePayloads[j]);
						}
				}

			//	Otherwise, if this is a foreign central module, then
			//	send it any updates for all local endpoints

			else if (pDestEndpoint->bCentralModule && !pDestEndpoint->bLocalMachine)
				{
				SMnemosynthUpdate *pUpdate = NULL;

#ifdef DEBUG_MNEMOSYNTH
				if (pDestEndpoint->bFullUpdate)
					printf("[CMnemosynthDb::GenerateDelta]: Composing FULL update for %s\n", (LPSTR)pDestEndpoint->sName);
				else
					printf("[CMnemosynthDb::GenerateDelta]: Composing DIFF update for %s\n", (LPSTR)pDestEndpoint->sName);
#endif

				for (j = 0; j < m_Endpoints.GetCount(); j++)
					if (m_Endpoints[j].bLocalMachine)
						{
						//	If we have no update entries, then skip.

						if (!pDestEndpoint->bFullUpdate
								&& UpdatePayloads[j].GetElement(STR_ENTRIES).GetCount() == 0)
							continue;

#ifdef DEBUG_MNEMOSYNTH
						printf("[CMnemosynthDb::GenerateDelta]: Updates from %s\n", (LPSTR)m_Endpoints[j].sName);
#endif

						//	Add an update entry

						if (pUpdate == NULL)
							{
							pUpdate = retUpdates->Insert();
							pUpdate->sDestEndpoint = pDestEndpoint->sName;
							}

						if (pDestEndpoint->bFullUpdate)
							pUpdate->Payloads.Insert(FullPayloads[j]);
						else
							pUpdate->Payloads.Insert(UpdatePayloads[j]);
						}
				}
			}

		//	Local updates

		*retdLocalUpdates = UpdatePayloads[0];
		}

	//	Reset

	for (i = 0; i < m_Endpoints.GetCount(); i++)
		{
		m_Endpoints[i].dwSeqSent = m_Endpoints[i].dwSeqRecv;
		m_Endpoints[i].bFullUpdate = false;
		}

	m_ModifiedEvent.Reset();
	}
Exemple #12
0
void CArchonProcess::Log (const CString &sMsg, const CString &sText)

//	Log
//
//	Log a status or error from the engine

	{
	CString sAddress;

	//	In console mode we just output

	if (m_bConsoleMode)
		{
		LogBlackBox(strPattern("%s: %s", sMsg, sText));
		return;
		}

	//	We don't want to recurse, so we keep track here.

	static __declspec(thread) bool bInLog = false;
	if (bInLog)
		{
#ifdef DEBUG
		printf("ERROR: Unable to log: %s\n", (LPSTR)sText);
#endif
		return;
		}

	bInLog = true;

	//	Protect ourselves in case we crash

	try
		{
		//	If we are Arcology Prime, then we send to our machine's Exarch

		if (m_bArcologyPrime)
			sAddress = ADDRESS_EXARCH_LOG;

		//	Otherwise we need to send to Arcology Prime

		else
			{
			//	NOTE: We can't easily cache this because Arcology Prime might change
			//	(if it restarts, for example).

			sAddress = m_Transporter.GenerateMachineAddress(STR_ARCOLOGY_PRIME, ADDRESS_EXARCH_LOG);
			if (sAddress.IsEmpty())
				{
				bInLog = false;
				return;
				}
			}

		//	Compose the message

		SArchonMessage Msg;
		Msg.sMsg = sMsg;
		Msg.sReplyAddr = ADDR_NULL;
		Msg.dwTicket = 0;

		//	Log the message and the machine/module that it came from

		CComplexArray *pArray = new CComplexArray;
		pArray->Insert(sText);
		pArray->Insert(GenerateAddress(PORT_ARC_LOG));
		Msg.dPayload = CDatum(pArray);

		//	NOTE: We need to use a real address (instead of a virtual port) because the log
		//	command is used before virtual ports replicate to all modules.

		SendMessage(sAddress, Msg);
		}
	catch (...)
		{
#ifdef DEBUG
		printf("ERROR: Crash in log.\n");
#endif
		}

	bInLog = false;
	}
Exemple #13
0
bool CUserInfoSession::OnProcessMessage (const SArchonMessage &Msg)

//	OnProcessMessage
//
//	We received a reply from Aeon

	{
	int i;

	//	If this is an error, then we return the error back to the client

	if (IsError(Msg))
		{
		SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, Msg.dPayload);
		return false;
		}

	//	If we're waiting for the user record, then see if we can process it now.

	if (m_iState == stateWaitingForUserRecord)
		{
		//	Cryptosaur.getUser

		if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_GET_USER))
			{
			CDatum dUserData = Msg.dPayload;

			//	If the user does not exist, then we return Nil

			if (dUserData.IsNil())
				{
				SendMessageReply(MSG_REPLY_DATA, CDatum());
				return false;
				}

			//	Generate a sanitized user record

			CComplexStruct *pReply = new CComplexStruct;
			pReply->SetElement(FIELD_USERNAME, dUserData.GetElement(FIELD_USERNAME));

			//	Sanitize rights

			CDatum dRights = dUserData.GetElement(FIELD_RIGHTS);
			if (!m_sScope.IsEmpty())
				{
				CComplexArray *pRights = new CComplexArray;

				for (i = 0; i < dRights.GetCount(); i++)
					if (strStartsWith(dRights.GetElement(i), m_sScope))
						pRights->Insert(dRights.GetElement(i));

				pReply->SetElement(FIELD_RIGHTS, CDatum(pRights));
				}
			else
				pReply->SetElement(FIELD_RIGHTS, dRights);

			//	Done

			SendMessageReply(MSG_REPLY_DATA, CDatum(pReply));
			return false;
			}

		//	If we get back nil then the user does not exist.

		else if (Msg.dPayload.IsNil())
			{
			SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, strPattern(ERR_UNKNOWN_USERNAME, m_sUsername));
			return false;
			}

		//	Otherwise, we handle the result based on the original message

		else if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_CHECK_PASSWORD_SHA1))
			{
			//	Get the parameters from the original message

			CDatum dChallenge = GetOriginalMsg().dPayload.GetElement(1);
			CDatum dResponse = GetOriginalMsg().dPayload.GetElement(2);

			//	Get the password has from the response

			CDatum dAuthDesc = Msg.dPayload.GetElement(FIELD_AUTH_DESC);
			CDatum dPasswordHash = dAuthDesc.GetElement(FIELD_CREDENTIALS);

			//	Create a response to the challenge based on the password hash that
			//	we have stored.

			CDatum dCorrect = CAI1Protocol::CreateSHAPasswordChallengeResponse(dPasswordHash, dChallenge);

			//	Compare the correct response to the actual

			if ((const CIPInteger &)dResponse == (const CIPInteger &)dCorrect)
				return UpdateLoginSuccess(stateWaitingForSuccessUpdate);
			else
				return UpdateLoginFailure();
			}

		//	Cryptosaur.hasRights

		else if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_HAS_RIGHTS))
			{
			CDatum dRights = Msg.dPayload.GetElement(FIELD_RIGHTS);
			CDatum dRightsRequired = m_dPayload.GetElement(1);

			//	Get the rights from the user

			CAttributeList Rights;
			dRights.AsAttributeList(&Rights);

			//	Check

			for (i = 0; i < dRightsRequired.GetCount(); i++)
				{
				if (!Rights.HasAttribute(dRightsRequired.GetElement(i)))
					{
					SendMessageReply(MSG_REPLY_DATA, CDatum());
					return false;
					}
				}

			//	We have all rights

			SendMessageReply(MSG_REPLY_DATA, CDatum(CDatum::constTrue));
			return false;
			}

		//	Cryptosaur.loginUser

		else if (strEquals(GetOriginalMsg().sMsg, MSG_CRYPTOSAUR_LOGIN_USER))
			{
			//	Get the parameters from the original message

			CDatum dRequestAuthDesc = GetOriginalMsg().dPayload.GetElement(1);
			CDatum dCredentials = dRequestAuthDesc.GetElement(FIELD_CREDENTIALS);
			CDatum dChallengeCredentials = dRequestAuthDesc.GetElement(FIELD_CHALLENGE_CREDENTIALS);
			CDatum dPassword = dRequestAuthDesc.GetElement(FIELD_PASSWORD);
			m_bActual = !dRequestAuthDesc.GetElement(FIELD_ACTUAL).IsNil();

			if (!dRequestAuthDesc.GetElement(FIELD_AUTH_TOKEN_INFINITE).IsNil())
				m_dwAuthTokenLifetime = 0;
			else
				{
				m_dwAuthTokenLifetime = (DWORD)(int)dRequestAuthDesc.GetElement(FIELD_AUTH_TOKEN_LIFETIME);
				if (m_dwAuthTokenLifetime == 0)
					m_dwAuthTokenLifetime = DEFAULT_AUTH_TOKEN_TIMEOUT;
				}

			//	If we're not actual and have no scope, then we can't continue

			if (!m_bActual && m_sScope.IsEmpty())
				{
				SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_SCOPE_REQUIRED);
				return false;
				}

			//	User data

			CDatum dUserData = Msg.dPayload;
			CDatum dAuthDesc;
			if (m_bActual)
				dAuthDesc = dUserData.GetElement(FIELD_AUTH_DESC);
			else
				dAuthDesc = dUserData.GetElement(strPattern("%s%s", m_sScope, FIELD_AUTH_DESC));

			//	If we have no authdesc, then we can't continue. This is likely 
			//	because the client is in a sandbox that the user has not registered
			//	with. We treat it the same as a username/password failure.

			if (dAuthDesc.IsNil())
				{
				SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_INVALID_USERNAME_OR_PASSWORD);
				return false;
				}

			//	If we've failed more than 5 consecutive times, we may need to delay
			//	the next login attempt.

			if ((int)dUserData.GetElement(FIELD_LOGIN_FAILURE_COUNT) > MAX_LOGIN_ATTEMPTS)
				{
				CDateTime LastLoginFailure = dUserData.GetElement(FIELD_LAST_LOGIN_FAILURE_ON);
				CTimeSpan TimeSinceLastFailure = timeSpan(LastLoginFailure, CDateTime(CDateTime::Now));

				//	If it has not been at least 1 hour, we return an error.

				if (TimeSinceLastFailure.Days() == 0 && TimeSinceLastFailure.Seconds() < LOGIN_TIMEOUT)
					{
					//	Timeout

					SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_FAILURE_TIMEOUT);
					return false;
					}
				}

			//	If we have straight credentials, then just compare

			bool bSuccess;
			if (!dCredentials.IsNil())
				bSuccess = ((const CIPInteger &)dCredentials == (const CIPInteger &)dAuthDesc.GetElement(FIELD_CREDENTIALS));

			//	Otherwise, we compare against the challenge

			else if (!dChallengeCredentials.IsNil())
				{
				//	Get the challenge. If not provided then we get it from the user
				//	record.

				CDatum dChallenge = GetOriginalMsg().dPayload.GetElement(2);
				if (dChallenge.IsNil())
					{
					//	Get the expiration time of the challenge

					const CDateTime &Expires = dAuthDesc.GetElement(FIELD_CHALLENGE_EXPIRATION);
					if (Expires < CDateTime(CDateTime::Now))
						{
						SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_INVALID_USERNAME_OR_PASSWORD);
						return false;
						}

					dChallenge = dAuthDesc.GetElement(FIELD_CHALLENGE);
					}

				//	Create a response to the challenge based on the password hash that
				//	we have stored.

				CDatum dCorrectChallenge = CAI1Protocol::CreateSHAPasswordChallengeResponse(
						dAuthDesc.GetElement(FIELD_CREDENTIALS),
						dChallenge
						);

				bSuccess = ((const CIPInteger &)dChallengeCredentials == (const CIPInteger &)dCorrectChallenge);
				}

			//	Otherwise we expect a clear text password

			else if (!dPassword.IsNil())
				{
				//	We have to hash the password to compare with credentials.

				CIPInteger Credentials;
				CCryptosaurInterface::CreateCredentials(dUserData.GetElement(FIELD_USERNAME), dPassword, &Credentials);

				//	Compare

				bSuccess = (Credentials == (const CIPInteger &)dAuthDesc.GetElement(FIELD_CREDENTIALS));
				}
			else
				bSuccess = false;

			//	Success or failure

			if (bSuccess)
				return UpdateLoginSuccess(stateWaitingForCredentials);
			else
				return UpdateLoginFailure();
			}

		//	Can never get here.

		else
			{
			ASSERT(false);
			return false;
			}
		}

	//	Otherwise, if we're waiting for the user record update, then continue

	else if (m_iState == stateWaitingForSuccessUpdate)
		{
		//	Since we succeeded, we send the user sanitized user record back.

		SendMessageReply(MSG_REPLY_DATA, CreateSanitizedUserRecord(Msg.dPayload));
		return false;
		}

	//	If we're waiting for credentials, compose them

	else if (m_iState == stateWaitingForCredentials)
		{
		//	The mutation returns the full record

		CDatum dUserData = Msg.dPayload;

		//	Compute the result

		CComplexStruct *pAuthToken = new CComplexStruct;
		pAuthToken->SetElement(FIELD_USERNAME, dUserData.GetElement(FIELD_USERNAME));
		pAuthToken->SetElement(FIELD_RIGHTS, dUserData.GetElement(FIELD_RIGHTS));
		if (!m_bActual)
			pAuthToken->SetElement(FIELD_SCOPE, m_sScope);

		CDatum dAuthToken = m_pEngine->GenerateAuthToken(CDatum(pAuthToken), m_dwAuthTokenLifetime);

		//	Compose a basic user record

		CComplexStruct *pReply = new CComplexStruct;
		pReply->SetElement(FIELD_AUTH_TOKEN, dAuthToken);
		pReply->SetElement(FIELD_RIGHTS, dUserData.GetElement(FIELD_RIGHTS));
		pReply->SetElement(FIELD_USERNAME, dUserData.GetElement(FIELD_USERNAME));

		//	Send the reply

		SendMessageReply(MSG_REPLY_DATA, CDatum(pReply));

		//	Done

		return false;
		}

	//	Otherwise, failure

	else if (m_iState == stateWaitingForFailureUpdate)
		{
		CDatum dUserData = Msg.dPayload;

		//	If we've exceeded our limit, log it

		int iAttempts = (int)dUserData.GetElement(FIELD_LOGIN_FAILURE_COUNT);
		if (iAttempts > MAX_LOGIN_ATTEMPTS)
			GetProcessCtx()->Log(MSG_LOG_INFO, strPattern(ERR_USERNAME_TIMEOUT, m_sUsername, iAttempts));

		//	Send a failure

		SendMessageReplyError(MSG_ERROR_DOES_NOT_EXIST, ERR_INVALID_USERNAME_OR_PASSWORD);
		return false;
		}

	//	Can never get here

	else
		{
		ASSERT(false);
		return false;
		}
	}
Exemple #14
0
void CAeonView::WriteDesc (CComplexStruct *pDesc)

//	WriteDesc
//
//	Write out a description of the view.

	{
	int i;

	//	ID

	if (m_dwID)
		pDesc->SetElement(FIELD_ID, CDatum((int)m_dwID));

	//	Name

	if (!m_sName.IsEmpty())
		pDesc->SetElement(FIELD_NAME, m_sName);

	//	Dimensions

	if (IsSecondaryView())
		{
		//	Secondary views always have an extra dimension (used for the disambiguating rowKey).

		int iDimsToSave = m_Dims.GetCount() - 1;

		//	Save the user-created dimensions.

		pDesc->SetElement(FIELD_X, CAeonTable::GetDimensionDescForSecondaryView(m_Dims[0], m_Keys[0]));
		if (iDimsToSave > 1)
			{
			pDesc->SetElement(FIELD_Y, CAeonTable::GetDimensionDescForSecondaryView(m_Dims[1], m_Keys[1]));
			if (iDimsToSave > 2)
				pDesc->SetElement(FIELD_Z, CAeonTable::GetDimensionDescForSecondaryView(m_Dims[2], m_Keys[2]));
			}
		}
	else
		{
		pDesc->SetElement(FIELD_X, CAeonTable::GetDimensionDesc(m_Dims[0]));
		if (m_Dims.GetCount() > 1)
			{
			pDesc->SetElement(FIELD_Y, CAeonTable::GetDimensionDesc(m_Dims[1]));
			if (m_Dims.GetCount() > 2)
				pDesc->SetElement(FIELD_Z, CAeonTable::GetDimensionDesc(m_Dims[2]));
			}
		}

	//	Write out columns

	if (m_Columns.GetCount() > 0)
		{
		CComplexArray *pColumns = new CComplexArray;
		for (i = 0; i < m_Columns.GetCount(); i++)
			pColumns->Insert(CDatum(m_Columns[i]));

		pDesc->SetElement(FIELD_COLUMNS, CDatum(pColumns));
		}

	//	Computed columns

	if (!m_ComputedColumns.IsNil())
		pDesc->SetElement(FIELD_COMPUTED_COLUMNS, m_ComputedColumns);

	//	Exclude nil

	if (m_bExcludeNil)
		pDesc->SetElement(FIELD_EXCLUDE_NIL_KEYS, CDatum(CDatum::constTrue));

	//	Write out update sequence number

	if (m_bUpdateNeeded)
		pDesc->SetElement(FIELD_UPDATE_NEEDED, CDatum(CDatum::constTrue));
	}
Exemple #15
0
bool CAeonInterface::ParseFilePath (const CString &sFilePath, const CString &sRoot, int iOffset, const CDateTime &IfModifiedAfter, CString *retsAddr, CString *retsMsg, CDatum *retdPayload)

//	ParseFilePath
//
//	Parses a filePath of the form:
//
//	@Aeon.command/Arc.services/TransPackage.ars
//	/Arc.services/TransPackage.ars
//	./TransPackage.ars
//
//	Returns FALSE if error.

	{
	char *pPos = sFilePath.GetParsePointer();
	char *pPosEnd = pPos + sFilePath.GetLength();

	//	Create a fileDownloadDesc to specify that we not read more than 100K
	//	at a time (so that we don't overload our IPC buffer).

	CComplexStruct *pFDDesc = new CComplexStruct;
	pFDDesc->SetElement(FIELD_PARTIAL_MAX_SIZE, 100000);
	pFDDesc->SetElement(FIELD_PARTIAL_POS, iOffset);
	if (IfModifiedAfter.IsValid())
		pFDDesc->SetElement(FIELD_IF_MODIFIED_AFTER, IfModifiedAfter);

	CDatum dFileDownloadDesc(pFDDesc);

	//	If the path starts with @ then this is an absolute path

	CString sParsedPath;
	if (*pPos == '@')
		{
		//	LATER

		return false;
		}

	//	Is this a service namespace?

	else if (*pPos == '#')
		{
		CString sNamespace;
		if (!CTranspaceInterface::ParseAddress(sFilePath, &sNamespace))
			return false;

		//	Compose a proper download command payload

		CComplexArray *pPayload = new CComplexArray;
		pPayload->Append(sFilePath);
		pPayload->Append(sFilePath);
		pPayload->Append(dFileDownloadDesc);
		CDatum dPayload(pPayload);

		//	Parse the service endpoint

		CString sService(sNamespace.GetParsePointer() + 1);

		//	Encode into the proper payload

		CComplexArray *pPayload2 = new CComplexArray;
		pPayload2->Append(sService);
		pPayload2->Append(MSG_TRANSPACE_DOWNLOAD);
		pPayload2->Append(dPayload);

		//	Done

		*retsAddr = ADDRESS_HYPERION_COMMAND;
		*retsMsg = MSG_HYPERION_SERVICE_MSG;
		*retdPayload = CDatum(pPayload2);
		return true;
		}

	//	If it starts with a slash then it is an Aeon path

	else if (*pPos == '/')
		{
		sParsedPath = sFilePath;
		*retsAddr = ADDR_AEON;
		*retsMsg = MSG_AEON_FILE_DOWNLOAD;

		//	Generate a message for Aeon to load the file

		CComplexArray *pPayload = new CComplexArray;
		pPayload->Insert(sParsedPath);
		pPayload->Insert(dFileDownloadDesc);

		//	Done

		*retdPayload = CDatum(pPayload);
		}

	//	If it starts with a ./ then this is a relative path

	else if (*pPos == '.')
		{
		pPos++;
		if (pPos == pPosEnd || *pPos != '/')
			return false;

		//	Root must be valid

		if (sRoot.IsEmpty())
			return false;

		//	If the root already ends in '/' then skip.

		if (*(sRoot.GetParsePointer() + sRoot.GetLength() - 1) == '/')
			pPos++;

		sParsedPath = sRoot + CString(pPos);
		*retsAddr = ADDR_AEON;
		*retsMsg = MSG_AEON_FILE_DOWNLOAD;

		//	Generate a message for Aeon to load the file

		CComplexArray *pPayload = new CComplexArray;
		pPayload->Insert(sParsedPath);
		pPayload->Insert(dFileDownloadDesc);

		//	Done

		*retdPayload = CDatum(pPayload);
		}

	//	Otherwise this is a relative path.

	else
		{
		//	Root must be valid

		if (sRoot.IsEmpty())
			return false;

		//	Add '/' separator

		if (*(sRoot.GetParsePointer() + sRoot.GetLength() - 1) == '/')
			sParsedPath = sRoot + sFilePath;
		else
			sParsedPath = sRoot + SEPARATOR_SLASH, sFilePath;

		*retsAddr = ADDR_AEON;
		*retsMsg = MSG_AEON_FILE_DOWNLOAD;

		//	Generate a message for Aeon to load the file

		CComplexArray *pPayload = new CComplexArray;
		pPayload->Insert(sParsedPath);
		pPayload->Insert(dFileDownloadDesc);

		//	Done

		*retdPayload = CDatum(pPayload);
		}


	return true;
	}