Reimplement some functions

This commit is contained in:
KimLS 2017-12-24 23:21:17 -08:00
parent 7a778c549f
commit 0ec53eff52
11 changed files with 195 additions and 146 deletions

View File

@ -224,7 +224,7 @@ uint32 Database::CreateAccount(const char* name, const char* password, int16 sta
return results.LastInsertedID();
}
bool Database::DeleteAccount(const char *loginserver, const char* name) {
bool Database::DeleteAccount(const char* name, const char *loginserver) {
std::string query = StringFormat("DELETE FROM account WHERE name='%s' AND ls_id='%s'", name, loginserver);
Log(Logs::General, Logs::World_Server, "Account Attempting to be deleted:'%s:%s'", loginserver, name);

View File

@ -174,7 +174,7 @@ public:
/* Account Related */
bool DeleteAccount(const char *loginserver, const char* name);
bool DeleteAccount(const char *name, const char* loginserver);
bool GetLiveChar(uint32 account_id, char* cname);
bool SetAccountStatus(const char* name, int16 status);
bool SetLocalPassword(uint32 accid, const char* password);

View File

@ -196,6 +196,19 @@ void find_replace(std::string& string_subject, const std::string& search_string,
}
}
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver)
{
auto split = SplitString(s, '.');
if (split.size() == 2) {
loginserver = split[0];
account = split[1];
}
else if(split.size() == 1) {
loginserver = "eqemu";
account = split[0];
}
}
//Const char based
// normal strncpy doesnt put a null term on copied strings, this one does

View File

@ -34,6 +34,7 @@ void ToLowerString(std::string &s);
void ToUpperString(std::string &s);
std::string JoinString(const std::vector<std::string>& ar, const std::string &delim);
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string);
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver);
//const char based

View File

