[svn] * Proper SVN structure

--HG--
branch : trunk
This commit is contained in:
Neo2003
2008-10-02 16:23:55 -05:00
commit 9b1c0e006f
2564 changed files with 621124 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** \file
\ingroup realmd
*/
#ifndef _AUTHCODES_H
#define _AUTHCODES_H
enum eAuthResults
{
REALM_AUTH_SUCCESS = 0x00,
REALM_AUTH_FAILURE = 0x01, ///< Unable to connect
REALM_AUTH_UNKNOWN1 = 0x02, ///< Unable to connect
REALM_AUTH_ACCOUNT_BANNED = 0x03, ///< This <game> account has been closed and is no longer available for use. Please go to <site>/banned.html for further information.
REALM_AUTH_NO_MATCH = 0x04, ///< The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see <site> for more information
REALM_AUTH_UNKNOWN2 = 0x05, ///< The information you have entered is not valid. Please check the spelling of the account name and password. If you need help in retrieving a lost or stolen password, see <site> for more information
REALM_AUTH_ACCOUNT_IN_USE = 0x06, ///< This account is already logged into <game>. Please check the spelling and try again.
REALM_AUTH_PREPAID_TIME_LIMIT = 0x07, ///< You have used up your prepaid time for this account. Please purchase more to continue playing
REALM_AUTH_SERVER_FULL = 0x08, ///< Could not log in to <game> at this time. Please try again later.
REALM_AUTH_WRONG_BUILD_NUMBER = 0x09, ///< Unable to validate game version. This may be caused by file corruption or interference of another program. Please visit <site> for more information and possible solutions to this issue.
REALM_AUTH_UPDATE_CLIENT = 0x0a, ///< Downloading
REALM_AUTH_UNKNOWN3 = 0x0b, ///< Unable to connect
REALM_AUTH_ACCOUNT_FREEZED = 0x0c, ///< This <game> account has been temporarily suspended. Please go to <site>/banned.html for further information
REALM_AUTH_UNKNOWN4 = 0x0d, ///< Unable to connect
REALM_AUTH_UNKNOWN5 = 0x0e, ///< Connected.
REALM_AUTH_PARENTAL_CONTROL = 0x0f ///< Access to this account has been blocked by parental controls. Your settings may be changed in your account preferences at <site>
};
enum LoginResult
{
LOGIN_OK = 0x00,
LOGIN_FAILED = 0x01,
LOGIN_FAILED2 = 0x02,
LOGIN_BANNED = 0x03,
LOGIN_UNKNOWN_ACCOUNT = 0x04,
LOGIN_UNKNOWN_ACCOUNT3 = 0x05,
LOGIN_ALREADYONLINE = 0x06,
LOGIN_NOTIME = 0x07,
LOGIN_DBBUSY = 0x08,
LOGIN_BADVERSION = 0x09,
LOGIN_DOWNLOAD_FILE = 0x0A,
LOGIN_FAILED3 = 0x0B,
LOGIN_SUSPENDED = 0x0C,
LOGIN_FAILED4 = 0x0D,
LOGIN_CONNECTED = 0x0E,
LOGIN_PARENTALCONTROL = 0x0F,
LOGIN_LOCKED_ENFORCED = 0x10,
};
// we need to stick to 1 version or half of the stuff will work for someone
// others will not and opposite
// will only support WoW and WoW:TBC 2.4.3 client build 8606...
#define EXPECTED_MANGOS_CLIENT_BUILD {8606, 0}
#endif
+975
View File
@@ -0,0 +1,975 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** \file
\ingroup realmd
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "ByteBuffer.h"
#include "Config/ConfigEnv.h"
#include "Log.h"
#include "RealmList.h"
#include "AuthSocket.h"
#include "AuthCodes.h"
#include <openssl/md5.h>
#include "Auth/Sha1.h"
//#include "Util.h" -- for commented utf8ToUpperOnlyLatin
extern RealmList m_realmList;
extern DatabaseType dbRealmServer;
#define ChunkSize 2048
enum eAuthCmd
{
//AUTH_NO_CMD = 0xFF,
AUTH_LOGON_CHALLENGE = 0x00,
AUTH_LOGON_PROOF = 0x01,
//AUTH_RECONNECT_CHALLENGE = 0x02,
//AUTH_RECONNECT_PROOF = 0x03,
//update srv =4
REALM_LIST = 0x10,
XFER_INITIATE = 0x30,
XFER_DATA = 0x31,
XFER_ACCEPT = 0x32,
XFER_RESUME = 0x33,
XFER_CANCEL = 0x34
};
enum eStatus
{
STATUS_CONNECTED = 0,
STATUS_AUTHED
};
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some paltform
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
typedef struct AUTH_LOGON_CHALLENGE_C
{
uint8 cmd;
uint8 error;
uint16 size;
uint8 gamename[4];
uint8 version1;
uint8 version2;
uint8 version3;
uint16 build;
uint8 platform[4];
uint8 os[4];
uint8 country[4];
uint32 timezone_bias;
uint32 ip;
uint8 I_len;
uint8 I[1];
} sAuthLogonChallenge_C;
//typedef sAuthLogonChallenge_C sAuthReconnectChallenge_C;
/*
typedef struct
{
uint8 cmd;
uint8 error;
uint8 unk2;
uint8 B[32];
uint8 g_len;
uint8 g[1];
uint8 N_len;
uint8 N[32];
uint8 s[32];
uint8 unk3[16];
} sAuthLogonChallenge_S;
*/
typedef struct AUTH_LOGON_PROOF_C
{
uint8 cmd;
uint8 A[32];
uint8 M1[20];
uint8 crc_hash[20];
uint8 number_of_keys;
uint8 unk; // Added in 1.12.x client branch
} sAuthLogonProof_C;
/*
typedef struct
{
uint16 unk1;
uint32 unk2;
uint8 unk3[4];
uint16 unk4[20];
} sAuthLogonProofKey_C;
*/
typedef struct AUTH_LOGON_PROOF_S
{
uint8 cmd;
uint8 error;
uint8 M2[20];
uint32 unk1;
uint32 unk2;
uint16 unk3;
} sAuthLogonProof_S;
typedef struct XFER_INIT
{
uint8 cmd; // XFER_INITIATE
uint8 fileNameLen; // strlen(fileName);
uint8 fileName[1]; // fileName[fileNameLen]
uint64 file_size; // file size (bytes)
uint8 md5[MD5_DIGEST_LENGTH]; // MD5
}XFER_INIT;
typedef struct XFER_DATA
{
uint8 opcode;
uint16 data_size;
uint8 data[ChunkSize];
}XFER_DATA_STRUCT;
typedef struct AuthHandler
{
eAuthCmd cmd;
uint32 status;
bool (AuthSocket::*handler)(void);
}AuthHandler;
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif
/// Launch a thread to transfer a patch to the client
class PatcherRunnable: public ZThread::Runnable
{
public:
PatcherRunnable(class AuthSocket *);
void run();
private:
AuthSocket * mySocket;
};
typedef struct PATCH_INFO
{
uint8 md5[MD5_DIGEST_LENGTH];
}PATCH_INFO;
/// Caches MD5 hash of client patches present on the server
class Patcher
{
public:
typedef std::map<std::string, PATCH_INFO*> Patches;
~Patcher();
Patcher();
Patches::const_iterator begin() const { return _patches.begin(); }
Patches::const_iterator end() const { return _patches.end(); }
void LoadPatchMD5(char*);
bool GetHash(char * pat,uint8 mymd5[16]);
private:
void LoadPatchesInfo();
Patches _patches;
};
const AuthHandler table[] =
{
{ AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge},
{ AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof },
{ REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList },
{ XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept },
{ XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume },
{ XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel }
};
#define AUTH_TOTAL_COMMANDS sizeof(table)/sizeof(AuthHandler)
///Holds the MD5 hash of client patches present on the server
Patcher PatchesCache;
/// Constructor - set the N and g values for SRP6
AuthSocket::AuthSocket(ISocketHandler &h) : TcpSocket(h)
{
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
g.SetDword(7);
_authed = false;
pPatch=NULL;
_accountSecurityLevel = SEC_PLAYER;
}
/// Close patch file descriptor before leaving
AuthSocket::~AuthSocket()
{
if(pPatch)
fclose(pPatch);
}
/// Accept the connection and set the s random value for SRP6
void AuthSocket::OnAccept()
{
sLog.outBasic("Accepting connection from '%s:%d'",
GetRemoteAddress().c_str(), GetRemotePort());
s.SetRand(s_BYTE_SIZE * 8);
}
/// Read the packet from the client
void AuthSocket::OnRead()
{
///- Read the packet
TcpSocket::OnRead();
uint8 _cmd;
while (1)
{
if (!ibuf.GetLength())
return;
///- Get the command out of it
ibuf.SoftRead((char *)&_cmd, 1); // UQ1: No longer exists in new net code ???
//ibuf.Read((char *)&_cmd, 1);
/*char *command = (char *)malloc(1);
ibuf.Read(command, 1);
_cmd = (uint8)command;*/
// assert(0);
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 ibuf length %u", (uint32)_cmd, ibuf.GetLength());
if (!(*this.*table[i].handler)())
{
DEBUG_LOG("Command handler failed for cmd %u ibuf length %u", (uint32)_cmd, ibuf.GetLength());
return;
}
break;
}
}
///- Report unknown commands in the debug log
if (i==AUTH_TOTAL_COMMANDS)
{
DEBUG_LOG("[Auth] got unknown packet %u", (uint32)_cmd);
return;
}
}
}
/// Make the SRP6 calculation from hash in dB
void AuthSocket::_SetVSFields(std::string rI)
{
BigNumber I;
I.SetHexStr(rI.c_str());
//In case of leading zeroes in the rI hash, restore them
uint8 mDigest[SHA_DIGEST_LENGTH];
memset(mDigest,0,SHA_DIGEST_LENGTH);
if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
memcpy(mDigest,I.AsByteArray(),I.GetNumBytes());
std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH);
Sha1Hash sha;
sha.UpdateData(s.AsByteArray(), s.GetNumBytes());
sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
sha.Finalize();
BigNumber x;
x.SetBinary(sha.GetDigest(), sha.GetLength());
v = g.ModExp(x, N);
// No SQL injection (username escaped)
const char *v_hex, *s_hex;
v_hex = v.AsHexStr();
s_hex = s.AsHexStr();
dbRealmServer.PExecute("UPDATE account SET v = '%s', s = '%s' WHERE username = '%s'",v_hex,s_hex, _safelogin.c_str() );
OPENSSL_free((void*)v_hex);
OPENSSL_free((void*)s_hex);
}
/// Logon Challenge command handler
bool AuthSocket::_HandleLogonChallenge()
{
DEBUG_LOG("Entering _HandleLogonChallenge");
if (ibuf.GetLength() < 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);
ibuf.Read((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()) || (ibuf.GetLength() < 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];
// 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);
///- Read the remaining of the packet
ibuf.Read((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);
ByteBuffer pkt;
_login = (const char*)ch->I;
///- 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;
dbRealmServer.escape_string(_safelogin);
///- Check if the client has one of the expected version numbers
bool valid_version=false;
int accepted_versions[]=EXPECTED_MANGOS_CLIENT_BUILD;
for(int i=0;accepted_versions[i];i++)
if(ch->build==accepted_versions[i])
{
valid_version=true;
break;
}
/// <ul><li> if this is a valid version
if(valid_version)
{
pkt << (uint8) 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)
dbRealmServer.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
std::string address = GetRemoteAddress();
dbRealmServer.escape_string(address);
QueryResult *result = dbRealmServer.PQuery( "SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str());
if(result)
{
pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED;
sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!",GetRemoteAddress().c_str ());
delete result;
}
else
{
///- Get the account details from the account table
// No SQL injection (escaped user name)
result = dbRealmServer.PQuery("SELECT sha_pass_hash,id,locked,last_ip,gmlevel FROM account WHERE username = '%s'",_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'", GetRemoteAddress().c_str());
if ( strcmp((*result)[3].GetString(),GetRemoteAddress().c_str()) )
{
DEBUG_LOG("[AuthChallenge] Account IP differs");
pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
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)
{
//set expired bans to inactive
dbRealmServer.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
///- If the account is banned, reject the logon attempt
QueryResult *banresult = dbRealmServer.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = %u AND active = 1", (*result)[1].GetUInt32());
if(banresult)
{
if((*banresult)[0].GetUInt64() == (*banresult)[1].GetUInt64())
{
pkt << (uint8) REALM_AUTH_ACCOUNT_BANNED;
sLog.outBasic("[AuthChallenge] Banned account %s tries to login!",_login.c_str ());
}
else
{
pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED;
sLog.outBasic("[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();
_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)REALM_AUTH_SUCCESS;
// B may be calculated < 32B so we force minnimal 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);
pkt.append(s.AsByteArray(), s.GetNumBytes()); // 32 bytes
pkt.append(unk3.AsByteArray(), 16);
pkt << (uint8)0; // Added in 1.12.x client branch
uint8 secLevel = (*result)[4].GetUInt8();
_accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;
std::string localeName;
localeName.resize(4);
for(int i = 0; i <4; ++i)
localeName[i] = ch->country[4-i-1];
_localization = GetLocaleByName(localeName);
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], _localization);
}
}
delete result;
}
else //no account
{
pkt<< (uint8) REALM_AUTH_NO_MATCH;
}
}
} //valid version
else
///<li> else
{
///- Check if we have the apropriate patch on the disk
char tmp[64];
// No buffer overflow (fixed length of arguments)
sprintf(tmp,"./patches/%d%c%c%c%c.mpq",ch->build,ch->country[3],
ch->country[2],ch->country[1],ch->country[0]);
// This will be closed at the destruction of the AuthSocket (client deconnection)
FILE *pFile=fopen(tmp,"rb");
if(!pFile)
{
pkt << (uint8) AUTH_LOGON_CHALLENGE;
pkt << (uint8) 0x00;
pkt << (uint8) REALM_AUTH_WRONG_BUILD_NUMBER;
DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", ch->build);
DEBUG_LOG("[AuthChallenge] Patch %s not found",tmp);
}else
{ //have patch
pPatch=pFile;
XFER_INIT xferh;
///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it)
if(PatchesCache.GetHash(tmp,(uint8*)&xferh.md5))
{
DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s",tmp);
}
else
{ //calculate patch md5
printf("\n[AuthChallenge] Patch info for %s was not cached.",tmp);
PatchesCache.LoadPatchMD5(tmp);
PatchesCache.GetHash(tmp,(uint8*)&xferh.md5);
}
///- Send a packet to the client with the file length and MD5 hash
uint8 data[2]={AUTH_LOGON_PROOF,REALM_AUTH_UPDATE_CLIENT};
SendBuf((const char*)data,sizeof(data));
memcpy(&xferh,"0\x05Patch",7);
xferh.cmd=XFER_INITIATE;
fseek(pPatch,0,SEEK_END);
xferh.file_size=ftell(pPatch);
SendBuf((const char*)&xferh,sizeof(xferh));
return true;
}
}
/// </ul>
SendBuf((char const*)pkt.contents(), pkt.size());
return true;
}
/// Logon Proof command handler
bool AuthSocket::_HandleLogonProof()
{
DEBUG_LOG("Entering _HandleLogonProof");
///- Read the packet
if (ibuf.GetLength() < sizeof(sAuthLogonProof_C))
return false;
sAuthLogonProof_C lp;
ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C));
///- Continue the SRP6 calculation based on data received from the client
BigNumber A;
A.SetBinary(lp.A, 32);
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);
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))
{
sLog.outBasic("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();
dbRealmServer.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, GetRemoteAddress().c_str(), _localization, _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();
sAuthLogonProof_S proof;
memcpy(proof.M2, sha.GetDigest(), 20);
proof.cmd = AUTH_LOGON_PROOF;
proof.error = 0;
proof.unk1 = 0x00800000;
proof.unk2 = 0x00;
proof.unk3 = 0x00;
SendBuf((char *)&proof, sizeof(proof));
///- Set _authed to true!
_authed = true;
}
else
{
char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0};
SendBuf(data,sizeof(data));
sLog.outBasic("[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
dbRealmServer.PExecute("UPDATE account SET failed_logins = failed_logins + 1 WHERE username = '%s'",_safelogin.c_str());
if(QueryResult *loginfail = dbRealmServer.PQuery("SELECT id, failed_logins FROM account WHERE username = '%s'", _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();
dbRealmServer.PExecute("INSERT INTO account_banned VALUES ('%u',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban',1)",
acc_id, WrongPassBanTime);
sLog.outBasic("[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 = GetRemoteAddress();
dbRealmServer.escape_string(current_ip);
dbRealmServer.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','MaNGOS realmd','Failed login autoban')",
current_ip.c_str(), WrongPassBanTime);
sLog.outBasic("[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;
}
/// %Realm List command handler
bool AuthSocket::_HandleRealmList()
{
DEBUG_LOG("Entering _HandleRealmList");
if (ibuf.GetLength() < 5)
return false;
ibuf.Remove(5);
///- Get the user id (else close the connection)
// No SQL injection (escaped user name)
QueryResult *result = dbRealmServer.PQuery("SELECT id,sha_pass_hash FROM account WHERE username = '%s'",_safelogin.c_str());
if(!result)
{
sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.",_login.c_str());
SetCloseAndDelete();
return false;
}
uint32 id = (*result)[0].GetUInt32();
std::string rI = (*result)[1].GetCppString();
delete result;
///- Update realm list if need
m_realmList.UpdateIfNeed();
///- Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm)
ByteBuffer pkt;
pkt << (uint32) 0;
pkt << (uint16) m_realmList.size();
RealmList::RealmMap::const_iterator i;
for( i = m_realmList.begin(); i != m_realmList.end(); i++ )
{
uint8 AmountOfCharacters;
// No SQL injection. id of realm is controlled by the database.
result = dbRealmServer.PQuery( "SELECT numchars FROM realmcharacters WHERE realmid = '%d' AND acctid='%u'",i->second.m_ID,id);
if( result )
{
Field *fields = result->Fetch();
AmountOfCharacters = fields[0].GetUInt8();
delete result;
}
else
AmountOfCharacters = 0;
uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;
pkt << i->second.icon; // realm type
pkt << lock; // if 1, then realm locked
pkt << i->second.color; // if 2, then realm is offline
pkt << i->first;
pkt << i->second.address;
pkt << i->second.populationLevel;
pkt << AmountOfCharacters;
pkt << i->second.timezone; // realm category
pkt << (uint8) 0x2C; // unk, may be realm number/id?
}
pkt << (uint8) 0x10;
pkt << (uint8) 0x00;
ByteBuffer hdr;
hdr << (uint8) REALM_LIST;
hdr << (uint16)pkt.size();
hdr.append(pkt);
SendBuf((char const*)hdr.contents(), hdr.size());
// Set check field before possible relogin to realm
_SetVSFields(rI);
return true;
}
/// Resume patch transfer
bool AuthSocket::_HandleXferResume()
{
DEBUG_LOG("Entering _HandleXferResume");
///- Check packet length and patch existence
if (ibuf.GetLength()<9 || !pPatch)
{
sLog.outError("Error while resuming patch transfer (wrong packet)");
return false;
}
///- Launch a PatcherRunnable thread starting at given patch file offset
uint64 start;
ibuf.Remove(1);
ibuf.Read((char*)&start,sizeof(start));
fseek(pPatch,start,0);
ZThread::Thread u(new PatcherRunnable(this));
return true;
}
/// Cancel patch transfer
bool AuthSocket::_HandleXferCancel()
{
DEBUG_LOG("Entering _HandleXferCancel");
///- Close and delete the socket
ibuf.Remove(1); //clear input buffer
//ZThread::Thread::sleep(15);
SetCloseAndDelete();
return true;
}
/// Accept patch transfer
bool AuthSocket::_HandleXferAccept()
{
DEBUG_LOG("Entering _HandleXferAccept");
///- Check packet length and patch existence
if (!pPatch)
{
sLog.outError("Error while accepting patch transfer (wrong packet)");
return false;
}
///- Launch a PatcherRunnable thread, starting at the begining of the patch file
ibuf.Remove(1); //clear input buffer
fseek(pPatch,0,0);
ZThread::Thread u(new PatcherRunnable(this));
return true;
}
/// Check if there is lag on the connection to the client
bool AuthSocket::IsLag()
{
return (TCP_BUFSIZE_READ-GetOutputLength()< 2*ChunkSize);
}
PatcherRunnable::PatcherRunnable(class AuthSocket * as)
{
mySocket=as;
}
/// Send content of patch file to the client
void PatcherRunnable::run()
{
XFER_DATA_STRUCT xfdata;
xfdata.opcode = XFER_DATA;
while(!feof(mySocket->pPatch) && mySocket->Ready())
{
///- Wait until output buffer is reasonably empty
while(mySocket->Ready() && mySocket->IsLag())
{
ZThread::Thread::sleep(1);
}
///- And send content of the patch file to the client
xfdata.data_size=fread(&xfdata.data,1,ChunkSize,mySocket->pPatch);
mySocket->SendBuf((const char*)&xfdata,xfdata.data_size +(sizeof(XFER_DATA_STRUCT)-ChunkSize));
}
}
/// Preload MD5 hashes of existing patch files on server
#ifndef _WIN32
#include <sys/dir.h>
#include <errno.h>
void Patcher::LoadPatchesInfo()
{
DIR * dirp;
//int errno;
struct dirent * dp;
dirp = opendir("./patches/");
if(!dirp)
return;
while (dirp)
{
errno = 0;
if ((dp = readdir(dirp)) != NULL)
{
int l=strlen(dp->d_name);
if(l<8)continue;
if(!memcmp(&dp->d_name[l-4],".mpq",4))
LoadPatchMD5(dp->d_name);
}
else
{
if(errno != 0)
{
closedir(dirp);
return;
}
break;
}
}
if(dirp)
closedir(dirp);
}
#else
void Patcher::LoadPatchesInfo()
{
WIN32_FIND_DATA fil;
HANDLE hFil=FindFirstFile("./patches/*.mpq",&fil);
if(hFil==INVALID_HANDLE_VALUE)
return; //no patches were found
LoadPatchMD5(fil.cFileName);
while(FindNextFile(hFil,&fil))
LoadPatchMD5(fil.cFileName);
}
#endif
/// Calculate and store MD5 hash for a given patch file
void Patcher::LoadPatchMD5(char * szFileName)
{
///- Try to open the patch file
std::string path = "./patches/";
path += szFileName;
FILE * pPatch=fopen(path.c_str(),"rb");
sLog.outDebug("Loading patch info from %s\n",path.c_str());
if(!pPatch)
{
sLog.outError("Error loading patch %s\n",path.c_str());
return;
}
///- Calculate the MD5 hash
MD5_CTX ctx;
MD5_Init(&ctx);
uint8* buf = new uint8[512*1024];
while (!feof(pPatch))
{
size_t read = fread(buf, 1, 512*1024, pPatch);
MD5_Update(&ctx, buf, read);
}
delete [] buf;
fclose(pPatch);
///- Store the result in the internal patch hash map
_patches[path] = new PATCH_INFO;
MD5_Final((uint8 *)&_patches[path]->md5 , &ctx);
}
/// Get cached MD5 hash for a given patch file
bool Patcher::GetHash(char * pat,uint8 mymd5[16])
{
for( Patches::iterator i = _patches.begin(); i != _patches.end(); i++ )
if(!stricmp(pat,i->first.c_str () ))
{
memcpy(mymd5,i->second->md5,16);
return true;
}
return false;
}
/// Launch the patch hashing mechanism on object creation
Patcher::Patcher()
{
LoadPatchesInfo();
}
/// Empty and delete the patch map on termination
Patcher::~Patcher()
{
for(Patches::iterator i = _patches.begin(); i != _patches.end(); i++ )
delete i->second;
}
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/// \addtogroup realmd
/// @{
/// \file
#ifndef _AUTHSOCKET_H
#define _AUTHSOCKET_H
#include "Common.h"
#include "Auth/BigNumber.h"
#include "sockets/TcpSocket.h"
#include "sockets/SocketHandler.h"
#include "sockets/ListenSocket.h"
#include "sockets/Utility.h"
#include "sockets/Parse.h"
#include "sockets/Socket.h"
/// Handle login commands
class AuthSocket: public TcpSocket
{
public:
const static int s_BYTE_SIZE = 32;
AuthSocket(ISocketHandler& h);
~AuthSocket();
void OnAccept();
void OnRead();
bool _HandleLogonChallenge();
bool _HandleLogonProof();
bool _HandleRealmList();
//data transfer handle for patch
bool _HandleXferResume();
bool _HandleXferCancel();
bool _HandleXferAccept();
void _SetVSFields(std::string rI);
FILE *pPatch;
bool IsLag();
private:
BigNumber N, s, g, v;
BigNumber b, B;
BigNumber K;
bool _authed;
std::string _login;
std::string _safelogin;
uint8 _localization;
AccountTypes _accountSecurityLevel;
};
#endif
/// @}
+344
View File
@@ -0,0 +1,344 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/// \addtogroup realmd Realm Daemon
/// @{
/// \file
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "RealmList.h"
#include "Config/ConfigEnv.h"
#include "Log.h"
#include "sockets/ListenSocket.h"
#include "AuthSocket.h"
#include "SystemConfig.h"
#include "Util.h"
// Format is YYYYMMDDRR where RR is the change in the conf file
// for that day.
#ifndef _REALMDCONFVERSION
# define _REALMDCONFVERSION 2007062001
#endif
#ifndef _TRINITY_REALM_CONFIG
# define _TRINITY_REALM_CONFIG "trinityrealm.conf"
#endif //_TRINITY_REALM_CONFIG
#ifdef WIN32
#include "ServiceWin32.h"
char serviceName[] = "realmd";
char serviceLongName[] = "MaNGOS realmd service";
char serviceDescription[] = "Massive Network Game Object Server";
/*
* -1 - not in service mode
* 0 - stopped
* 1 - running
* 2 - paused
*/
int m_ServiceStatus = -1;
#endif
bool StartDB(std::string &dbstring);
void UnhookSignals();
void HookSignals();
bool stopEvent = false; ///< Setting it to true stops the server
RealmList m_realmList; ///< Holds the list of realms for this server
DatabaseType dbRealmServer; ///< Accessor to the realm server database
/// Print out the usage string for this program on the console.
void usage(const char *prog)
{
sLog.outString("Usage: \n %s [<options>]\n"
" -c config_file use config_file as configuration file\n\r"
#ifdef WIN32
" Running as service functions:\n\r"
" --service run as service\n\r"
" -s install install service\n\r"
" -s uninstall uninstall service\n\r"
#endif
,prog);
}
/// Launch the realm server
extern int main(int argc, char **argv)
{
///- Command line parsing to get the configuration file name
char const* cfg_file = _TRINITY_REALM_CONFIG;
int c=1;
while( c < argc )
{
if( strcmp(argv[c],"-c") == 0)
{
if( ++c >= argc )
{
sLog.outError("Runtime-Error: -c option requires an input argument");
usage(argv[0]);
return 1;
}
else
cfg_file = argv[c];
}
#ifdef WIN32
////////////
//Services//
////////////
if( strcmp(argv[c],"-s") == 0)
{
if( ++c >= argc )
{
sLog.outError("Runtime-Error: -s option requires an input argument");
usage(argv[0]);
return 1;
}
if( strcmp(argv[c],"install") == 0)
{
if (WinServiceInstall())
sLog.outString("Installing service");
return 1;
}
else if( strcmp(argv[c],"uninstall") == 0)
{
if(WinServiceUninstall())
sLog.outString("Uninstalling service");
return 1;
}
else
{
sLog.outError("Runtime-Error: unsupported option %s",argv[c]);
usage(argv[0]);
return 1;
}
}
if( strcmp(argv[c],"--service") == 0)
{
WinServiceRun();
}
////
#endif
++c;
}
if (!sConfig.SetSource(cfg_file))
{
sLog.outError("Could not find configuration file %s.", cfg_file);
return 1;
}
sLog.outString("Using configuration file %s.", cfg_file);
///- Check the version of the configuration file
uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
if (confVersion < _REALMDCONFVERSION)
{
sLog.outError("*****************************************************************************");
sLog.outError(" WARNING: Your trinityrealm.conf version indicates your conf file is out of date!");
sLog.outError(" Please check for updates, as your current default values may cause");
sLog.outError(" strange behavior.");
sLog.outError("*****************************************************************************");
clock_t pause = 3000 + clock();
while (pause > clock()) {}
}
sLog.outString( "%s (realm-daemon)", _FULLVERSION );
sLog.outString( "<Ctrl-C> to stop.\n" );
/// realmd PID file creation
std::string pidfile = sConfig.GetStringDefault("PidFile", "");
if(!pidfile.empty())
{
uint32 pid = CreatePIDFile(pidfile);
if( !pid )
{
sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() );
return 1;
}
sLog.outString( "Daemon PID: %u\n", pid );
}
///- Initialize the database connection
std::string dbstring;
if(!StartDB(dbstring))
return 1;
///- Get the list of realms for the server
m_realmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20));
if (m_realmList.size() == 0)
{
sLog.outError("No valid realms specified.");
return 1;
}
///- Launch the listening network socket
port_t rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT );
std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0");
SocketHandler h;
ListenSocket<AuthSocket> authListenSocket(h);
if ( authListenSocket.Bind(bind_ip.c_str(),rmport))
{
sLog.outError( "MaNGOS realmd can not bind to %s:%d",bind_ip.c_str(), rmport );
return 1;
}
h.Add(&authListenSocket);
///- Catch termination signals
HookSignals();
///- Handle affinity for multiple processors and process priority on Windows
#ifdef WIN32
{
HANDLE hProcess = GetCurrentProcess();
uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0);
if(Aff > 0)
{
ULONG_PTR appAff;
ULONG_PTR sysAff;
if(GetProcessAffinityMask(hProcess,&appAff,&sysAff))
{
ULONG_PTR curAff = Aff & appAff; // remove non accessible processors
if(!curAff )
{
sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for realmd. Accessible processors bitmask (hex): %x",Aff,appAff);
}
else
{
if(SetProcessAffinityMask(hProcess,curAff))
sLog.outString("Using processors (bitmask, hex): %x", curAff);
else
sLog.outError("Can't set used processors (hex): %x", curAff);
}
}
sLog.outString();
}
bool Prio = sConfig.GetBoolDefault("ProcessPriority", false);
if(Prio)
{
if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS))
sLog.outString("TrinityRealm process priority class set to HIGH");
else
sLog.outError("ERROR: Can't set realmd process priority class.");
sLog.outString();
}
}
#endif
// maximum counter for next ping
uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000));
uint32 loopCounter = 0;
///- Wait for termination signal
while (!stopEvent)
{
h.Select(0, 100000);
if( (++loopCounter) == numLoops )
{
loopCounter = 0;
sLog.outDetail("Ping MySQL to keep connection alive");
delete dbRealmServer.Query("SELECT 1 FROM realmlist LIMIT 1");
}
#ifdef WIN32
if (m_ServiceStatus == 0) stopEvent = true;
while (m_ServiceStatus == 2) Sleep(1000);
#endif
}
///- Wait for the delay thread to exit
dbRealmServer.HaltDelayThread();
///- Remove signal handling before leaving
UnhookSignals();
sLog.outString( "Halting process..." );
return 0;
}
/// Handle termination signals
/** Put the global variable stopEvent to 'true' if a termination signal is caught **/
void OnSignal(int s)
{
switch (s)
{
case SIGINT:
case SIGTERM:
stopEvent = true;
break;
#ifdef _WIN32
case SIGBREAK:
stopEvent = true;
break;
#endif
}
signal(s, OnSignal);
}
/// Initialize connection to the database
bool StartDB(std::string &dbstring)
{
if(!sConfig.GetString("LoginDatabaseInfo", &dbstring))
{
sLog.outError("Database not specified");
return false;
}
sLog.outString("Database: %s", dbstring.c_str() );
if(!dbRealmServer.Initialize(dbstring.c_str()))
{
sLog.outError("Cannot connect to database");
return false;
}
return true;
}
/// Define hook 'OnSignal' for all termination signals
void HookSignals()
{
signal(SIGINT, OnSignal);
signal(SIGTERM, OnSignal);
#ifdef _WIN32
signal(SIGBREAK, OnSignal);
#endif
}
/// Unhook the signals before leaving
void UnhookSignals()
{
signal(SIGINT, 0);
signal(SIGTERM, 0);
#ifdef _WIN32
signal(SIGBREAK, 0);
#endif
}
/// @}
+69
View File
@@ -0,0 +1,69 @@
# Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## Process this file with automake to produce Makefile.in
## Build realm list daemon as standalone program
bin_PROGRAMS = trinity-realm
## Preprocessor flags
trinity_realm_CPPFLAGS = \
$(MYSQL_INCLUDES) \
$(POSTGRE_INCLUDES) \
-I$(top_srcdir)/dep/include \
-I$(top_srcdir)/src/framework \
-I$(top_srcdir)/src/shared \
-D_TRINITY_REALM_CONFIG='"$(sysconfdir)/trinityrealm.conf"'
## Sources
trinity_realm_SOURCES = \
$(srcdir)/AuthCodes.h \
$(srcdir)/AuthSocket.cpp \
$(srcdir)/AuthSocket.h \
$(srcdir)/Main.cpp \
$(srcdir)/RealmList.cpp \
$(srcdir)/RealmList.h
## Convenience libs to add
trinity_realm_LDADD = \
$(top_builddir)/src/shared/libshared.a \
$(top_builddir)/src/framework/libmangosframework.a \
$(top_builddir)/dep/src/sockets/libmangossockets.a \
$(top_builddir)/dep/src/zthread/libZThread.la
## Linker flags
trinity_realm_LDFLAGS = $(MYSQL_LIBS) $(POSTGRE_LIBS) $(ZLIB) $(COMPATLIB) $(SSLLIB)
## Additional files to install
sysconf_DATA = \
trinityrealm.conf.dist
## Prevend overwrite of the config file, if its already installed
install-data-hook:
@list='$(sysconf_DATA)'; for p in $$list; do \
dest=`echo $$p | sed -e s/.dist//`; \
if test -f $(DESTDIR)$(sysconfdir)/$$dest; then \
echo "$@ will not overwrite existing $(DESTDIR)$(sysconfdir)/$$dest"; \
else \
echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$dest"; \
$(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$dest; \
fi; \
done
## Additional files to include when running 'make dist'
# Include realm list daemon configuration
# EXTRA_DIST =
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** \file
\ingroup realmd
*/
#include "Common.h"
#include "RealmList.h"
#include "Policies/SingletonImp.h"
#include "Database/DatabaseEnv.h"
INSTANTIATE_SINGLETON_1( RealmList );
extern DatabaseType dbRealmServer;
RealmList::RealmList( ) : m_UpdateInterval(0), m_NextUpdateTime(time(NULL))
{
}
/// Load the realm list from the database
void RealmList::Initialize(uint32 updateInterval)
{
m_UpdateInterval = updateInterval;
///- Get the content of the realmlist table in the database
UpdateRealms(true);
}
void RealmList::UpdateRealm( uint32 ID, std::string name, std::string address, uint32 port, uint8 icon, uint8 color, uint8 timezone, AccountTypes allowedSecurityLevel, float popu)
{
///- Create new if not exist or update existed
Realm& realm = m_realms[name];
realm.m_ID = ID;
realm.name = name;
realm.icon = icon;
realm.color = color;
realm.timezone = timezone;
realm.allowedSecurityLevel = allowedSecurityLevel;
realm.populationLevel = popu;
///- Append port to IP address.
std::ostringstream ss;
ss << address << ":" << port;
realm.address = ss.str();
}
void RealmList::UpdateIfNeed()
{
// maybe disabled or updated recently
if(!m_UpdateInterval || m_NextUpdateTime > time(NULL))
return;
m_NextUpdateTime = time(NULL) + m_UpdateInterval;
// Clears Realm list
m_realms.clear();
// Get the content of the realmlist table in the database
UpdateRealms(false);
}
void RealmList::UpdateRealms(bool init)
{
sLog.outDetail("Updating Realm List...");
QueryResult *result = dbRealmServer.Query( "SELECT id, name, address, port, icon, color, timezone, allowedSecurityLevel, population FROM realmlist WHERE color <> 3 ORDER BY name" );
///- Circle through results and add them to the realm map
if(result)
{
do
{
Field *fields = result->Fetch();
uint8 allowedSecurityLevel = fields[7].GetUInt8();
UpdateRealm(fields[0].GetUInt32(), fields[1].GetCppString(),fields[2].GetCppString(),fields[3].GetUInt32(),fields[4].GetUInt8(), fields[5].GetUInt8(), fields[6].GetUInt8(), (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), fields[8].GetFloat() );
if(init)
sLog.outString("Added realm \"%s\".", fields[1].GetString());
} while( result->NextRow() );
delete result;
}
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/// \addtogroup realmd
/// @{
/// \file
#ifndef _REALMLIST_H
#define _REALMLIST_H
#include "Common.h"
/// Storage object for a realm
struct Realm
{
std::string name;
std::string address;
uint8 icon;
uint8 color;
uint8 timezone;
uint32 m_ID;
AccountTypes allowedSecurityLevel;
float populationLevel;
};
/// Storage object for the list of realms on the server
class RealmList
{
public:
typedef std::map<std::string, Realm> RealmMap;
RealmList();
~RealmList() {}
void Initialize(uint32 updateInterval);
void UpdateIfNeed();
RealmMap::const_iterator begin() const { return m_realms.begin(); }
RealmMap::const_iterator end() const { return m_realms.end(); }
uint32 size() const { return m_realms.size(); }
private:
void UpdateRealms(bool init);
void UpdateRealm( uint32 ID, std::string name, std::string address, uint32 port, uint8 icon, uint8 color, uint8 timezone, AccountTypes allowedSecurityLevel, float popu);
private:
RealmMap m_realms; ///< Internal map of realms
uint32 m_UpdateInterval;
time_t m_NextUpdateTime;
};
#endif
/// @}
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h" //"afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPICON ICON "TrinityRealm.ico"
/////////////////////////////////////////////////////////////////////////////
// Neutre (Par défaut système) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
#ifdef _WIN32
LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,1,6700,670
PRODUCTVERSION 0,1,6700,670
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x0L
FILETYPE 0x0L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080004b0"
BEGIN
VALUE "FileDescription", "TrinityRealm"
VALUE "FileVersion", "0, 1, 6700, 670"
VALUE "InternalName", "TrinityRealm"
VALUE "LegalCopyright", "Copyright (C) 2008"
VALUE "OriginalFilename", "TrinityRealm.exe"
VALUE "ProductName", "TrinityRealm"
VALUE "ProductVersion", "0, 1, 6700, 670"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x800, 1200
END
END
#endif
+15
View File
@@ -0,0 +1,15 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by TrinityCore.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
+116
View File
@@ -0,0 +1,116 @@
############################################
# MaNGOS realmd configuration file #
############################################
ConfVersion=2007062001
###################################################################################################################
# REALMD SETTINGS
#
# LoginDatabaseInfo
# Database connection settings for the realm server.
# Default: hostname;port;username;password;database
# .;somenumber;username;password;database - use named pipes at Windows
# Named pipes: mySQL required adding "enable-named-pipe" to [mysqld] section my.ini
# .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux
# Unix sockets: experimental, not tested
#
# LogsDir
# Logs directory setting.
# Important: Logs dir must exists, or all logs be disable
# Default: "" - no log directory prefix, if used log names isn't absolute path then logs will be
# stored in current directory for run program.
#
# MaxPingTime
# Settings for maximum database-ping interval (minutes between pings)
#
# RealmServerPort
# Default RealmServerPort
#
# BindIP
# Bind Realm Server to IP/hostname
#
# PidFile
# Realmd daemon PID file
# Default: "" - do not create PID file
# "./realmd.pid" - create PID file (recommended name)
#
# LogLevel
# Server console level of logging
# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
# Default: 0
#
# LogTime
# Include time in server console output [hh:mm:ss]
# Default: 0 (no time)
# 1 (print time)
#
# LogFile
# Logfile name
# Default: "Realmd.log"
# "" - empty name disable creating log file
#
# LogTimestamp
# Logfile with timestamp of server start in name
# Default: 0 - no timestamp in name
# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
#
# LogFileLevel
# Server file level of logging
# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
# Default: 0
#
# LogColors
# Color for messages (format "normal_color details_color debug_color error_color)
# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
# Default: "" - none colors
# "13 7 11 9" - for example :)
#
# UseProcessors
# Used processors mask for multi-processors system (Used only at Windows)
# Default: 0 (selected by OS)
# number (bitmask value of selected processors)
#
# ProcessPriority
# Process proirity setting (Used only at Windows)
# Default: 1 (HIGH)
# 0 (Normal)
#
# RealmsStateUpdateDelay
# Realm list Update up delay (updated at realm list request if delay expired).
# Default: 20
# 0 (Disabled)
#
# WrongPass.MaxCount
# Number of login attemps with wrong password before the account or IP is banned
# Default: 0 (Never ban)
#
# WrongPass.BanTime
# Duration of the ban in seconds (0 means permanent ban)
# Default: 600
#
# WrongPass.BanType
# Ban the IP or account on which login is attempted
# Default: 0 (Ban IP)
# 1 (Ban Account)
#
###################################################################################################################
LoginDatabaseInfo = "127.0.0.1;3306;root;mangos;realmd"
LogsDir = ""
MaxPingTime = 30
RealmServerPort = 3724
BindIP = "0.0.0.0"
PidFile = ""
LogLevel = 0
LogTime = 0
LogFile = "Realmd.log"
LogTimestamp = 0
LogFileLevel = 0
LogColors = ""
UseProcessors = 0
ProcessPriority = 1
RealmsStateUpdateDelay = 20
WrongPass.MaxCount = 0
WrongPass.BanTime = 600
WrongPass.BanType = 0