Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
AuthSocket.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include <algorithm>
7
8#include "AuthCodes.h"
9#include "AuthPatchTransfer.h"
10#include "AuthSocket.h"
11#include "ByteBuffer.h"
12#include "Common.h"
13#include "CryptoRandom.h"
14#include "CryptoHash.h"
17#include "Log.h"
18#include "NetworkAddress.h"
19#include "openssl/crypto.h"
20#include "RealmList.h"
21#include "TOTP.h"
22
34
40
41// GCC has alternative #pragma pack(N) syntax. Old GCC versions do not support
42// pack(push, N), and some platforms do not support it at all.
43#if defined(__GNUC__)
44#pragma pack(1)
45#else
46#pragma pack(push, 1)
47#endif
48
67
77
87
95
103
110
111// GCC has alternative #pragma pack() syntax. Old GCC versions do not support
112// pack(pop), and some platforms do not support it at all.
113#if defined(__GNUC__)
114#pragma pack()
115#else
116#pragma pack(pop)
117#endif
118
130
131#define AUTH_TOTAL_COMMANDS 8
132
133namespace
134{
135 bool ReadAuthChallengeFrame(RealmSocket& socket, std::vector<uint8>& packet, uint16& remaining)
136 {
137 const size_t headerSize = 4;
138 if (socket.GetAvailableBytes() < headerSize)
139 return false;
140
141 std::vector<uint8> header(headerSize);
142 if (!socket.PeekBytes(&header[0], header.size()))
143 return false;
144
145 EndianConvertPtr<uint16>(&header[0]);
146 remaining = ((sAuthLogonChallenge_C*)&header[0])->size;
147
148 if (remaining < sizeof(sAuthLogonChallenge_C) - headerSize)
149 {
150 socket.DiscardBytes(headerSize);
151 return false;
152 }
153
154 if (socket.GetAvailableBytes() < headerSize + remaining)
155 return false;
156
157 packet.resize(headerSize + remaining + 1);
158 packet[packet.size() - 1] = 0;
159
160 if (!socket.ReadBytes(&packet[0], packet.size() - 1))
161 return false;
162
163 EndianConvertPtr<uint16>(&packet[0]);
164 return true;
165 }
166}
167
168// Constructor - set the N and g values for SRP6
174
175// Close patch file descriptor before leaving
177
178// Accept the connection
180{
181 SF_LOG_DEBUG("server.authserver", "'%s:%d' Accepting connection",
182 socket().getRemoteAddress().c_str(), socket().getRemotePort());
183}
184
186{
187 SF_LOG_DEBUG("server.authserver", "AuthSocket::OnClose");
188}
189
190// Read the packet from the client
192{
193#define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3
194 uint32 challengesInARow = 0;
195 uint8 _cmd = 0;
196 while (1)
197 {
198 if (!socket().PeekBytes(&_cmd, 1))
199 return;
200
201 if (_cmd == AUTH_LOGON_CHALLENGE)
202 {
203 ++challengesInARow;
204 if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW)
205 {
206 SF_LOG_WARN("server.authserver", "Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS",
207 challengesInARow, socket().getRemoteAddress().c_str());
208 socket().Close();
209 return;
210 }
211 }
212
213 size_t i;
214
215 // Circle through known commands and call the correct command handler
216 for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i)
217 {
218 if ((uint8)table[i].cmd == _cmd &&
219 (table[i].status == STATUS_CONNECTED || (_authed && table[i].status == STATUS_AUTHED)))
220 {
221 SF_LOG_DEBUG("server.authserver", "Got data for cmd %u recv length %u",
222 (uint32)_cmd, (uint32)socket().GetAvailableBytes());
223
224 if (!(*this.*table[i].handler)())
225 {
226 SF_LOG_DEBUG("server.authserver", "Command handler failed for cmd %u recv length %u",
227 (uint32)_cmd, (uint32)socket().GetAvailableBytes());
228 return;
229 }
230 break;
231 }
232 }
233
234 // Report unknown packets in the error log
235 if (i == AUTH_TOTAL_COMMANDS)
236 {
237 SF_LOG_ERROR("server.authserver", "Got unknown packet from '%s'", socket().getRemoteAddress().c_str());
238 socket().Close();
239 return;
240 }
241 }
242}
243
244// Logon Challenge command handler
246{
247 SF_LOG_DEBUG("server.authserver", "Entering _HandleLogonChallenge");
248 std::vector<uint8> buf;
249 uint16 remaining = 0;
250 if (!ReadAuthChallengeFrame(socket(), buf, remaining))
251 return false;
252
253 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] got header, body is %#04x bytes", remaining);
255
256 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", ch->size);
257 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I);
258
259 // BigEndian code, nop in little endian case
260 // size already converted
262 EndianConvert(ch->build);
267 EndianConvert(ch->ip);
268
269 ByteBuffer pkt;
270
271 _login = (const char*)ch->I;
273 _build = ch->build;
276 _os = (const char*)ch->os;
277
278 if (_os.size() > 4)
279 return false;
280
281 // Restore string order as its byte order is reversed
282 std::reverse(_os.begin(), _os.end());
283
285 pkt << uint8(0x00);
286
287 // Verify that this IP is not in the ip_banned table
288 LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
289
290 std::string const& ip_address = socket().getRemoteAddress();
291 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED);
292 stmt->setString(0, ip_address);
293 PreparedQueryResult result = LoginDatabase.Query(stmt);
294 if (result)
295 {
297 SF_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!",
298 socket().getRemoteAddress().c_str(), socket().getRemotePort());
299 }
300 else
301 {
302 // Get the account details from the account table
303 // No SQL injection (prepared statement)
304 stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE);
305 stmt->setString(0, _login);
306
307 PreparedQueryResult res2 = LoginDatabase.Query(stmt);
308 if (res2)
309 {
310 Field* fields = res2->Fetch();
311
312 // If the IP is 'locked', check that the player comes indeed from the correct IP address
313 bool locked = false;
314 if (fields[1].GetUInt8() == 1) // if ip is locked
315 {
316 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'",
317 _login.c_str(), fields[3].GetCString());
318 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ip_address.c_str());
319
320 if (strcmp(fields[3].GetCString(), ip_address.c_str()) != 0)
321 {
322 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs");
324 locked = true;
325 }
326 else
327 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches");
328 }
329 else
330 {
331 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str());
332 std::string accountCountry = fields[2].GetString();
333 if (accountCountry.empty() || accountCountry == "00")
334 {
335 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country",
336 _login.c_str());
337 }
338
339 if (!accountCountry.empty())
340 {
343
344 stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY);
345 stmt->setUInt32(0, ip);
346 if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt))
347 {
348 std::string loginCountry = (*sessionCountryQuery)[0].GetString();
349 SF_LOG_DEBUG("server.authserver",
350 "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'",
351 _login.c_str(), accountCountry.c_str(), loginCountry.c_str());
352 if (loginCountry != accountCountry)
353 {
354 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs.");
356 locked = true;
357 }
358 else
359 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches");
360 }
361 else
362 SF_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty");
363 }
364 }
365
366 if (!locked)
367 {
368 //set expired bans to inactive
369 LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
370
371 // If the account is banned, reject the logon attempt
372 stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED);
373 stmt->setUInt32(0, fields[1].GetUInt32());
374 PreparedQueryResult banresult = LoginDatabase.Query(stmt);
375 if (banresult)
376 {
377 if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32())
378 {
380 SF_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!",
381 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
382 }
383 else
384 {
386 SF_LOG_DEBUG("server.authserver",
387 "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!",
388 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
389 }
390 }
391 else
392 {
393 _srp6.emplace(_login, fields[5].GetBinary<SkyFire::Crypto::SRP6::SALT_LENGTH>(),
394 fields[6].GetBinary<SkyFire::Crypto::SRP6::VERIFIER_LENGTH>());
395
396 BigNumber unk3;
397 unk3.SetRand(16 * 8);
398
399 // Fill the response packet with the result
402 else
404
405 // B may be calculated < 32B so we force minimal length to 32B
406 pkt.append(_srp6->B);
407 pkt << uint8(1);
408 pkt.append(_srp6->g);
409 pkt << uint8(32);
410 pkt.append(_srp6->N);
411 pkt.append(_srp6->s);
412 pkt.append(unk3.ToByteArray<16>());
413 uint8 securityFlags = 0;
414
415 // Check if token is used
416 _tokenKey = fields[7].GetString();
417 if (!_tokenKey.empty())
418 securityFlags = 4;
419
420 pkt << uint8(securityFlags); // security flags (0x0...0x04)
421
422 if (securityFlags & 0x01) // PIN input
423 {
424 pkt << uint32(0);
425 pkt << uint64(0) << uint64(0); // 16 bytes hash?
426 }
427
428 if (securityFlags & 0x02) // Matrix input
429 {
430 pkt << uint8(0);
431 pkt << uint8(0);
432 pkt << uint8(0);
433 pkt << uint8(0);
434 pkt << uint64(0);
435 }
436
437 if (securityFlags & 0x04) // Security token input
438 pkt << uint8(1);
439
440 AccountTypes secLevel = AccountTypes(fields[4].GetUInt8());
443
444 _localizationName.resize(4);
445 for (int i = 0; i < 4; ++i)
446 _localizationName[i] = ch->country[4 - i - 1];
447
448 SF_LOG_DEBUG("server.authserver",
449 "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)",
450 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(),
451 ch->country[3], ch->country[2], ch->country[1], ch->country[0],
453 }
454 }
455 }
456 else //no account
458 }
459
460 socket().QueueSend(pkt.contents(), pkt.size());
461 return true;
462}
463
464// Logon Proof command handler
466{
467 SF_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
469
470 if (!socket().PeekBytes(&lp, sizeof(sAuthLogonProof_C)))
471 return false;
472
473 bool needsToken = (lp.securityFlags & 0x04) || !_tokenKey.empty();
474 uint8 tokenSize = 0;
475 size_t requiredBytes = sizeof(sAuthLogonProof_C);
476
477 if (needsToken)
478 {
479 if (!socket().PeekBytes(&tokenSize, sizeof(tokenSize), requiredBytes))
480 return false;
481
482 requiredBytes += sizeof(tokenSize) + tokenSize;
483 if (socket().GetAvailableBytes() < requiredBytes)
484 return false;
485 }
486
487 if (!socket().ReadBytes(&lp, sizeof(sAuthLogonProof_C)))
488 return false;
489
490 // If the client has no valid version
492 {
493 // Check if we have the appropriate patch on the disk
494 SF_LOG_DEBUG("network", "Client with invalid version, patching is not implemented");
495 socket().Close();
496 return true;
497 }
498
499 if (std::optional<SessionKey> K = _srp6->VerifyChallengeResponse(lp.A, lp.clientM))
500 {
501 _sessionKey = *K;
502
503 SF_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated",
504 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
505
506 // Update the sessionkey, last_ip, last login time and reset number of failed logins
507 // in the account table for this account.
508 // No SQL injection (escaped user name) and IP address as received by socket
509
510 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
511 stmt->setBinary(0, _sessionKey);
512 stmt->setString(1, socket().getRemoteAddress().c_str());
514 stmt->setString(3, _os);
515 stmt->setString(4, _login);
516 LoginDatabase.DirectExecute(stmt);
517
518 // Finish SRP6 and send the final result to the client
520
521 // Check auth token
522 if (needsToken)
523 {
524 uint8 size = 0;
525 if (!socket().ReadBytes(&size, sizeof(size)))
526 return false;
527
528 std::vector<char> token(size + 1);
529 token[size] = '\0';
530 if (!socket().ReadBytes(&token[0], size))
531 return false;
532
533 unsigned int validToken = TOTP::GenerateToken(_tokenKey);
534 unsigned int incomingToken = atoi(&token[0]);
535 if (validToken != incomingToken)
536 {
538 socket().QueueSend(data, sizeof(data));
539 return false;
540 }
541 }
542
543 if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
544 {
545 sAuthLogonProof_S proof;
546 proof.M2 = M2;
547 proof.cmd = AUTH_LOGON_PROOF;
548 proof.error = 0;
549 proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass.
550 proof.unk2 = 0x00; // SurveyId
551 proof.unk3 = 0x00;
552 socket().QueueSend(&proof, sizeof(proof));
553 }
554 else
555 {
557 proof.M2 = M2;
558 proof.cmd = AUTH_LOGON_PROOF;
559 proof.error = 0;
560 proof.unk2 = 0x00;
561 socket().QueueSend(&proof, sizeof(proof));
562 }
563
564 _authed = true;
565 }
566 else
567 {
569 socket().QueueSend(data, sizeof(data));
570
571 SF_LOG_DEBUG("server.authserver",
572 "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!",
573 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
574
575 uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0);
576 if (MaxWrongPassCount > 0)
577 {
578 //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP
579 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS);
580 stmt->setString(0, _login);
581 LoginDatabase.Execute(stmt);
582
583 stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS);
584 stmt->setString(0, _login);
585
586 if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt))
587 {
588 uint32 failed_logins = (*loginfail)[1].GetUInt32();
589
590 if (failed_logins >= MaxWrongPassCount)
591 {
592 uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600);
593 bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false);
594
595 if (WrongPassBanType)
596 {
597 uint32 acc_id = (*loginfail)[0].GetUInt32();
598 stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED);
599 stmt->setUInt32(0, acc_id);
600 stmt->setUInt32(1, WrongPassBanTime);
601 LoginDatabase.Execute(stmt);
602
603 SF_LOG_DEBUG("server.authserver",
604 "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds "
605 "because it failed to authenticate '%u' times",
606 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(),
607 WrongPassBanTime, failed_logins);
608 }
609 else
610 {
611 stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED);
612 stmt->setString(0, socket().getRemoteAddress());
613 stmt->setUInt32(1, WrongPassBanTime);
614 LoginDatabase.Execute(stmt);
615
616 SF_LOG_DEBUG("server.authserver",
617 "'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds "
618 "because account %s failed to authenticate '%u' times",
619 socket().getRemoteAddress().c_str(), socket().getRemotePort(),
620 socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins);
621 }
622 }
623 }
624 }
625 }
626
627 return true;
628}
629
630// Reconnect Challenge command handler
632{
633 SF_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge");
634 std::vector<uint8> buf;
635 uint16 remaining = 0;
636 if (!ReadAuthChallengeFrame(socket(), buf, remaining))
637 return false;
638
639 SF_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got header, body is %#04x bytes", remaining);
641
642 SF_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got full packet, %#04x bytes", ch->size);
643 SF_LOG_DEBUG("server.authserver", "[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I);
644
645 _login = (const char*)ch->I;
647
648 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY);
649 stmt->setString(0, _login);
650 PreparedQueryResult result = LoginDatabase.Query(stmt);
651
652 // Stop if the account is not found
653 if (!result)
654 {
655 SF_LOG_ERROR("server.authserver",
656 "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.",
657 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
658 socket().Close();
659 return false;
660 }
661
662 // Reinitialize build, expansion and the account securitylevel
663 _build = ch->build;
666 _os = (const char*)ch->os;
667
668 if (_os.size() > 4)
669 return false;
670
671 // Restore string order as its byte order is reversed
672 std::reverse(_os.begin(), _os.end());
673
674 Field* fields = result->Fetch();
675 AccountTypes secLevel = AccountTypes(fields[2].GetUInt8());
678
681
682 // Sending response
683 ByteBuffer pkt;
685 pkt << uint8(0x00);
686 pkt.append(_reconnectProof); // 16 bytes random
687 pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros
688 socket().QueueSend(pkt.contents(), pkt.size());
689 return true;
690}
691
692// Reconnect Proof command handler
694{
695 SF_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof");
696 // Read the packet
698 if (!socket().ReadBytes(&lp, sizeof(sAuthReconnectProof_C)))
699 return false;
700
701 if (_login.empty())
702 return false;
703
704 BigNumber t1;
705 t1.SetBinary(lp.R1, 16);
706
708 sha.UpdateData(_login);
709 sha.UpdateData(t1.ToByteArray<16>());
712 sha.Finalize();
713
714 if (sha.GetDigest() == lp.R2)
715 {
716 // Sending response
717 ByteBuffer pkt;
719 pkt << uint8(0x00);
720 pkt << uint16(0x00); // 2 bytes zeros
721 socket().QueueSend(pkt.contents(), pkt.size());
722 _authed = true;
723 return true;
724 }
725 else
726 {
727 SF_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.",
728 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
729 socket().Close();
730 return false;
731 }
732}
733
735{
736 // Attempt to send best address for client
737 if (clientAddr.IsLoopback())
738 {
739 // Try guessing if realm is also connected locally
740 if (realm.LocalAddress.IsLoopback() || realm.ExternalAddress.IsLoopback())
741 return clientAddr;
742
743 // Assume that user connecting from the machine that authserver is located on
744 // has all realms available in his local network
745 return realm.LocalAddress;
746 }
747
748 // Check if connecting client is in the same network
749 if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask))
750 return realm.LocalAddress;
751
752 // Return external IP
753 return realm.ExternalAddress;
754}
755
756// Realm List command handler
758{
759 SF_LOG_DEBUG("server.authserver", "Entering _HandleRealmList");
760 if (socket().GetAvailableBytes() < 5)
761 return false;
762
763 socket().DiscardBytes(5);
764
765 // Get the user id (else close the connection)
766 // No SQL injection (prepared statement)
768 stmt->setString(0, _login);
769 PreparedQueryResult result = LoginDatabase.Query(stmt);
770 if (!result)
771 {
772 SF_LOG_ERROR("server.authserver",
773 "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.",
774 socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
775 socket().Close();
776 return false;
777 }
778
779 Field* fields = result->Fetch();
780 uint32 id = fields[0].GetUInt32();
781
782 // Update realm list if need
783 sRealmList->UpdateIfNeed();
784
785 Skyfire::Net::Address clientAddr(socket().getRemoteAddress(), socket().getRemotePort());
786
787 // Circle through realms in the RealmList and construct the return packet,
788 // including the number of user characters in each realm.
789 ByteBuffer pkt;
790
791 size_t RealmListSize = 0;
792 for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i)
793 {
794 const Realm& realm = i->second;
795 // don't work with realms which not compatible with the client
796 bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) ||
798
799 // No SQL injection. id of realm is controlled by the database.
800 uint32 flag = realm.flag;
801 RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild);
802 if (!okBuild)
803 {
804 if (!buildInfo)
805 continue;
806
807 flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for
808 }
809
810 if (!buildInfo)
812
813 std::string name = i->first;
815 {
816 std::ostringstream ss;
817 ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.'
818 << buildInfo->BugfixVersion << ')';
819 name = ss.str();
820 }
821
822 // We don't need the port number from which client connects with but the realm's port
823 clientAddr.SetPort(realm.ExternalAddress.GetPort());
824
825 uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;
826
827 uint8 AmountOfCharacters = 0;
828 stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM);
829 stmt->setUInt32(0, realm.m_ID);
830 stmt->setUInt32(1, id);
831 result = LoginDatabase.Query(stmt);
832 if (result)
833 AmountOfCharacters = (*result)[0].GetUInt8();
834
835 pkt << realm.icon; // realm type
836 if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients
837 pkt << lock; // if 1, then realm locked
838 pkt << uint8(flag); // RealmFlags
839 pkt << name;
840 pkt << GetAddressString(GetAddressForClient(realm, clientAddr));
841 pkt << realm.populationLevel;
842 pkt << AmountOfCharacters;
843 pkt << realm.timezone; // realm category
844 if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
845 pkt << uint8(realm.m_ID); // VirtualRealmID
846 else
847 pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients
848
850 {
851 pkt << uint8(buildInfo->MajorVersion);
852 pkt << uint8(buildInfo->MinorVersion);
853 pkt << uint8(buildInfo->BugfixVersion);
854 pkt << uint16(buildInfo->Build);
855 }
856
857 ++RealmListSize;
858 }
859
860 if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
861 {
862 pkt << uint8(0x10);
863 pkt << uint8(0x00);
864 }
865 else // 1.12.1 and 1.12.2 clients
866 {
867 pkt << uint8(0x00);
868 pkt << uint8(0x02);
869 }
870
871 // make a ByteBuffer which stores the RealmList's size
872 ByteBuffer RealmListSizeBuffer;
873 RealmListSizeBuffer << uint32(0);
874 if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients
875 RealmListSizeBuffer << uint16(RealmListSize);
876 else
877 RealmListSizeBuffer << uint32(RealmListSize);
878
879 ByteBuffer hdr;
880 hdr << uint8(REALM_LIST);
881 hdr << uint16(pkt.size() + RealmListSizeBuffer.size());
882 hdr.append(RealmListSizeBuffer); // append RealmList's size buffer
883 hdr.append(pkt); // append realms in the realmlist
884
885 socket().QueueSend(hdr.contents(), hdr.size());
886
887 return true;
888}
889
890// Resume patch transfer
892{
893 SF_LOG_DEBUG("server.authserver", "Entering _HandleXferResume");
894
896 {
898 SF_LOG_ERROR("server.authserver", "Error while resuming patch transfer (wrong packet)");
899 return false;
901 SF_LOG_ERROR("server.authserver", "Client requested unsupported patch transfer resume");
902 socket().Close();
903 return false;
905 break;
906 }
907
908 return false;
909}
910
911// Cancel patch transfer
913{
914 SF_LOG_DEBUG("server.authserver", "Entering _HandleXferCancel");
915
918 return false;
919
920 // Close and delete the socket
921 socket().DiscardBytes(1); // clear input buffer
922 socket().Close();
923
924 return true;
925}
926
927// Accept patch transfer
929{
930 SF_LOG_DEBUG("server.authserver", "Entering _HandleXferAccept");
931
934 {
935 SF_LOG_ERROR("server.authserver", "Client requested unsupported patch transfer accept");
936 socket().Close();
937 return false;
938 }
939
940 return false;
941}
@ WOW_FAIL_SUSPENDED
Definition AuthCodes.h:21
@ WOW_FAIL_UNKNOWN_ACCOUNT
Definition AuthCodes.h:13
@ WOW_FAIL_BANNED
Definition AuthCodes.h:12
@ WOW_FAIL_VERSION_INVALID
Definition AuthCodes.h:18
@ WOW_FAIL_UNLOCKABLE_LOCK
Definition AuthCodes.h:34
@ WOW_FAIL_LOCKED_ENFORCED
Definition AuthCodes.h:25
@ POST_BC_EXP_FLAG
Definition AuthCodes.h:85
@ NO_VALID_EXP_FLAG
Definition AuthCodes.h:87
@ PRE_BC_EXP_FLAG
Definition AuthCodes.h:86
constexpr size_t SESSION_KEY_LENGTH
Definition AuthDefines.h:7
struct AUTH_LOGON_PROOF_S sAuthLogonProof_S
const AuthHandler table[]
eAuthCmd
@ XFER_ACCEPT
@ XFER_CANCEL
@ AUTH_LOGON_CHALLENGE
@ REALM_LIST
@ AUTH_RECONNECT_PROOF
@ AUTH_RECONNECT_CHALLENGE
@ XFER_RESUME
@ AUTH_LOGON_PROOF
#define AUTH_TOTAL_COMMANDS
eStatus
@ STATUS_CONNECTED
@ STATUS_AUTHED
struct AUTH_LOGON_PROOF_C sAuthLogonProof_C
struct AUTH_LOGON_PROOF_S_OLD sAuthLogonProof_S_Old
struct AUTH_RECONNECT_PROOF_C sAuthReconnectProof_C
struct AUTH_LOGON_CHALLENGE_C sAuthLogonChallenge_C
#define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW
void EndianConvertReverse(T &val)
void EndianConvertPtr(void *)
void EndianConvert(T &)
LocaleConstant GetLocaleByName(const std::string &name)
Definition Common.cpp:23
AccountTypes
Definition Common.h:129
@ SEC_ADMINISTRATOR
Definition Common.h:133
#define sConfigMgr
Definition Config.h:64
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_WARN(filterType__,...)
Definition Log.h:140
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
@ LOGIN_INS_ACCOUNT_AUTO_BANNED
@ LOGIN_DEL_EXPIRED_IP_BANS
@ LOGIN_SEL_IP_BANNED
@ LOGIN_SEL_LOGON_COUNTRY
@ LOGIN_UPD_LOGONPROOF
@ LOGIN_SEL_FAILEDLOGINS
@ LOGIN_SEL_NUM_CHARS_ON_REALM
@ LOGIN_UPD_EXPIRED_ACCOUNT_BANS
@ LOGIN_SEL_ACCOUNT_ID_BY_NAME
@ LOGIN_UPD_FAILEDLOGINS
@ LOGIN_INS_IP_AUTO_BANNED
@ LOGIN_SEL_ACCOUNT_BANNED
@ LOGIN_SEL_LOGONCHALLENGE
@ LOGIN_SEL_SESSIONKEY
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
Definition QueryResult.h:94
#define sRealmList
Definition RealmList.h:75
@ REALM_FLAG_OFFLINE
Definition RealmList.h:17
@ REALM_FLAG_SPECIFYBUILD
Definition RealmList.h:18
bool IsIPAddrInNetwork(Skyfire::Net::Address const &net, Skyfire::Net::Address const &addr, Skyfire::Net::Address const &subnetMask)
Checks if address belongs to the a network with specified submask.
Definition Util.cpp:244
std::string GetAddressString(Skyfire::Net::Address const &addr)
Transforms network address into string format "dotted_ip:port".
Definition Util.cpp:237
virtual void OnClose(void)
AuthSocket(RealmSocket &socket)
uint16 _build
Definition AuthSocket.h:60
bool _HandleRealmList()
bool _HandleXferResume()
bool _HandleLogonProof()
virtual void OnAccept(void)
std::optional< SkyFire::Crypto::SRP6 > _srp6
Definition AuthSocket.h:47
bool _HandleReconnectChallenge()
AccountTypes _accountSecurityLevel
Definition AuthSocket.h:62
bool _HandleXferAccept()
static Skyfire::Net::Address const & GetAddressForClient(Realm const &realm, Skyfire::Net::Address const &clientAddr)
bool _HandleXferCancel()
bool _HandleLogonChallenge()
uint8 _expversion
Definition AuthSocket.h:61
std::string _os
Definition AuthSocket.h:59
virtual void OnRead(void)
SessionKey _sessionKey
Definition AuthSocket.h:48
virtual ~AuthSocket(void)
RealmSocket & socket(void)
Definition AuthSocket.h:45
std::string _tokenKey
Definition AuthSocket.h:54
std::array< uint8, 16 > _reconnectProof
Definition AuthSocket.h:49
std::string _login
Definition AuthSocket.h:53
bool _HandleReconnectProof()
RealmSocket & socket_
Definition AuthSocket.h:44
bool _authed
Definition AuthSocket.h:51
std::string _localizationName
Definition AuthSocket.h:58
std::array< uint8, Size > ToByteArray(bool littleEndian=true) const
Definition BigNumber.h:95
void SetRand(int32 numbits)
Definition BigNumber.cpp:70
void SetBinary(uint8 const *bytes, int32 len, bool littleEndian=true)
Definition BigNumber.cpp:44
void append(T value)
Definition ByteBuffer.h:147
size_t size() const
Definition ByteBuffer.h:609
uint8 * contents()
Definition ByteBuffer.h:605
Definition Field.h:16
std::string GetString() const
Definition Field.h:228
std::vector< uint8 > GetBinary() const
Definition Field.cpp:56
char const * GetCString() const
Definition Field.h:213
uint32 GetUInt32() const
Definition Field.h:105
void setString(const uint8 index, const std::string &value)
void setBinary(const uint8 index, const std::vector< uint8 > &value)
void setUInt32(const uint8 index, const uint32 value)
bool PeekBytes(void *buf, size_t len, size_t offset=0) const
size_t GetAvailableBytes(void) const
bool ReadBytes(void *buf, size_t len)
const std::string & getRemoteAddress(void) const
void DiscardBytes(size_t len)
bool QueueSend(void const *buf, size_t len)
void SetPacketLogAccountName(std::string accountName)
std::array< uint8, EPHEMERAL_KEY_LENGTH > EphemeralKey
Definition SRP6.h:22
static SHA1::Digest GetSessionVerifier(EphemeralKey const &A, SHA1::Digest const &clientM, SessionKey const &K)
Definition SRP6.h:35
Digest const & GetDigest() const
Definition CryptoHash.h:93
void UpdateData(uint8 const *data, size_t len)
Definition CryptoHash.h:72
uint16 GetPort() const
void SetPort(uint16 port)
bool IsAcceptedClientBuild(int build)
Definition AuthCodes.cpp:67
RealmBuildInfo const * GetBuildInfo(int build)
Definition AuthCodes.cpp:72
bool IsPreBCAcceptedClientBuild(int build)
Definition AuthCodes.cpp:49
bool IsPostBCAcceptedClientBuild(int build)
Definition AuthCodes.cpp:58
SkyFire::Impl::GenericHash< EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES > SHA1
Definition CryptoHash.h:103
std::array< uint8, S > GetRandomBytes()
PatchTransferDecision EvaluatePatchTransferRequest(PatchTransferAction action, size_t availableBytes)
uint32 ToIPv4NetworkOrder(std::string const &host)
unsigned int GenerateToken(std::string &b32key)
Definition TOTP.cpp:63
LoginDatabaseWorkerPool LoginDatabase
Definition Main.cpp:54
SkyFire::Crypto::SRP6::EphemeralKey A
SkyFire::Crypto::SHA1::Digest clientM
SkyFire::Crypto::SHA1::Digest crc_hash
SkyFire::Crypto::SHA1::Digest M2
SkyFire::Crypto::SHA1::Digest M2
SkyFire::Crypto::SHA1::Digest R3
SkyFire::Crypto::SHA1::Digest R2
bool(AuthSocket::* handler)(void)
eAuthCmd cmd
Skyfire::Net::Address LocalAddress
Definition RealmList.h:32
RealmFlags flag
Definition RealmList.h:36
AccountTypes allowedSecurityLevel
Definition RealmList.h:39
uint8 icon
Definition RealmList.h:35
uint8 timezone
Definition RealmList.h:37
uint32 m_ID
Definition RealmList.h:38
float populationLevel
Definition RealmList.h:40
Skyfire::Net::Address ExternalAddress
Definition RealmList.h:31
uint32 gamebuild
Definition RealmList.h:41
Skyfire::Net::Address LocalSubnetMask
Definition RealmList.h:33