bool ChallengeRespond(const CNick& Nick, const CString& sChallenge) { // Validate before responding - don't blindly trust everyone bool bValid = false; bool bMatchedHost = false; CAutoOpUser* pUser = NULL; for (map<CString, CAutoOpUser*>::iterator it = m_msUsers.begin(); it != m_msUsers.end(); it++) { pUser = it->second; // First verify that the guy who challenged us matches a user's host if (pUser->HostMatches(Nick.GetHostMask())) { const vector<CChan*>& Chans = m_pUser->GetChans(); bMatchedHost = true; // Also verify that they are opped in at least one of the user's chans for (size_t a = 0; a < Chans.size(); a++) { const CChan& Chan = *Chans[a]; CNick* pNick = Chan.FindNick(Nick.GetNick()); if (pNick) { if (pNick->HasPerm(CChan::Op) && pUser->ChannelMatches(Chan.GetName())) { bValid = true; break; } } } if (bValid) { break; } } } if (!bValid) { if (bMatchedHost) { PutModule("[" + Nick.GetHostMask() + "] sent us a challenge but they are not opped in any defined channels."); } else { PutModule("[" + Nick.GetHostMask() + "] sent us a challenge but they do not match a defined user."); } return false; } if (sChallenge.length() != AUTOOP_CHALLENGE_LENGTH) { PutModule("WARNING! [" + Nick.GetHostMask() + "] sent an invalid challenge."); return false; } CString sResponse = pUser->GetUserKey() + "::" + sChallenge; PutIRC("NOTICE " + Nick.GetNick() + " :!ZNCAO RESPONSE " + sResponse.MD5()); return false; }
CString HMAC_MD5(const CString& sKey, const CString& sData) { CString sRealKey; if (sKey.length() > 64) PackHex(sKey.MD5(), sRealKey); else sRealKey = sKey; CString sOuterKey, sInnerKey; unsigned int iKeyLength = sRealKey.length(); for (unsigned int i = 0; i < 64; i++) { int r = (i < iKeyLength ? sRealKey[i] : 0); sOuterKey += r ^ 0x5c; sInnerKey += r ^ 0x36; } CString sInnerHash; PackHex(CString(sInnerKey + sData).MD5(), sInnerHash); return CString(sOuterKey + sInnerHash).MD5(); }