mirror of
https://github.com/znc/znc.git
synced 2026-08-07 01:13:25 +02:00
Add supports for salted hashes to znc.conf
These changes the format of the 'Pass' config option. The old format is still accepted. The new format is: Pass = plain#<plain text password> Pass = md5#<password hash> Pass = md5#<hash of password with salt appended>#<salt># This also makes ZNC only write configs in the new format. znc --makeconf and znc --makepass now always generate salted hashes. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1127 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
@@ -565,7 +565,15 @@ bool CUser::PrintLine(CFile& File, const CString& sName, const CString& sValue)
|
||||
bool CUser::WriteConfig(CFile& File) {
|
||||
File.Write("<User " + GetUserName() + ">\n");
|
||||
|
||||
PrintLine(File, "Pass", GetPass() + ((IsPassHashed()) ? " -" : ""));
|
||||
if (IsPassHashed()) {
|
||||
if (m_sPassSalt.empty()) {
|
||||
PrintLine(File, "Pass", "md5#" + GetPass());
|
||||
} else {
|
||||
PrintLine(File, "Pass", "md5#" + GetPass() + "#" + m_sPassSalt + "#");
|
||||
}
|
||||
} else {
|
||||
PrintLine(File, "Pass", "plain#" + GetPass());
|
||||
}
|
||||
PrintLine(File, "Nick", GetNick());
|
||||
PrintLine(File, "AltNick", GetAltNick());
|
||||
PrintLine(File, "Ident", GetIdent());
|
||||
@@ -808,7 +816,9 @@ bool CUser::CheckPass(const CString& sPass) {
|
||||
return (sPass == m_sPass);
|
||||
}
|
||||
|
||||
return (m_sPass.CaseCmp(sPass.MD5()) == 0);
|
||||
CString sSaltedPass = sPass + m_sPassSalt;
|
||||
|
||||
return (m_sPass.CaseCmp(sSaltedPass.MD5()) == 0);
|
||||
}
|
||||
|
||||
/*CClient* CUser::GetClient() {
|
||||
@@ -1023,7 +1033,11 @@ void CUser::SetAltNick(const CString& s) { m_sAltNick = s; }
|
||||
void CUser::SetIdent(const CString& s) { m_sIdent = s; }
|
||||
void CUser::SetRealName(const CString& s) { m_sRealName = s; }
|
||||
void CUser::SetVHost(const CString& s) { m_sVHost = s; }
|
||||
void CUser::SetPass(const CString& s, bool bHashed) { m_sPass = s; m_bPassHashed = bHashed; }
|
||||
void CUser::SetPass(const CString& s, bool bHashed, const CString& sSalt) {
|
||||
m_sPass = s;
|
||||
m_bPassHashed = bHashed;
|
||||
m_sPassSalt = sSalt;
|
||||
}
|
||||
void CUser::SetMultiClients(bool b) { m_bMultiClients = b; }
|
||||
void CUser::SetBounceDCCs(bool b) { m_bBounceDCCs = b; }
|
||||
void CUser::SetUseClientIP(bool b) { m_bUseClientIP = b; }
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
void SetIdent(const CString& s);
|
||||
void SetRealName(const CString& s);
|
||||
void SetVHost(const CString& s);
|
||||
void SetPass(const CString& s, bool bHashed);
|
||||
void SetPass(const CString& s, bool bHashed, const CString& sSalt = "");
|
||||
void SetBounceDCCs(bool b);
|
||||
void SetMultiClients(bool b);
|
||||
void SetUseClientIP(bool b);
|
||||
@@ -207,6 +207,7 @@ protected:
|
||||
CString m_sRealName;
|
||||
CString m_sVHost;
|
||||
CString m_sPass;
|
||||
CString m_sPassSalt;
|
||||
CString m_sStatusPrefix;
|
||||
CString m_sDefaultChanModes;
|
||||
CString m_sChanPrefixes;
|
||||
|
||||
@@ -189,6 +189,49 @@ CString CUtils::GetHashPass() {
|
||||
return "";
|
||||
}
|
||||
|
||||
CString CUtils::GetSaltedHashPass(CString& sSalt, unsigned int uiSaltLength) {
|
||||
sSalt = CString::RandomString(uiSaltLength);
|
||||
const char *pSalt = sSalt.c_str();
|
||||
|
||||
while (true) {
|
||||
char* pass = CUtils::GetPass("Enter Password");
|
||||
char* pass1 = (char *) malloc(strlen(pass) + 1);
|
||||
// Make a copy of this since it is stored in a static buffer and will be overwritten when we fill pass2 below
|
||||
strcpy(pass1, pass);
|
||||
// null out our pass so it doesn't sit in memory
|
||||
memset(pass, 0, strlen(pass));
|
||||
char* pass2 = CUtils::GetPass("Confirm Password");
|
||||
int iLen = strlen(pass1);
|
||||
|
||||
if (strcmp(pass1, pass2) != 0) {
|
||||
CUtils::PrintError("The supplied passwords did not match");
|
||||
} else if (!iLen) {
|
||||
CUtils::PrintError("You can not use an empty password");
|
||||
} else {
|
||||
// Construct the salted pass
|
||||
char *salted_pass = (char *) malloc(iLen + uiSaltLength + 1);
|
||||
strcpy(salted_pass, pass1);
|
||||
strcpy(salted_pass + iLen, pSalt);
|
||||
|
||||
CString sRet((const char*) CMD5(salted_pass, iLen + uiSaltLength));
|
||||
// null out our pass so it doesn't sit in memory
|
||||
memset(salted_pass, 0, iLen + uiSaltLength);
|
||||
memset(pass1, 0, iLen);
|
||||
memset(pass2, 0, strlen(pass2));
|
||||
free(salted_pass);
|
||||
free(pass1);
|
||||
|
||||
return sRet;
|
||||
}
|
||||
|
||||
memset((char*) pass1, 0, iLen); // null out our pass so it doesn't sit in memory
|
||||
memset((char*) pass2, 0, strlen(pass2)); // null out our pass so it doesn't sit in memory
|
||||
free(pass1);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
char* CUtils::GetPass(const CString& sPrompt) {
|
||||
PrintPrompt(sPrompt);
|
||||
return getpass("");
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
static void PrintAction(const CString& sMessage);
|
||||
static void PrintStatus(bool bSuccess, const CString& sMessage = "");
|
||||
static CString GetHashPass();
|
||||
static CString GetSaltedHashPass(CString& sSalt, unsigned int uiSaltLength = 20);
|
||||
static char* GetPass(const CString& sPrompt);
|
||||
static bool GetInput(const CString& sPrompt, CString& sRet, const CString& sDefault = "", const CString& sHint = "");
|
||||
static bool GetBoolInput(const CString& sPrompt, bool bDefault);
|
||||
|
||||
@@ -193,9 +193,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
#endif /* HAVE_LIBSSL */
|
||||
if (bMakePass) {
|
||||
CString sHash = CUtils::GetHashPass();
|
||||
CString sSalt;
|
||||
CString sHash = CUtils::GetSaltedHashPass(sSalt);
|
||||
CUtils::PrintMessage("Use this in the <User> section of your config:");
|
||||
CUtils::PrintMessage("Pass = " + sHash + " -");
|
||||
CUtils::PrintMessage("Pass = md5#" + sHash + "#" + sSalt + "#");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -666,8 +666,9 @@ bool CZNC::WriteNewConfig(const CString& sConfig) {
|
||||
} while (!CUser::IsValidUserName(sUser));
|
||||
|
||||
vsLines.push_back("<User " + sUser + ">");
|
||||
sAnswer = CUtils::GetHashPass();
|
||||
vsLines.push_back("\tPass = " + sAnswer + " -");
|
||||
CString sSalt;
|
||||
sAnswer = CUtils::GetSaltedHashPass(sSalt);
|
||||
vsLines.push_back("\tPass = md5#" + sAnswer + "#" + sSalt + "#");
|
||||
|
||||
if (CUtils::GetBoolInput("Would you like this user to be an admin?", bFirstUser)) {
|
||||
vsLines.push_back("\tAdmin = true");
|
||||
@@ -1180,12 +1181,29 @@ bool CZNC::DoRehash(CString& sError)
|
||||
CUtils::PrintMessage("WARNING: AwaySuffix has been depricated, instead try -> LoadModule = awaynick %nick%_" + sValue);
|
||||
continue;
|
||||
} else if (sName.CaseCmp("Pass") == 0) {
|
||||
// There are different formats for this available:
|
||||
// Pass = <plain text>
|
||||
// Pass = <md5 hash> -
|
||||
// Pass = plain#<plain text>
|
||||
// Pass = md5#<md5 hash>
|
||||
// Pass = md5#<salted md5 hash>#<salt>#
|
||||
// The last one is the md5 hash of 'password' + 'salt'
|
||||
if (sValue.Right(1) == "-") {
|
||||
sValue.RightChomp();
|
||||
sValue.Trim();
|
||||
pUser->SetPass(sValue, true);
|
||||
} else {
|
||||
pUser->SetPass(sValue, false);
|
||||
CString sMethod = sValue.Token(0, false, "#");
|
||||
CString sPass = sValue.Token(1, true, "#");
|
||||
if (sMethod == "md5") {
|
||||
CString sSalt = sPass.Token(1, false, "#");
|
||||
sPass = sPass.Token(0, false, "#");
|
||||
pUser->SetPass(sPass, true, sSalt);
|
||||
} else if (sMethod == "plain") {
|
||||
pUser->SetPass(sPass, false);
|
||||
} else {
|
||||
pUser->SetPass(sValue, false);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user