@ -180,8 +180,6 @@ void Client::Handle_SessionReady(const char* data, unsigned int size)
void Client::Handle_Login(const char* data, unsigned int size)
{
auto mode = server.options.GetEncryptionMode();
if (status != cs_waiting_for_login) {
Log(Logs::General, Logs::Error, "Login received after already having logged in.");
return;
@ -241,6 +239,8 @@ void Client::Handle_Login(const char* data, unsigned int size)
db_loginserver = components[0];
user = components[1];
}
ParseAccountString(user, user, db_loginserver);
if (server.db->GetLoginDataFromAccountInfo(user, db_loginserver, db_account_password_hash, db_account_id) == false) {
status = cs_creating_account;
@ -248,41 +248,7 @@ void Client::Handle_Login(const char* data, unsigned int size)
return;
}
else {
if (eqcrypt_verify_hash(user, cred, db_account_password_hash, mode)) {
result = true;
}
else
{
if (server.options.IsUpdatingInsecurePasswords()) {
auto len = db_account_password_hash.length();
int start = 0;
int end = 0;
switch (len) {
case 32:
start = 1;
end = 4;
break;
case 40:
start = 5;
end = 8;
break;
case 128:
start = 9;
end = 12;
break;
}
if (start != 0) {
for (int i = start; i <= end; ++i) {
if (eqcrypt_verify_hash(user, cred, db_account_password_hash, i)) {
result = true;
server.db->UpdateLoginHash(user, db_loginserver, eqcrypt_hash(user, cred, mode));
break;
}
}
}
}
}
result = VerifyLoginHash(user, db_loginserver, cred, db_account_password_hash);
}
}
}
@ -432,6 +398,50 @@ void Client::DoFailedLogin()
status = cs_failed_to_login;
}
bool Client::VerifyLoginHash(const std::string &user, const std::string &loginserver, const std::string &cred, const std::string &hash)
{
auto mode = server.options.GetEncryptionMode();
if (eqcrypt_verify_hash(user, cred, hash, mode)) {
return true;
}
else {
if (server.options.IsUpdatingInsecurePasswords()) {
if (mode < EncryptionModeArgon2) {
mode = EncryptionModeArgon2;
}
if (hash.length() == 32) { //md5 is insecure
for (int i = EncryptionModeMD5; i <= EncryptionModeMD5Triple; ++i) {
if (i != mode && eqcrypt_verify_hash(user, cred, hash, i)) {
server.db->UpdateLoginHash(user, loginserver, eqcrypt_hash(user, cred, mode));
return true;
}
}
}
else if (hash.length() == 40) { //sha1 is insecure
for (int i = EncryptionModeSHA; i <= EncryptionModeSHATriple; ++i) {
if (i != mode && eqcrypt_verify_hash(user, cred, hash, i)) {
server.db->UpdateLoginHash(user, loginserver, eqcrypt_hash(user, cred, mode));
return true;
}
}
}
else if (hash.length() == 128) { //sha2-512 is insecure
for (int i = EncryptionModeSHA512; i <= EncryptionModeSHA512Triple; ++i) {
if (i != mode && eqcrypt_verify_hash(user, cred, hash, i)) {
server.db->UpdateLoginHash(user, loginserver, eqcrypt_hash(user, cred, mode));
return true;
}
}
}
//argon2 is still secure
//scrypt is still secure
}
}
return false;
}
void Client::DoSuccessfulLogin(const std::string &user, int db_account_id, const std::string &db_loginserver)
{
stored_user.clear();

View File

@ -141,6 +141,11 @@ public:
*/
void DoFailedLogin();
/**
* Verifies a login hash, will also attempt to update a login hash if needed.
*/
bool VerifyLoginHash(const std::string &user, const std::string &loginserver, const std::string &cred, const std::string &hash);
/**
* Does a successful login
*/

View File

@ -7,6 +7,8 @@
#include <sodium.h>
#endif
#include "encryption.h"
const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc) {
DES_key_schedule k;
DES_cblock v;
@ -100,34 +102,34 @@ std::string eqcrypt_scrypt(const std::string &msg)
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode) {
switch (mode)
{
case 1:
case EncryptionModeMD5:
return eqcrypt_md5(password);
case 2:
case EncryptionModeMD5PassUser:
return eqcrypt_md5(password + ":" + username);
case 3:
case EncryptionModeMD5UserPass:
return eqcrypt_md5(username + ":" + password);
case 4:
case EncryptionModeMD5Triple:
return eqcrypt_md5(eqcrypt_md5(username) + eqcrypt_md5(password));
case 5:
case EncryptionModeSHA:
return eqcrypt_sha1(password);
case 6:
case EncryptionModeSHAPassUser:
return eqcrypt_sha1(password + ":" + username);
case 7:
case EncryptionModeSHAUserPass:
return eqcrypt_sha1(username + ":" + password);
case 8:
case EncryptionModeSHATriple:
return eqcrypt_sha1(eqcrypt_sha1(username) + eqcrypt_sha1(password));
case 9:
case EncryptionModeSHA512:
return eqcrypt_sha512(password);
case 10:
case EncryptionModeSHA512PassUser:
return eqcrypt_sha512(password + ":" + username);
case 11:
case EncryptionModeSHA512UserPass:
return eqcrypt_sha512(username + ":" + password);
case 12:
case EncryptionModeSHA512Triple:
return eqcrypt_sha512(eqcrypt_sha512(username) + eqcrypt_sha512(password));
#ifdef ENABLE_SECURITY
case 13:
case EncryptionModeArgon2:
return eqcrypt_argon2(password);
case 14:
case EncryptionModeSCrypt:
return eqcrypt_scrypt(password);
#endif
//todo bcrypt? pbkdf2?

View File

@ -2,6 +2,24 @@
#include <string>
enum EncryptionMode
{
EncryptionModeMD5 = 1,
EncryptionModeMD5PassUser = 2,
EncryptionModeMD5UserPass = 3,
EncryptionModeMD5Triple = 4,
EncryptionModeSHA = 5,
EncryptionModeSHAPassUser = 6,
EncryptionModeSHAUserPass = 7,
EncryptionModeSHATriple = 8,
EncryptionModeSHA512 = 9,
EncryptionModeSHA512PassUser = 10,
EncryptionModeSHA512UserPass = 11,
EncryptionModeSHA512Triple = 12,
EncryptionModeArgon2 = 13,
EncryptionModeSCrypt = 14
};
const char* eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char* buffer_out, bool enc);
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);

View File

