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; }
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); }
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; }
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); }
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); }
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); }
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; }
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)); }
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; }
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); }
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(); }
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; }
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; } }
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)); }
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; }