From 821bcfe6b8db045a03694d032bde530e8152585f Mon Sep 17 00:00:00 2001 From: MrHappyAsthma Date: Sat, 22 Feb 2020 20:39:27 -0800 Subject: [PATCH 1/2] Add a simple flow to allow changing user passwords. This is a prerequisite for DarkstarProject/xiloader#7. This change adds support for a new command in the login code to support changing a users password. It simply verifies the users login similarly to the existing flow, and then makes another request over the socket for the new password. Then it updates the SQL. Tested locally. Have a set of changes ready for xiloader as well, but this work is required first. NOTE: There is definitely some refactoring that could be done in this file to reduce the amount of nested braces and to reduce duplicated code. I tried to touch as little existing code as possible in this change to reduce the risk of introducing a regression. --- src/login/login_auth.cpp | 88 ++++++++++++++++++++++++++++++++++++++-- src/login/login_auth.h | 18 +++++--- 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/login/login_auth.cpp b/src/login/login_auth.cpp index 063ddf7201b..d8d651e50fa 100644 --- a/src/login/login_auth.cpp +++ b/src/login/login_auth.cpp @@ -100,6 +100,9 @@ int32 login_parse(int32 fd) return -1; } + Sql_EscapeString(SqlHandle, escaped_name, name.c_str()); + Sql_EscapeString(SqlHandle, escaped_pass, password.c_str()); + switch (code) { case LOGIN_ATTEMPT: @@ -107,8 +110,6 @@ int32 login_parse(int32 fd) const char* fmtQuery = "SELECT accounts.id,accounts.status \ FROM accounts \ WHERE accounts.login = '%s' AND accounts.password = PASSWORD('%s')"; - Sql_EscapeString(SqlHandle, escaped_name, name.c_str()); - Sql_EscapeString(SqlHandle, escaped_pass, password.c_str()); int32 ret = Sql_Query(SqlHandle, fmtQuery, escaped_name, escaped_pass); if (ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0) { @@ -208,8 +209,6 @@ int32 login_parse(int32 fd) break; case LOGIN_CREATE: //looking for same login - Sql_EscapeString(SqlHandle, escaped_name, name.c_str()); - Sql_EscapeString(SqlHandle, escaped_pass, password.c_str()); if (Sql_Query(SqlHandle, "SELECT accounts.id FROM accounts WHERE accounts.login = '%s'", escaped_name) == SQL_ERROR) { session[fd]->wdata.resize(1); @@ -273,6 +272,87 @@ int32 login_parse(int32 fd) do_close_login(sd, fd); } break; + case LOGIN_CHANGE_PASSWORD: + { + const char* fmtQuery = "SELECT accounts.id,accounts.status \ + FROM accounts \ + WHERE accounts.login = '%s' AND accounts.password = PASSWORD('%s')"; + int32 ret = Sql_Query(SqlHandle, fmtQuery, escaped_name, escaped_pass); + if (ret == SQL_ERROR || Sql_NumRows(SqlHandle) == 0) + { + session[fd]->wdata.resize(1); + ref(session[fd]->wdata.data(), 0) = LOGIN_ERROR; + ShowWarning("login_parse: unexisting user" CL_WHITE"<%s>" CL_RESET" tried to connect\n", escaped_name); + do_close_login(sd, fd); + return 0; + } + + ret = Sql_NextRow(SqlHandle); + + sd->accid = (uint32)Sql_GetUIntData(SqlHandle, 0); + uint8 status = (uint8)Sql_GetUIntData(SqlHandle, 1); + + if (status & ACCST_BANNED) + { + session[fd]->wdata.resize(1); + ref(session[fd]->wdata.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ShowInfo("login_parse: banned user" CL_WHITE"<%s>" CL_RESET" detected. Aborting.\n", escaped_name); + do_close_login(sd, fd); + return 0; + } + + if (status & ACCST_NORMAL) + { + // Account info verified. Now request the new password. + session[fd]->wdata.resize(1); + ref(session[fd]->wdata.data(), 0) = LOGIN_REQUEST_NEW_PASSWORD; + flush_fifo(fd); + session[fd]->rdata.resize(0); // Clear read buffer + session[fd]->func_recv(fd); + + // Packet expects a single password parameter no longer than + // 16 bytes. + size_t size = session[fd]->rdata.size(); + if (size == 0 || size > 16) + { + session[fd]->wdata.resize(1); + ref(session[fd]->wdata.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ShowWarning("login_parse: Invalid packet size (%d). Could not update password for user" CL_WHITE"<%s>" CL_RESET".\n", size, escaped_name); + do_close_login(sd, fd); + return 0; + } + + char* buff2 = &session[fd]->rdata[0]; + std::string updated_password(buff2, buff2 + 16); + char escaped_updated_password[16 * 2 + 1]; + Sql_EscapeString(SqlHandle, escaped_updated_password, updated_password.c_str()); + + fmtQuery = "UPDATE accounts SET accounts.timelastmodify = NULL WHERE accounts.id = %d"; + Sql_Query(SqlHandle, fmtQuery, sd->accid); + + fmtQuery = "UPDATE accounts SET accounts.password = PASSWORD('%s') WHERE accounts.id = %d"; + ret = Sql_Query(SqlHandle, fmtQuery, escaped_updated_password, sd->accid); + if (ret == SQL_ERROR) + { + session[fd]->wdata.resize(1); + ref(session[fd]->wdata.data(), 0) = LOGIN_ERROR_CHANGE_PASSWORD; + ShowWarning("login_parse: Error trying to update password in database for user" CL_WHITE"<%s>" CL_RESET".\n", escaped_name); + do_close_login(sd, fd); + return 0; + } + + memset(&session[fd]->wdata[0], 0, 33); + session[fd]->wdata.resize(33); + ref(session[fd]->wdata.data(), 0) = LOGIN_SUCCESS_CHANGE_PASSWORD; + ref(session[fd]->wdata.data(), 1) = sd->accid; + flush_fifo(fd); + do_close_tcp(fd); + + ShowInfo("login_parse: password updated successfully.\n"); + return 0; + } + } + break; default: ShowWarning("login_parse: undefined code:[%d], ip sender:<%s>\n", code, ip2str(session[fd]->client_addr, nullptr)); do_close_login(sd, fd); diff --git a/src/login/login_auth.h b/src/login/login_auth.h index 38d7001dc88..dff7551e4d8 100644 --- a/src/login/login_auth.h +++ b/src/login/login_auth.h @@ -30,14 +30,20 @@ * Login-Server data parse *-------------------------------------------*/ /*main events*/ -#define LOGIN_ATTEMPT 0x10 -#define LOGIN_CREATE 0x20 +#define LOGIN_ATTEMPT 0x10 +#define LOGIN_CREATE 0x20 +#define LOGIN_CHANGE_PASSWORD 0x30 + /*return result*/ -#define LOGIN_SUCCESS 0x01 -#define LOGIN_SUCCESS_CREATE 0x03 +#define LOGIN_SUCCESS 0x01 +#define LOGIN_SUCCESS_CREATE 0x03 +#define LOGIN_SUCCESS_CHANGE_PASSWORD 0x06 + +#define LOGIN_REQUEST_NEW_PASSWORD 0x05 -#define LOGIN_ERROR 0x02 -#define LOGIN_ERROR_CREATE 0x04 +#define LOGIN_ERROR 0x02 +#define LOGIN_ERROR_CREATE 0x04 +#define LOGIN_ERROR_CHANGE_PASSWORD 0x07 extern int32 login_fd; /* From b0f9d2a7cc0c59afe53b8cbb34ca75ff91b128fd Mon Sep 17 00:00:00 2001 From: MrHappyAsthma Date: Tue, 10 Mar 2020 23:46:02 -0700 Subject: [PATCH 2/2] Clarify the warning message text. --- src/login/login_auth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login_auth.cpp b/src/login/login_auth.cpp index d8d651e50fa..68dd07b80c9 100644 --- a/src/login/login_auth.cpp +++ b/src/login/login_auth.cpp @@ -282,7 +282,7 @@ int32 login_parse(int32 fd) { session[fd]->wdata.resize(1); ref(session[fd]->wdata.data(), 0) = LOGIN_ERROR; - ShowWarning("login_parse: unexisting user" CL_WHITE"<%s>" CL_RESET" tried to connect\n", escaped_name); + ShowWarning("login_parse: user" CL_WHITE"<%s>" CL_RESET" could not be found using the provided information. Aborting.\n", escaped_name); do_close_login(sd, fd); return 0; }