@ -19,14 +19,7 @@ struct EQ::Net::ConsoleLoginStatus CheckLogin(const std::string& username, const
std::string prefix = "eqemu";
std::string raw_user = "";
auto split = SplitString(username, '.');
if (split.size() == 2) {
prefix = split[0];
raw_user = split[1];
}
else {
raw_user = split[0];
}
ParseAccountString(username, raw_user, prefix);
ret.account_id = database.CheckLogin(raw_user.c_str(), password.c_str(), prefix.c_str());
@ -399,14 +392,7 @@ void ConsoleSetPass(EQ::Net::ConsoleServerConnection* connection, const std::str
std::string prefix = "eqemu";
std::string raw_user = "";
auto split = SplitString(args[0], '.');
if (split.size() == 2) {
prefix = split[0];
raw_user = split[1];
}
else {
raw_user = split[0];
}
ParseAccountString(args[0], raw_user, prefix);
int16 tmpstatus = 0;
uint32 tmpid = database.GetAccountIDByName(raw_user.c_str(), prefix.c_str(), &tmpstatus);

View File

@ -213,24 +213,28 @@ int main(int argc, char** argv) {
}
}
else if (strcasecmp(argv[1], "adduser") == 0) {
//TODO: REIMPLEMENT
//if (argc == 5) {
// if (Seperator::IsNumber(argv[4])) {
// if (atoi(argv[4]) >= 0 && atoi(argv[4]) <= 255) {
// if (database.CreateAccount(argv[2], argv[3], atoi(argv[4])) == 0) {
// std::cerr << "database.CreateAccount failed." << std::endl;
// return 1;
// }
// else {
// std::cout << "Account created: Username='" << argv[2] << "', Password='" << argv[3] << "', status=" << argv[4] << std::endl;
// return 0;
// }
// }
// }
//}
//std::cout << "Usage: world adduser username password flag" << std::endl;
//std::cout << "flag = 0, 1 or 2" << std::endl;
//return 0;
if (argc == 5) {
if (Seperator::IsNumber(argv[4])) {
if (atoi(argv[4]) >= 0 && atoi(argv[4]) <= 255) {
std::string user;
std::string loginserver;
ParseAccountString(argv[2], user, loginserver);
if (database.CreateAccount(argv[2], argv[3], atoi(argv[4]), loginserver.c_str(), 0) == 0) {
std::cerr << "database.CreateAccount failed." << std::endl;
return 1;
}
else {
std::cout << "Account created: Username='" << argv[2] << "', Password='" << argv[3] << "', status=" << argv[4] << std::endl;
return 0;
}
}
}
}
std::cout << "Usage: world adduser username password flag" << std::endl;
std::cout << "flag = 0, 1 or 2" << std::endl;
return 0;
}
else if (strcasecmp(argv[1], "flag") == 0) {
if (argc == 4) {

View File

@ -1957,33 +1957,40 @@ void command_shutdown(Client *c, const Seperator *sep)
void command_delacct(Client *c, const Seperator *sep)
{
//TODO: REIMPLEMENT
// if(sep->arg[1][0] == 0)
// c->Message(0, "Format: #delacct accountname");
// else
// if (database.DeleteAccount(sep->arg[1]))
// c->Message(0, "The account was deleted.");
// else
// c->Message(0, "Unable to delete account.");
if (sep->arg[1][0] == 0)
c->Message(0, "Format: #delacct accountname");
else {
std::string user;
std::string loginserver;
ParseAccountString(sep->arg[1], user, loginserver);
if (database.DeleteAccount(user.c_str(), loginserver.c_str()))
c->Message(0, "The account was deleted.");
else
c->Message(0, "Unable to delete account.");
}
}
void command_setpass(Client *c, const Seperator *sep)
{
//TODO: REIMPLEMENT
//if(sep->argnum != 2)
// c->Message(0, "Format: #setpass accountname password");
//else {
// int16 tmpstatus = 0;
// uint32 tmpid = database.GetAccountIDByName(sep->arg[1], &tmpstatus);
// if (!tmpid)
// c->Message(0, "Error: Account not found");
// else if (tmpstatus > c->Admin())
// c->Message(0, "Cannot change password: Account's status is higher than yours");
// else if (database.SetLocalPassword(tmpid, sep->arg[2]))
// c->Message(0, "Password changed.");
// else
// c->Message(0, "Error changing password.");
//}
if(sep->argnum != 2)
c->Message(0, "Format: #setpass accountname password");
else {
std::string user;
std::string loginserver;
ParseAccountString(sep->arg[1], user, loginserver);
int16 tmpstatus = 0;
uint32 tmpid = database.GetAccountIDByName(user.c_str(), loginserver.c_str(), &tmpstatus);
if (!tmpid)
c->Message(0, "Error: Account not found");
else if (tmpstatus > c->Admin())
c->Message(0, "Cannot change password: Account's status is higher than yours");
else if (database.SetLocalPassword(tmpid, sep->arg[2]))
c->Message(0, "Password changed.");
else
c->Message(0, "Error changing password.");
}
}
void command_setlsinfo(Client *c, const Seperator *sep)
@ -4416,42 +4423,45 @@ void command_uptime(Client *c, const Seperator *sep)
void command_flag(Client *c, const Seperator *sep)
{
//TODO: REIMPLEMENT
// if(sep->arg[2][0] == 0) {
// if (!c->GetTarget() || (c->GetTarget() && c->GetTarget() == c)) {
// c->UpdateAdmin();
// c->Message(0, "Refreshed your admin flag from DB.");
// } else if (c->GetTarget() && c->GetTarget() != c && c->GetTarget()->IsClient()) {
// c->GetTarget()->CastToClient()->UpdateAdmin();
// c->Message(0, "%s's admin flag has been refreshed.", c->GetTarget()->GetName());
// c->GetTarget()->Message(0, "%s refreshed your admin flag.", c->GetName());
// }
// }
// else if (!sep->IsNumber(1) || atoi(sep->arg[1]) < -2 || atoi(sep->arg[1]) > 255 || strlen(sep->arg[2]) == 0)
// c->Message(0, "Usage: #flag [status] [acctname]");
//
// else if (c->Admin() < commandChangeFlags) {
////this check makes banning players by less than this level
////impossible, but i'll leave it in anyways
// c->Message(0, "You may only refresh your own flag, doing so now.");
// c->UpdateAdmin();
// }
// else {
// if (atoi(sep->arg[1]) > c->Admin())
// c->Message(0, "You cannot set people's status to higher than your own");
// else if (atoi(sep->arg[1]) < 0 && c->Admin() < commandBanPlayers)
// c->Message(0, "You have too low of status to suspend/ban");
// else if (!database.SetAccountStatus(sep->argplus[2], atoi(sep->arg[1])))
// c->Message(0, "Unable to set GM Flag.");
// else {
// c->Message(0, "Set GM Flag on account.");
// auto pack = new ServerPacket(ServerOP_FlagUpdate, 6);
// *((uint32*) pack->pBuffer) = database.GetAccountIDByName(sep->argplus[2]);
// *((int16*) &pack->pBuffer[4]) = atoi(sep->arg[1]);
// worldserver.SendPacket(pack);
// delete pack;
// }
// }
if(sep->arg[2][0] == 0) {
if (!c->GetTarget() || (c->GetTarget() && c->GetTarget() == c)) {
c->UpdateAdmin();
c->Message(0, "Refreshed your admin flag from DB.");
} else if (c->GetTarget() && c->GetTarget() != c && c->GetTarget()->IsClient()) {
c->GetTarget()->CastToClient()->UpdateAdmin();
c->Message(0, "%s's admin flag has been refreshed.", c->GetTarget()->GetName());
c->GetTarget()->Message(0, "%s refreshed your admin flag.", c->GetName());
}
}
else if (!sep->IsNumber(1) || atoi(sep->arg[1]) < -2 || atoi(sep->arg[1]) > 255 || strlen(sep->arg[2]) == 0)
c->Message(0, "Usage: #flag [status] [acctname]");
else if (c->Admin() < commandChangeFlags) {
//this check makes banning players by less than this level
//impossible, but i'll leave it in anyways
c->Message(0, "You may only refresh your own flag, doing so now.");
c->UpdateAdmin();
}
else {
if (atoi(sep->arg[1]) > c->Admin())
c->Message(0, "You cannot set people's status to higher than your own");
else if (atoi(sep->arg[1]) < 0 && c->Admin() < commandBanPlayers)
c->Message(0, "You have too low of status to suspend/ban");
else if (!database.SetAccountStatus(sep->argplus[2], atoi(sep->arg[1])))
c->Message(0, "Unable to set GM Flag.");
else {
c->Message(0, "Set GM Flag on account.");
std::string user;
std::string loginserver;
ParseAccountString(sep->argplus[2], user, loginserver);
ServerPacket pack(ServerOP_FlagUpdate, 6);
*((uint32*) pack.pBuffer) = database.GetAccountIDByName(user.c_str(), loginserver.c_str());
*((int16*) &pack.pBuffer[4]) = atoi(sep->arg[1]);
worldserver.SendPacket(&pack);
}
}
}
void command_time(Client *c, const Seperator *sep)