From a0652b789dd8ab69be85291a266dabc5c6d082e7 Mon Sep 17 00:00:00 2001 From: Mark Klara Date: Sun, 12 Jan 2020 00:26:01 -0800 Subject: [PATCH 1/2] Add a simple flow to allow changing user passwords. This is a prerequisite for https://github.com/DarkstarProject/xiloader/issues/7. There is probably some refactoring that could be done in this file to reduce the amount of nested braces and 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 1a6fa09390a..7834971aa59 100644 --- a/src/login/login_auth.cpp +++ b/src/login/login_auth.cpp @@ -102,6 +102,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: @@ -109,8 +112,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) { @@ -210,8 +211,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); @@ -275,6 +274,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. + int32_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 20e61d64562..0d69768fe7f 100644 --- a/src/login/login_auth.h +++ b/src/login/login_auth.h @@ -32,14 +32,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 2c607231e85c82e7010781d211d5a318e31add08 Mon Sep 17 00:00:00 2001 From: Mark Klara Date: Sun, 12 Jan 2020 00:54:29 -0800 Subject: [PATCH 2/2] Fix a warning caused by lossy type coersion. --- 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 7834971aa59..6ecb4b2ad6b 100644 --- a/src/login/login_auth.cpp +++ b/src/login/login_auth.cpp @@ -314,7 +314,7 @@ int32 login_parse(int32 fd) // Packet expects a single password parameter no longer than // 16 bytes. - int32_t size = session[fd]->rdata.size(); + size_t size = session[fd]->rdata.size(); if (size == 0 || size > 16) { session[fd]->wdata.resize(1);