/// Accept the connection and set the s random value for SRP6 void AuthSocket::OnAccept() { BASIC_LOG("Accepting connection from '%s'", get_remote_address().c_str()); if(!AllowedToConnect(get_remote_address().c_str())) { sLog.outBasic("FLOOD! Dropping connection. [%s]", get_remote_address().c_str()); close_connection(); } }
gboolean cockpit_handler_login (CockpitWebServer *server, const gchar *path, GHashTable *headers, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; CockpitCreds *creds; gchar *remote_peer = NULL; GHashTable *out_headers; GIOStream *io_stream; service = cockpit_auth_check_cookie (ws->auth, headers); if (service == NULL) { io_stream = cockpit_web_response_get_stream (response); remote_peer = get_remote_address (io_stream); cockpit_auth_login_async (ws->auth, headers, remote_peer, on_login_complete, g_object_ref (response)); g_free (remote_peer); } else { out_headers = cockpit_web_server_new_table (); creds = cockpit_web_service_get_creds (service); send_login_response (response, creds, out_headers); g_hash_table_unref (out_headers); g_object_unref (service); } /* no response yet */ return TRUE; }
static void handle_login (CockpitHandlerData *data, CockpitWebService *service, const gchar *path, GHashTable *headers, CockpitWebResponse *response) { GHashTable *out_headers; gchar *remote_peer = NULL; GIOStream *io_stream; CockpitCreds *creds; if (service) { out_headers = cockpit_web_server_new_table (); creds = cockpit_web_service_get_creds (service); send_login_response (response, creds, out_headers); g_hash_table_unref (out_headers); } else { io_stream = cockpit_web_response_get_stream (response); remote_peer = get_remote_address (io_stream); cockpit_auth_login_async (data->auth, path, headers, remote_peer, on_login_complete, g_object_ref (response)); g_free (remote_peer); } }
gboolean cockpit_handler_login (CockpitWebServer *server, CockpitWebServerRequestType reqtype, const gchar *path, GHashTable *headers, GBytes *input, CockpitWebResponse *response, CockpitHandlerData *ws) { CockpitWebService *service; gchar *remote_peer = NULL; GIOStream *io_stream; LoginResponse *lr; lr = g_new0 (LoginResponse, 1); lr->response = g_object_ref (response); lr->headers = cockpit_web_server_new_table (); if (reqtype == COCKPIT_WEB_SERVER_REQUEST_GET) { service = cockpit_auth_check_cookie (ws->auth, headers); if (service == NULL) { cockpit_web_response_error (response, 401, NULL, NULL); login_response_free (lr); } else { cockpit_web_service_modules (service, "localhost", on_login_modules, lr); g_object_unref (service); /* no response yet */ } } else if (reqtype == COCKPIT_WEB_SERVER_REQUEST_POST) { io_stream = cockpit_web_response_get_stream (response); remote_peer = get_remote_address (io_stream); cockpit_auth_login_async (ws->auth, headers, input, remote_peer, on_login_complete, lr); g_free (remote_peer); /* no response yet */ } return TRUE; }
/// Accept the connection and set the s random value for SRP6 void AuthSocket::OnAccept() { BASIC_LOG("Accepting connection from '%s'", get_remote_address().c_str()); }
inline Address get_remote_address( SocketPtr const &s ) { return get_remote_address( s->fd() ); }
inline Address get_remote_address( Socket const &s ) { return get_remote_address( s.fd() ); }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; _os = (const char*)ch->os; if(_os.size() > 4) return false; ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); // Starting CMD_AUTH_LOGON_CHALLENGE AuthResult result = WOW_FAIL_UNKNOWN0; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult* qresult = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); if (qresult) { result = WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete qresult; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) //qresult = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str()); qresult = LoginDatabase.PQuery("SELECT a.sha_pass_hash,a.id,a.locked,a.last_ip,aa.gmlevel,a.v,a.s FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = '******'", _safelogin.c_str()); if (qresult) { std::string rI = (*qresult)[0].GetCppString(); uint32 accountId = (*qresult)[1].GetUInt32(); uint8 locked = (*qresult)[2].GetUInt8(); std::string lastIP = (*qresult)[3].GetString(); uint8 secLevel = (*qresult)[4].GetUInt8(); std::string databaseV = (*qresult)[5].GetCppString(); std::string databaseS = (*qresult)[6].GetCppString(); bool blockLogin = false; if (sConfig.GetBoolDefault("MultiIPCheck", false)) { int32 iplimit = sConfig.GetIntDefault("MultiIPLimit", 10); int32 multiIPdelay = sConfig.GetIntDefault("MultiIPPeriodInHours", 48); // If a GM account login ignore MultiIP QueryResult* ipcheck = LoginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s' AND id != %u AND last_login > NOW() - INTERVAL %u HOUR ORDER BY last_login DESC;", get_remote_address().c_str(), accountId, multiIPdelay); if (ipcheck) { // build whitelist std::list<uint32> accountsInWhitelist; accountsInWhitelist.clear(); QueryResult* IDsinwhite = LoginDatabase.PQuery("SELECT whitelist FROM multi_IP_whitelist WHERE whitelist LIKE '%|%u|%'", accountId); if (IDsinwhite) { Tokens whitelistaccounts((*IDsinwhite)[0].GetCppString(),'|'); bool isInWhite = false; for (Tokens::const_iterator itr = whitelistaccounts.begin(); itr != whitelistaccounts.end(); ++itr) accountsInWhitelist.push_back(atoi(*itr)); delete IDsinwhite; } do { Field* pFields =ipcheck->Fetch(); uint32 MultiAccountID = pFields[0].GetUInt32(); bool isInWhite = false; for (std::list<uint32>::const_iterator itr = accountsInWhitelist.begin(); itr != accountsInWhitelist.end(); ++itr) { if (*itr == MultiAccountID) isInWhite = true; } if (!isInWhite) { --iplimit; } } while (ipcheck->NextRow()); delete ipcheck; } /* * default case 10 allowed account with same last_ip * we found 9 account with current ip. NOTE: actual account is not in list * 10 - 9 - 1 * ^ current account * ^ account in list * ^ allowed */ if (iplimit < 1) { DEBUG_LOG("[AuthChallenge] Account '%s' is multi IP - '%s'", _login.c_str(), lastIP.c_str()); result = WOW_FAIL_PARENTCONTROL; blockLogin = true; } } ///- If the IP is 'locked', check that the player comes indeed from the correct IP address if (locked == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), lastIP.c_str()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if (strcmp(lastIP.c_str(),get_remote_address().c_str()) ) { DEBUG_LOG("[AuthChallenge] Account IP differs"); result = WOW_FAIL_SUSPENDED; blockLogin = true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!blockLogin) { ///- If the account is banned, reject the logon attempt QueryResult* banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", accountId); if (banresult) { if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { result = WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned account %s (Id: %u) tries to login!", _login.c_str(), accountId); } else { result = WOW_FAIL_SUSPENDED; BASIC_LOG("[AuthChallenge] Temporarily banned account %s (Id: %u) tries to login!",_login.c_str(), accountId); } delete banresult; } else { DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if (databaseV.size() != s_BYTE_SIZE*2 || databaseS.size() != s_BYTE_SIZE*2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } result = WOW_SUCCESS; _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; BASIC_LOG("[AuthChallenge] account %s (Id: %u) is using '%c%c%c%c' locale (%u)", _login.c_str (), accountId, ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete qresult; } else if (sConfig.GetBoolDefault("AutoRegistration", false)) { if (_safelogin.find_first_of("\t\v\b\f\a\n\r\\\"\'\? <>[](){}_=+-|/!@#$%^&*~`.,\0") == _safelogin.npos && _safelogin.length() > 3) { QueryResult* checkIPresult = LoginDatabase.PQuery("SELECT COUNT(last_ip) FROM account WHERE last_ip = '%s'",get_remote_address().c_str()); int32 regCount = checkIPresult ? (*checkIPresult)[0].GetUInt32() : 0; if (regCount >= sConfig.GetIntDefault("AutoRegistration.Amount", 1)) { BASIC_LOG("[AuthChallenge] Impossible auto-register account %s, number of auto-registered accouts is %u, but allowed only %u", _safelogin.c_str(),regCount, sConfig.GetIntDefault("AutoRegistration.Amount", 1)); // result = WOW_FAIL_DB_BUSY; result = WOW_FAIL_DISCONNECTED; } else { std::transform(_safelogin.begin(), _safelogin.end(), _safelogin.begin(), std::towupper); Sha1Hash sha; sha.Initialize(); sha.UpdateData(_safelogin); sha.UpdateData(":"); sha.UpdateData(_safelogin); sha.Finalize(); std::string encoded; hexEncodeByteArray(sha.GetDigest(), sha.GetLength(), encoded); LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate) VALUES('%s','%s',NOW())", _safelogin.c_str(), encoded.c_str()); _SetVSFields(encoded); BASIC_LOG("[AuthChallenge] account %s auto-registered (count %u)!",_safelogin.c_str(), ++regCount); result = WOW_SUCCESS; _accountSecurityLevel = SEC_PLAYER; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; } if (checkIPresult) delete checkIPresult; } } else result = WOW_FAIL_UNKNOWN_ACCOUNT; } pkt << uint8(CMD_AUTH_LOGON_CHALLENGE); pkt << uint8(0x00); pkt << uint8(result); switch (result) { case WOW_SUCCESS: { b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; MANGOS_ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input { pkt << uint8(1); } break; } case WOW_FAIL_UNKNOWN0: case WOW_FAIL_UNKNOWN1: case WOW_FAIL_SUSPENDED: case WOW_FAIL_BANNED: case WOW_FAIL_UNKNOWN_ACCOUNT: case WOW_FAIL_INCORRECT_PASSWORD: case WOW_FAIL_ALREADY_ONLINE: case WOW_FAIL_NO_TIME: case WOW_FAIL_DB_BUSY: case WOW_FAIL_VERSION_INVALID: case WOW_FAIL_VERSION_UPDATE: case WOW_FAIL_INVALID_SERVER: case WOW_FAIL_FAIL_NOACCESS: case WOW_SUCCESS_SURVEY: case WOW_FAIL_PARENTCONTROL: case WOW_FAIL_LOCKED_ENFORCED: case WOW_FAIL_TRIAL_ENDED: case WOW_FAIL_USE_BATTLENET: case WOW_FAIL_TOO_FAST: case WOW_FAIL_CHARGEBACK: case WOW_FAIL_GAME_ACCOUNT_LOCKED: case WOW_FAIL_INTERNET_GAME_ROOM_WITHOUT_BNET: case WOW_FAIL_UNLOCKABLE_LOCK: case WOW_FAIL_DISCONNECTED: break; default: BASIC_LOG("[AuthChallenge] unknown CMD_AUTH_LOGON_CHALLENGE execution result %u!", result); break; } send((char const*)pkt.contents(), pkt.size()); return true; }
/// Read the packet from the client void AuthSocket::OnRead() { #define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3 uint32 challengesInARow = 0; uint8 _cmd; while (1) { if (!recv_soft((char*)&_cmd, 1)) return; if (_cmd == CMD_AUTH_LOGON_CHALLENGE) { ++challengesInARow; if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW) { DETAIL_LOG("Got %u CMD_AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS", challengesInARow, get_remote_address().c_str()); close_connection(); return; } } size_t i; ///- Circle through known commands and call the correct command handler for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i) { if ((uint8)table[i].cmd == _cmd && (table[i].status == STATUS_CONNECTED || (_authed && table[i].status == STATUS_AUTHED))) { DEBUG_LOG("[Auth] got data for cmd %u recv length %u", (uint32)_cmd, (uint32)recv_len()); if (!(*this.*table[i].handler)()) { DEBUG_LOG("Command handler failed for cmd %u recv length %u", (uint32)_cmd, (uint32)recv_len()); return; } break; } } ///- Report unknown commands in the debug log if (i == AUTH_TOTAL_COMMANDS) { DEBUG_LOG("[Auth] got unknown packet %u", (uint32)_cmd); return; } } }
JNIEXPORT void JNICALL Java_org_iotivity_ca_service_RMInterface_RMGetNetworkInfomation(JNIEnv *env, jobject obj) { LOGI("RMGetNetworkInfomation"); if (!env || !obj) { LOGI("Invalid input parameter"); return; } CAEndpoint_t *tempInfo = NULL; uint32_t tempSize = 0; CAResult_t res = CAGetNetworkInformation(&tempInfo, &tempSize); if (CA_STATUS_OK != res) { LOGE("Could not start get network information"); free(tempInfo); return; } LOGI("################## Network Information #######################"); callback("######## Network Information", "#######"); LOGI("Network info total size is %d", tempSize); uint32_t index; for (index = 0; index < tempSize; index++) { res = get_remote_address(tempInfo[index].addr); if (CA_STATUS_OK != res) { free(tempInfo); return; } if (NULL != g_responseListenerObject) { char networkInfo[NETWORK_INFO_LENGTH]; LOGI("Type: %d", tempInfo[index].adapter); sprintf(networkInfo, "%d",tempInfo[index].adapter); callback("Type :", networkInfo); if (CA_ADAPTER_IP == tempInfo[index].adapter) { LOGI("Port: %d", tempInfo[index].port); sprintf(networkInfo, "%d",tempInfo[index].port); callback("Port: ", networkInfo); } LOGI("Secured: %d", (tempInfo[index].flags & CA_SECURE)); LOGI("Address: %s", g_remoteAddress); callback("Address: ", g_remoteAddress); free(g_remoteAddress); } if (tempInfo[index].flags & CA_SECURE) { g_localSecurePort = tempInfo[index].port; } } // free free(tempInfo); LOGI("##############################################################"); }
void response_handler(const CAEndpoint_t* object, const CAResponseInfo_t* responseInfo) { if (!object || !responseInfo) { LOGE("Invalid input parameter"); return; } CAResult_t res = get_remote_address(object->addr); if (CA_STATUS_OK != res) { return; } LOGI("##########Received response from remote device #############"); LOGI("Uri: %s", responseInfo->info.resourceUri); LOGI("Remote Address: %s", g_remoteAddress); LOGI("Remote Port: %d", object->port); LOGI("response result: %d", responseInfo->result); LOGI("Data: %s", responseInfo->info.payload); LOGI("Token: %s", responseInfo->info.token); LOGI("MessageType: %d", responseInfo->info.type); if (NULL != g_responseListenerObject) { uint32_t len = 0; if (NULL != responseInfo->info.resourceUri) { len = strlen(responseInfo->info.resourceUri); char *cloneUri = (char *) malloc(sizeof(char) * (len + 1)); if (NULL == cloneUri) { LOGE("cloneUri Out of memory"); free(g_remoteAddress); return; } memcpy(cloneUri, responseInfo->info.resourceUri, len + 1); callback("Uri: ", cloneUri); free(cloneUri); } len = strlen(g_remoteAddress); char *cloneRemoteAddress = (char *) malloc(sizeof(char) * (len + 1)); if (NULL == cloneRemoteAddress) { LOGE("cloneRemoteAddress Out of memory"); free(g_remoteAddress); return; } memcpy(cloneRemoteAddress, g_remoteAddress, len + 1); callback("Remote Address: ", cloneRemoteAddress); free(cloneRemoteAddress); free(g_remoteAddress); char portInfo[PORT_LENGTH] = { 0, }; sprintf(portInfo, "%d", object->port); callback("Remote Port: ", portInfo); if (NULL != responseInfo->info.payload && responseInfo->info.payloadSize) { len = responseInfo->info.payloadSize; char *clonePayload = (char *) malloc(len + 1); if (NULL == clonePayload) { LOGE("clonePayload Out of memory"); return; } memcpy(clonePayload, responseInfo->info.payload, len); clonePayload[len] = '\0'; callback("Data: ", clonePayload); free(clonePayload); } } if (responseInfo->info.options) { uint32_t len = responseInfo->info.numOptions; uint32_t i; for (i = 0; i < len; i++) { LOGI("Option %d", i + 1); LOGI("ID : %d", responseInfo->info.options[i].optionID); LOGI("Data[%d]: %s", responseInfo->info.options[i].optionLength, responseInfo->info.options[i].optionData); if (NULL != g_responseListenerObject) { char optionInfo[OPTION_INFO_LENGTH] = { 0, }; sprintf(optionInfo, "Num[%d] - ID : %d, Option Length : %d", i + 1, responseInfo->info.options[i].optionID, responseInfo->info.options[i].optionLength); callback("Option info: ", optionInfo); size_t optionDataLen = strlen(responseInfo->info.options[i].optionData); char *cloneOptionData = (char *) malloc(sizeof(char) * (optionDataLen + 1)); if (NULL == cloneOptionData) { LOGE("cloneOptionData Out of memory"); return; } memcpy(cloneOptionData, responseInfo->info.options[i].optionData, optionDataLen + 1); callback("Option Data: ", cloneOptionData); free(cloneOptionData); } } } LOGI("############################################################"); //Check if this has secure communication information if (responseInfo->info.payload && CA_ADAPTER_IP == object->adapter) { uint32_t securePort = get_secure_information(responseInfo->info.payload); if (0 < securePort) //Set the remote endpoint secure details and send response { LOGI("This is secure resource..."); } } }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult *result = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); if (result) { pkt << (uint8)WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete result; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) <<<<<<< HEAD:src/realmd/AuthSocket.cpp result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'",_safelogin.c_str ()); =======
/// Accept the connection and set the s random value for SRP6 void AuthSocket::OnAccept() { sLog.outBasic("Accepting connection from '%s'", get_remote_address().c_str()); }
int process_opts(int argc, char **argv, std::vector<std::string>& addresses, int& local_index, int& clients, std::string& target_dir, int& levels, int& num_dirs, int& num_files, std::string& data_output) { // some default values levels = 2; clients = 1; num_dirs = 5; num_files = 3; local_index = -1; int c; while (-1 != (c = getopt(argc, argv, "a:p:c:t:l:d:f:o:h"))) { switch(c) { case 'a': { std::string text(optarg); std::size_t start = 0, end = 0; while ((end = text.find(',', start)) != std::string::npos) { try { std::string s = text.substr(start, end - start); if (s.length() > 0) { std::string addr = get_remote_address(s); addresses.push_back(addr); } } catch (std::exception e) { std::cout << "Invalid option for -a" << std::endl; print_usage(); return -1; } start = end + 1; } std::string s = text.substr(start); if (s.length() > 0) { std::string addr = get_remote_address(s); addresses.push_back(addr); } } break; case 'p': #ifdef __GXX_EXPERIMENTAL_CXX0X__ local_index = std::stoi(std::string(optarg)); #else local_index = stoi(std::string(optarg)); #endif break; case 'c': #ifdef __GXX_EXPERIMENTAL_CXX0X__ clients = std::stoi(std::string(optarg)); #else clients = stoi(std::string(optarg)); #endif break; case 't': target_dir = optarg; break; case 'l': #ifdef __GXX_EXPERIMENTAL_CXX0X__ levels = std::stoi(std::string(optarg)); #else levels = stoi(std::string(optarg)); #endif break; case 'd': #ifdef __GXX_EXPERIMENTAL_CXX0X__ num_dirs = std::stoi(std::string(optarg)); #else num_dirs = stoi(std::string(optarg)); #endif break; case 'f': #ifdef __GXX_EXPERIMENTAL_CXX0X__ num_files = std::stoi(std::string(optarg)); #else num_files = stoi(std::string(optarg)); #endif break; case 'o': data_output = optarg; break; case 'h': case '?': default: print_usage(); break; } } if (0 == target_dir.size()) { std::cout << "Must specify target directory in option -t" << std::endl; print_usage(); return -1; } if (levels < 1) { std::cout << "Invalid for option -l" << std::endl; print_usage(); return -1; } if (0 == addresses.size()) { #ifdef __GXX_EXPERIMENTAL_CXX0X__ addresses.push_back(std::string("127.0.0.1:") + std::to_string(DEFAULT_PORT)); #else addresses.push_back(std::string("127.0.0.1:") + to_string(DEFAULT_PORT)); #endif } if (addresses.size() > 1 && local_index < 0) { std::cout << "Local index must be specified to identify one of addresses for local server" << std::endl; print_usage(); return -1; } if (addresses.size() < 2 && local_index < 0) { local_index = 0; } if (local_index >= addresses.size()) { std::cout << "Local index must identify one of addresses" << std::endl; print_usage(); return -1; } if (clients < 1) { std::cout << "Invalid option for -c" << std::endl; print_usage(); return -1; } std::cout << "Benchmark setup" << std::endl; std::cout << " Threads per server: " << clients << std::endl; std::cout << " Number of server(s): " << addresses.size() << std::endl; std::cout << " Server(s): "; #ifdef __GXX_EXPERIMENTAL_CXX0X__ for (auto& s : addresses) { #else for (int i = 0; i < addresses.size(); i++) { std::string& s = addresses[i]; #endif std::cout << s << " "; } std::cout << std::endl; std::cout << " Number of directory levels: " << levels << std::endl; std::cout << " Number of directores per level: " << num_dirs << std::endl; std::cout << " Number of files per level: " << num_files << std::endl; std::cout << " Benchmark target directory: " << target_dir << std::endl; return 0; }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(*((uint32*)(&ch->ip[0]))); std::stringstream tmpLocalIp; tmpLocalIp << (uint32)ch->ip[0] << "." << (uint32)ch->ip[1] << "." << (uint32)ch->ip[2] << "." << (uint32)ch->ip[3]; localIp_ = tmpLocalIp.str(); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; operatingSystem_ = (const char*)ch->os; // Restore string order as its byte order is reversed std::reverse(operatingSystem_.begin(), operatingSystem_.end()); if (operatingSystem_.size() > 4 || (operatingSystem_ != "Win" && operatingSystem_ != "OSX" && (sRealmList.ChatboxOsName == "" || operatingSystem_ != sRealmList.ChatboxOsName))){ sLog.outLog(LOG_WARDEN, "Client %s got unsupported operating system (%s)", _login.c_str(), operatingSystem_.c_str()); return false; } ///- Normalize account name //utf8ToUpperOnlyLatin(_login); -- client already send account in expected form //Escape the user login to avoid further SQL injection //Memory will be freed on AuthSocket object destruction _safelogin = _login; AccountsDatabase.escape_string(_safelogin); pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; std::string address = get_remote_address(); #ifdef REGEX_NAMESPACE for (PatternList::const_iterator i = pattern_banned.begin(); i != pattern_banned.end(); ++i) { if (REGEX_NAMESPACE::regex_match(address.c_str(), i->first) && REGEX_NAMESPACE::regex_match(localIp_.c_str(), i->second)) { pkt<< (uint8) WOW_FAIL_UNKNOWN_ACCOUNT; send((char const*)pkt.contents(), pkt.size()); return true; } } #endif ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) AccountsDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); AccountsDatabase.escape_string(address); //Delete ViP AccountsDatabase.Execute("UPDATE account_permissions SET permission_mask = 1 WHERE unsetdate<=UNIX_TIMESTAMP() AND unsetdate<>setdate"); QueryResultAutoPtr result = AccountsDatabase.PQuery("SELECT * FROM ip_banned WHERE ip = '%s'", address.c_str()); if (result) // ip banned { sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); pkt << uint8(WOW_FAIL_BANNED); send((char const*)pkt.contents(), pkt.size()); return true; } ///- Get the account details from the account table // No SQL injection (escaped user name) result = AccountsDatabase.PQuery("SELECT pass_hash, account.account_id, account_state_id, last_ip, permission_mask, email " "FROM account JOIN account_permissions ON account.account_id = account_permissions.account_id " "WHERE username = '******'", _safelogin.c_str()); if (!result) // account not exists { pkt<< uint8(WOW_FAIL_UNKNOWN_ACCOUNT); send((char const*)pkt.contents(), pkt.size()); return true; } Field * fields = result->Fetch(); ///- If the IP is 'locked', check that the player comes indeed from the correct IP address switch (fields[2].GetUInt8()) { case ACCOUNT_STATE_IP_LOCKED: { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if (strcmp(fields[4].GetString(), get_remote_address().c_str())) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) WOW_FAIL_LOCKED_ENFORCED; send((char const*)pkt.contents(), pkt.size()); return true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } break; } case ACCOUNT_STATE_FROZEN: { pkt << uint8(WOW_FAIL_SUSPENDED); send((char const*)pkt.contents(), pkt.size()); return true; } default: DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip or frozen", _login.c_str()); break; } ///- If the account is banned, reject the logon attempt QueryResultAutoPtr banresult = AccountsDatabase.PQuery("SELECT punishment_date, expiration_date " "FROM account_punishment " "WHERE account_id = '%u' AND punishment_type_id = '%u' AND (punishment_date = expiration_date OR expiration_date > UNIX_TIMESTAMP())", (*result)[1].GetUInt32(), PUNISHMENT_BAN); if (banresult) { if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << uint8(WOW_FAIL_BANNED); sLog.outBasic("[AuthChallenge] Banned account %s tries to login!", _login.c_str ()); } else { pkt << uint8(WOW_FAIL_SUSPENDED); sLog.outBasic("[AuthChallenge] Temporarily banned account %s tries to login!", _login.c_str ()); } send((char const*)pkt.contents(), pkt.size()); return true; } QueryResultAutoPtr emailbanresult = AccountsDatabase.PQuery("SELECT email FROM email_banned WHERE email = '%s'", (*result)[5].GetString()); if (emailbanresult) { pkt << uint8(WOW_FAIL_BANNED); sLog.outBasic("[AuthChallenge] Account %s with banned email %s tries to login!", _login.c_str (), (*emailbanresult)[0].GetString()); send((char const*)pkt.contents(), pkt.size()); return true; } ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = fields[0].GetCppString(); _SetVSFields(rI); b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); ///- Fill the response packet with the result pkt << uint8(WOW_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input pkt << uint8(1); accountPermissionMask_ = fields[4].GetUInt64(); _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4-i-1]; sLog.outBasic("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); send((char const*)pkt.contents(), pkt.size()); return true; }
/// Logon Challenge command handler bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); if (recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); recv((char*)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C*)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (recv_len() < remaining)) return false; // No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); buf[buf.size() - 1] = 0; sAuthLogonChallenge_C* ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet recv((char*)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); // BigEndian code, nop in little endian case // size already converted EndianConvert(*((uint32*)(&ch->gamename[0]))); EndianConvert(ch->build); EndianConvert(*((uint32*)(&ch->platform[0]))); EndianConvert(*((uint32*)(&ch->os[0]))); EndianConvert(*((uint32*)(&ch->country[0]))); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); ByteBuffer pkt; _login = (const char*)ch->I; _build = ch->build; ///- Normalize account name // utf8ToUpperOnlyLatin(_login); -- client already send account in expected form // Escape the user login to avoid further SQL injection // Memory will be freed on AuthSocket object destruction _safelogin = _login; LoginDatabase.escape_string(_safelogin); pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; ///- Verify that this IP is not in the ip_banned table // No SQL injection possible (paste the IP address as passed by the socket) std::string address = get_remote_address(); LoginDatabase.escape_string(address); QueryResult* result = LoginDatabase.PQuery("SELECT unbandate FROM ip_banned WHERE " // permanent still banned "(unbandate = bandate OR unbandate > UNIX_TIMESTAMP()) AND ip = '%s'", address.c_str()); if (result) { pkt << (uint8)WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned ip %s tries to login!", get_remote_address().c_str()); delete result; } else { ///- Get the account details from the account table // No SQL injection (escaped user name) result = LoginDatabase.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel,v,s FROM account WHERE username = '******'", _safelogin.c_str()); if (result) { ///- If the IP is 'locked', check that the player comes indeed from the correct IP address bool locked = false; if ((*result)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); DEBUG_LOG("[AuthChallenge] Player address is '%s'", get_remote_address().c_str()); if (strcmp((*result)[3].GetString(), get_remote_address().c_str())) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) WOW_FAIL_SUSPENDED; locked = true; } else { DEBUG_LOG("[AuthChallenge] Account IP matches"); } } else { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); } if (!locked) { ///- If the account is banned, reject the logon attempt QueryResult* banresult = LoginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE " "id = %u AND active = 1 AND (unbandate > UNIX_TIMESTAMP() OR unbandate = bandate)", (*result)[1].GetUInt32()); if (banresult) { if ((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64()) { pkt << (uint8) WOW_FAIL_BANNED; BASIC_LOG("[AuthChallenge] Banned account %s tries to login!", _login.c_str()); } else { pkt << (uint8) WOW_FAIL_SUSPENDED; BASIC_LOG("[AuthChallenge] Temporarily banned account %s tries to login!", _login.c_str()); } delete banresult; } else { ///- Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = (*result)[0].GetCppString(); ///- Don't calculate (v, s) if there are already some in the database std::string databaseV = (*result)[5].GetCppString(); std::string databaseS = (*result)[6].GetCppString(); DEBUG_LOG("database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2, bytes are stored as hexstring if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2) _SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(19 * 8); BigNumber gmod = g.ModExp(b, N); B = ((v * 3) + gmod) % N; MANGOS_ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk3; unk3.SetRand(16 * 8); ///- Fill the response packet with the result pkt << uint8(WOW_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B pkt.append(B.AsByteArray(32), 32); // 32 bytes pkt << uint8(1); pkt.append(g.AsByteArray(), 1); pkt << uint8(32); pkt.append(N.AsByteArray(32), 32); pkt.append(s.AsByteArray(), s.GetNumBytes());// 32 bytes pkt.append(unk3.AsByteArray(16), 16); uint8 securityFlags = 0; pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input { pkt << uint32(0); pkt << uint64(0) << uint64(0); // 16 bytes hash? } if (securityFlags & 0x02) // Matrix input { pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint8(0); pkt << uint64(0); } if (securityFlags & 0x04) // Security token input { pkt << uint8(1); } uint8 secLevel = (*result)[4].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _localizationName.resize(4); for (int i = 0; i < 4; ++i) _localizationName[i] = ch->country[4 - i - 1]; BASIC_LOG("[AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", _login.c_str(), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)); } } delete result; } else // no account { pkt << (uint8) WOW_FAIL_UNKNOWN_ACCOUNT; } } send((char const*)pkt.contents(), pkt.size()); return true; }
/// Logon Proof command handler bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet sAuthLogonProof_C lp; if (!recv((char*)&lp, sizeof(sAuthLogonProof_C))) return false; ///- Check if the client has one of the expected version numbers bool valid_version = FindBuildInfo(_build) != NULL; /// <ul><li> If the client has no valid version if (!valid_version) { if (this->patch_ != ACE_INVALID_HANDLE) return false; ///- Check if we have the apropriate patch on the disk // file looks like: 65535enGB.mpq char tmp[64]; snprintf(tmp, 24, "./patches/%d%s.mpq", _build, _localizationName.c_str()); char filename[PATH_MAX]; if (ACE_OS::realpath(tmp, filename) != NULL) { patch_ = ACE_OS::open(filename, GENERIC_READ | FILE_FLAG_SEQUENTIAL_SCAN); } if (patch_ == ACE_INVALID_HANDLE) { // no patch found ByteBuffer pkt; pkt << (uint8) CMD_AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; pkt << (uint8) WOW_FAIL_VERSION_INVALID; DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); send((char const*)pkt.contents(), pkt.size()); return true; } XFER_INIT xferh; ACE_OFF_T file_size = ACE_OS::filesize(this->patch_); if (file_size == -1) { close_connection(); return false; } if (!PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5)) { // calculate patch md5, happens if patch was added while realmd was running PatchCache::instance()->LoadPatchMD5(tmp); PatchCache::instance()->GetHash(tmp, (uint8*)&xferh.md5); } uint8 data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_VERSION_UPDATE}; send((const char*)data, sizeof(data)); memcpy(&xferh, "0\x05Patch", 7); xferh.cmd = CMD_XFER_INITIATE; xferh.file_size = file_size; send((const char*)&xferh, sizeof(xferh)); return true; } /// </ul> ///- Continue the SRP6 calculation based on data received from the client BigNumber A; A.SetBinary(lp.A, 32); // SRP safeguard: abort if A==0 if (A.isZero()) return false; Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), 20); BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); uint8 t[32]; uint8 t1[16]; uint8 vK[40]; memcpy(t, S.AsByteArray(32), 32); for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2] = sha.GetDigest()[i]; } for (int i = 0; i < 16; ++i) { t1[i] = t[i * 2 + 1]; } sha.Initialize(); sha.UpdateData(t1, 16); sha.Finalize(); for (int i = 0; i < 20; ++i) { vK[i * 2 + 1] = sha.GetDigest()[i]; } K.SetBinary(vK, 40); uint8 hash[20]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), 20); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < 20; ++i) { hash[i] ^= sha.GetDigest()[i]; } BigNumber t3; t3.SetBinary(hash, 20); sha.Initialize(); sha.UpdateData(_login); sha.Finalize(); uint8 t4[SHA_DIGEST_LENGTH]; memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); sha.Initialize(); sha.UpdateBigNumbers(&t3, NULL); sha.UpdateData(t4, SHA_DIGEST_LENGTH); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); BigNumber M; M.SetBinary(sha.GetDigest(), 20); ///- Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(), lp.M1, 20)) { BASIC_LOG("User '%s' successfully authenticated", _login.c_str()); ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); LoginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '******'", K_hex, get_remote_address().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str()); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client sha.Initialize(); sha.UpdateBigNumbers(&A, &M, &K, NULL); sha.Finalize(); SendProof(sha); ///- Set _authed to true! _authed = true; } else { if (_build > 6005) // > 1.12.2 { char data[4] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0}; send(data, sizeof(data)); } else { // 1.x not react incorrectly at 4-byte message use 3 as real error char data[2] = { CMD_AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT}; send(data, sizeof(data)); } BASIC_LOG("[AuthChallenge] account %s tried to login with wrong password!", _login.c_str()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); if (MaxWrongPassCount > 0) { // Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP LoginDatabase.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '******'", _safelogin.c_str()); if (QueryResult* loginfail = LoginDatabase.PQuery("SELECT id, failed_logins FROM account WHERE username = '******'", _safelogin.c_str())) { Field* fields = loginfail->Fetch(); uint32 failed_logins = fields[1].GetUInt32(); if (failed_logins >= MaxWrongPassCount) { uint32 WrongPassBanTime = sConfig.GetIntDefault("WrongPass.BanTime", 600); bool WrongPassBanType = sConfig.GetBoolDefault("WrongPass.BanType", false); if (WrongPassBanType) { uint32 acc_id = fields[0].GetUInt32(); LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)", acc_id, WrongPassBanTime); BASIC_LOG("[AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", _login.c_str(), WrongPassBanTime, failed_logins); } else { std::string current_ip = get_remote_address(); LoginDatabase.escape_string(current_ip); LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); BASIC_LOG("[AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", current_ip.c_str(), WrongPassBanTime, _login.c_str(), failed_logins); } } delete loginfail; } } } return true; }
void request_handler(const CAEndpoint_t* object, const CARequestInfo_t* requestInfo) { if (!object) { LOGE("Remote endpoint is NULL!"); return; } if (!requestInfo) { LOGE("Request info is NULL!"); return; } if ((NULL != g_lastRequestToken) && (NULL != requestInfo->info.token) && (strncmp(g_lastRequestToken, requestInfo->info.token, requestInfo->info.tokenLength) == 0)) { LOGI("token is same. received request of it's own. skip.. "); return; } CAResult_t res = get_remote_address(object->addr); if (CA_STATUS_OK != res) { return; } LOGI("##########received request from remote device #############"); LOGI("Remote Address: %s", g_remoteAddress); LOGI("Remote Port: %d", object->port); LOGI("Uri: %s", requestInfo->info.resourceUri); LOGI("Data: %s", requestInfo->info.payload); LOGI("Token: %s", requestInfo->info.token); LOGI("Code: %d", requestInfo->method); LOGI("MessageType: %d", requestInfo->info.type); if (NULL != g_responseListenerObject) { char *cloneUri = NULL; uint32_t len = 0; if (NULL != requestInfo->info.resourceUri) { len = strlen(requestInfo->info.resourceUri); cloneUri = (char *)malloc(sizeof(char) * (len + 1)); if (NULL == cloneUri) { LOGE("cloneUri Out of memory"); free(g_remoteAddress); return; } memcpy(cloneUri, requestInfo->info.resourceUri, len + 1); callback("Uri: ", cloneUri); } len = strlen(g_remoteAddress); char *cloneRemoteAddress = (char *) malloc(sizeof(char) * (len + 1)); if (NULL == cloneRemoteAddress) { LOGE("cloneRemoteAddress Out of memory"); free(g_remoteAddress); free(cloneUri); return; } memcpy(cloneRemoteAddress, g_remoteAddress, len + 1); callback("Remote Address: ", cloneRemoteAddress); free(cloneRemoteAddress); free(g_remoteAddress); char portInfo[PORT_LENGTH] = { 0, }; sprintf(portInfo, "%d", object->port); callback("Remote Port: ", portInfo); //clone g_clientEndpoint g_clientEndpoint = (CAEndpoint_t *) malloc(sizeof(CAEndpoint_t)); if (NULL == g_clientEndpoint) { LOGE("g_clientEndpoint Out of memory"); free(cloneUri); return; } memcpy(g_clientEndpoint, object, sizeof(CAEndpoint_t)); if (NULL != cloneUri) { len = strlen(cloneUri); g_resourceUri = (char *) malloc(sizeof(char) * (len + 1)); if (NULL == g_resourceUri) { LOGE("g_clientEndpoint->resourceUri Out of memory"); free(g_clientEndpoint); free(cloneUri); return; } memcpy(g_resourceUri, cloneUri, len + 1); free(cloneUri); } //clone g_clientToken len = requestInfo->info.tokenLength; g_clientToken = (char *) malloc(sizeof(char) * len); if (NULL == g_clientToken) { LOGE("g_clientToken Out of memory"); free(g_clientEndpoint); return; } if (NULL != requestInfo->info.token) { memcpy(g_clientToken, requestInfo->info.token, len); g_clientTokenLength = len; } //clone g_clientMsgId g_clientMsgId = requestInfo->info.messageId; if (NULL != requestInfo->info.payload && requestInfo->info.payloadSize > 0) { len = requestInfo->info.payloadSize; char *clonePayload = (char *) malloc(len + 1); if (NULL == clonePayload) { LOGE("clonePayload Out of memory"); free(g_clientEndpoint); return; } memcpy(clonePayload, requestInfo->info.payload, len); clonePayload[len] = '\0'; callback("Data: ", clonePayload); free(clonePayload); } } if (requestInfo->info.options) { uint32_t len = requestInfo->info.numOptions; uint32_t i; LOGI("Option count: %d", requestInfo->info.numOptions); for (i = 0; i < len; i++) { LOGI("Option %d", i + 1); LOGI("ID : %d", requestInfo->info.options[i].optionID); LOGI("Data[%d]: %s", requestInfo->info.options[i].optionLength, requestInfo->info.options[i].optionData); if (NULL != g_responseListenerObject) { char optionInfo[OPTION_INFO_LENGTH] = { 0, }; sprintf(optionInfo, "Num[%d] - ID : %d, Option Length : %d", i + 1, requestInfo->info.options[i].optionID, requestInfo->info.options[i].optionLength); callback("Option info: ", optionInfo); size_t optionDataLen = strlen(requestInfo->info.options[i].optionData); char *cloneOptionData = (char *) malloc(sizeof(char) * (optionDataLen + 1)); if (NULL == cloneOptionData) { LOGE("cloneOptionData Out of memory"); free(g_clientEndpoint); return; } memcpy(cloneOptionData, requestInfo->info.options[i].optionData, optionDataLen + 1); callback("Option Data: ", cloneOptionData); free(cloneOptionData); } } } LOGI("############################################################"); //Check if this has secure communication information if (requestInfo->info.payload && CA_ADAPTER_IP == object->adapter) { uint32_t securePort = get_secure_information(requestInfo->info.payload); if (0 < securePort) //Set the remote endpoint secure details and send response { LOGI("This is secure resource..."); CAEndpoint_t *endpoint = NULL; if (CA_STATUS_OK != CACreateEndpoint(CA_SECURE, object->adapter, object->addr, securePort, &endpoint)) { LOGE("Failed to create duplicate of remote endpoint!"); return; } object = endpoint; } } }