Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
AccountMgr.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 "AccountMgr.h"
7#include "CryptoHash.h"
8#include "Config.h"
9#include "DatabaseEnv.h"
10#include "ObjectAccessor.h"
11#include "Player.h"
12#include "SRP6.h"
13#include "Util.h"
14#include "WorldSession.h"
15
17
22
23AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email = "")
24{
25 if (utf8length(username) > MAX_ACCOUNT_STR)
26 return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long
27
28 normalizeString(username);
29 normalizeString(password);
30 normalizeString(email);
31
32 if (GetId(username))
33 return AccountOpResult::AOR_NAME_ALREADY_EXIST; // username does already exist
34
35 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT);
36
37 stmt->setString(0, username);
38 auto [salt, verifier] = SkyFire::Crypto::SRP6::MakeRegistrationData(username, password);
39 stmt->setBinary(1, salt);
40 stmt->setBinary(2, verifier);
41 stmt->setString(3, email);
42 stmt->setString(4, email);
43
44 LoginDatabase.DirectExecute(stmt); // Enforce saving, otherwise AddGroup can fail
45
46 stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT);
47 LoginDatabase.Execute(stmt);
48
50 {
51 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_BOOST);
52 stmt->setBool(0, true);
53 stmt->setUInt32(1, GetId(username));
54
55 LoginDatabase.Execute(stmt);
56 }
57
58 return AccountOpResult::AOR_OK; // everything's fine
59}
60
62{
63 // Check if accounts exists
64 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID);
65 stmt->setUInt32(0, accountId);
66 PreparedQueryResult result = LoginDatabase.Query(stmt);
67
68 if (!result)
70
71 // Obtain accounts characters
72 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
73
74 stmt->setUInt32(0, accountId);
75
76 result = CharacterDatabase.Query(stmt);
77
78 if (result)
79 {
80 do
81 {
82 uint32 guidLow = (*result)[0].GetUInt32();
83 uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER);
84
85 // Kick if player is online
87 {
88 WorldSession* s = p->GetSession();
89 s->KickPlayer(); // mark session to remove at next session list update
90 s->LogoutPlayer(false); // logout player without waiting next session list update
91 }
92
93 Player::DeleteFromDB(guid, accountId, false); // no need to update realm characters
94 } while (result->NextRow());
95 }
96
97 // table realm specific but common for all characters of account for realm
98 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS);
99 stmt->setUInt32(0, accountId);
100 CharacterDatabase.Execute(stmt);
101
102 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA);
103 stmt->setUInt32(0, accountId);
104 CharacterDatabase.Execute(stmt);
105
106 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN);
107 stmt->setUInt32(0, accountId);
108 CharacterDatabase.Execute(stmt);
109
110 SQLTransaction trans = LoginDatabase.BeginTransaction();
111
112 stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT);
113 stmt->setUInt32(0, accountId);
114 trans->Append(stmt);
115
116 stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS);
117 stmt->setUInt32(0, accountId);
118 trans->Append(stmt);
119
120 stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS);
121 stmt->setUInt32(0, accountId);
122 trans->Append(stmt);
123
124 stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_BANNED);
125 stmt->setUInt32(0, accountId);
126 trans->Append(stmt);
127
128 LoginDatabase.CommitTransaction(trans);
129
131}
132
133AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword)
134{
135 // Check if accounts exists
136 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID);
137 stmt->setUInt32(0, accountId);
138 PreparedQueryResult result = LoginDatabase.Query(stmt);
139
140 if (!result)
142
143 if (utf8length(newUsername) > MAX_ACCOUNT_STR)
145
146 if (utf8length(newPassword) > MAX_ACCOUNT_STR)
148
149 normalizeString(newUsername);
150 normalizeString(newPassword);
151
152 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME);
153
154 stmt->setString(0, newUsername);
155 stmt->setUInt32(1, accountId);
156 LoginDatabase.Execute(stmt);
157
158 auto [salt, verifier] = SkyFire::Crypto::SRP6::MakeRegistrationData(newUsername, newPassword);
159 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
160 stmt->setBinary(0, salt);
161 stmt->setBinary(1, verifier);
162 stmt->setUInt32(2, accountId);
163
164 LoginDatabase.Execute(stmt);
165
167}
168
169AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword)
170{
171 std::string username;
172
173 if (!GetName(accountId, username))
174 return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist
175
176 if (utf8length(newPassword) > MAX_ACCOUNT_STR)
178
179 normalizeString(username);
180 normalizeString(newPassword);
181
182 auto [salt, verifier] = SkyFire::Crypto::SRP6::MakeRegistrationData(username, newPassword);
183
184 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
185 stmt->setBinary(0, salt);
186 stmt->setBinary(1, verifier);
187 stmt->setUInt32(2, accountId);;
188
189 LoginDatabase.Execute(stmt);
190
192}
193
194AccountOpResult AccountMgr::ChangeEmail(uint32 accountId, std::string newEmail)
195{
196 std::string username;
197
198 if (!GetName(accountId, username))
199 return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist
200
201 if (utf8length(newEmail) > MAX_EMAIL_STR)
203
204 normalizeString(username);
205 normalizeString(newEmail);
206
207 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EMAIL);
208
209 stmt->setString(0, newEmail);
210 stmt->setUInt32(1, accountId);
211
212 LoginDatabase.Execute(stmt);
213
215}
216
217AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmail)
218{
219 std::string username;
220
221 if (!GetName(accountId, username))
222 return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist
223
224 if (utf8length(newEmail) > MAX_EMAIL_STR)
226
227 normalizeString(username);
228 normalizeString(newEmail);
229
230 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_REG_EMAIL);
231
232 stmt->setString(0, newEmail);
233 stmt->setUInt32(1, accountId);
234
235 LoginDatabase.Execute(stmt);
236
238}
239
240uint32 AccountMgr::GetId(std::string const& username)
241{
243 stmt->setString(0, username);
244 PreparedQueryResult result = LoginDatabase.Query(stmt);
245
246 return (result) ? (*result)[0].GetUInt32() : 0;
247}
248
250{
252 stmt->setUInt32(0, accountId);
253 PreparedQueryResult result = LoginDatabase.Query(stmt);
254
255 return (result) ? AccountTypes((*result)[0].GetUInt8()) : AccountTypes::SEC_PLAYER;
256}
257
259{
261 stmt->setUInt32(0, accountId);
262 stmt->setInt32(1, realmId);
263 PreparedQueryResult result = LoginDatabase.Query(stmt);
264
265 return (result) ? AccountTypes((*result)[0].GetUInt8()) : AccountTypes::SEC_PLAYER;
266}
267
268bool AccountMgr::GetName(uint32 accountId, std::string& name)
269{
270 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID);
271 stmt->setUInt32(0, accountId);
272 PreparedQueryResult result = LoginDatabase.Query(stmt);
273
274 if (result)
275 {
276 name = (*result)[0].GetString();
277 return true;
278 }
279
280 return false;
281}
282
283bool AccountMgr::GetEmail(uint32 accountId, std::string& email)
284{
285 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_EMAIL_BY_ID);
286 stmt->setUInt32(0, accountId);
287 PreparedQueryResult result = LoginDatabase.Query(stmt);
288
289 if (result)
290 {
291 email = (*result)[0].GetString();
292 return true;
293 }
294
295 return false;
296}
297
298bool AccountMgr::CheckPassword(uint32 accountId, std::string password)
299{
300 std::string username;
301
302 if (!GetName(accountId, username))
303 return false;
304
305 normalizeString(username);
306 normalizeString(password);
307
308 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD);
309 stmt->setUInt32(0, accountId);
310 if (PreparedQueryResult result = LoginDatabase.Query(stmt))
311 {
314 if (SkyFire::Crypto::SRP6::CheckLogin(username, password, salt, verifier))
315 return true;
316 }
317
318 return false;
319}
320
321bool AccountMgr::CheckEmail(uint32 accountId, std::string newEmail)
322{
323 std::string oldEmail;
324
325 // We simply return false for a non-existing email
326 if (!GetEmail(accountId, oldEmail))
327 return false;
328
329 normalizeString(oldEmail);
330 normalizeString(newEmail);
331
332 if (strcmp(oldEmail.c_str(), newEmail.c_str()) == 0)
333 return true;
334
335 return false;
336}
337
339{
340 // check character count
341 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS);
342 stmt->setUInt32(0, accountId);
343 PreparedQueryResult result = CharacterDatabase.Query(stmt);
344
345 return (result) ? (*result)[0].GetUInt64() : 0;
346}
347
348bool AccountMgr::normalizeString(std::string& utf8String)
349{
350 wchar_t buffer[MAX_ACCOUNT_STR + 1];
351
352 size_t maxLength = MAX_ACCOUNT_STR;
353 if (!Utf8toWStr(utf8String, buffer, maxLength))
354 return false;
355#ifdef _MSC_VER
356#pragma warning(disable: 4996)
357#endif
358 std::transform(&buffer[0], buffer + maxLength, &buffer[0], wcharToUpperOnlyLatin);
359#ifdef _MSC_VER
360#pragma warning(default: 4996)
361#endif
362
363 return WStrToUtf8(buffer, maxLength, utf8String);
364}
365
367{
368 return gmlevel == AccountTypes::SEC_PLAYER;
369}
370
375
377{
378 return gmlevel == AccountTypes::SEC_CONSOLE;
379}
380
382{
383 ClearRBAC();
384
385 SF_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC");
386 uint32 oldMSTime = getMSTime();
387 uint32 count1 = 0;
388 uint32 count2 = 0;
389 uint32 count3 = 0;
390
391 SF_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading permissions");
392 QueryResult result = LoginDatabase.Query("SELECT id, name FROM rbac_permissions");
393 if (!result)
394 {
395 SF_LOG_INFO("server.loading", ">> Loaded 0 account permission definitions. DB table `rbac_permissions` is empty.");
396 return;
397 }
398
399 do
400 {
401 Field* field = result->Fetch();
402 uint32 id = field[0].GetUInt32();
403 _permissions[id] = new rbac::RBACPermission(id, field[1].GetString());
404 ++count1;
405 } while (result->NextRow());
406
407 SF_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading linked permissions");
408 result = LoginDatabase.Query("SELECT id, linkedId FROM rbac_linked_permissions ORDER BY id ASC");
409 if (!result)
410 {
411 SF_LOG_INFO("server.loading", ">> Loaded 0 linked permissions. DB table `rbac_linked_permissions` is empty.");
412 return;
413 }
414
415 uint32 permissionId = 0;
416 rbac::RBACPermission* permission = NULL;
417
418 do
419 {
420 Field* field = result->Fetch();
421 uint32 newId = field[0].GetUInt32();
422 if (permissionId != newId)
423 {
424 permissionId = newId;
425 permission = _permissions[newId];
426 }
427
428 uint32 linkedPermissionId = field[1].GetUInt32();
429 if (linkedPermissionId == permissionId)
430 {
431 SF_LOG_ERROR("sql.sql", "RBAC Permission %u has itself as linked permission. Ignored", permissionId);
432 continue;
433 }
434 permission->AddLinkedPermission(linkedPermissionId);
435 ++count2;
436 } while (result->NextRow());
437
438 SF_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions");
439 result = LoginDatabase.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC");
440 if (!result)
441 {
442 SF_LOG_INFO("server.loading", ">> Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty.");
443 return;
444 }
445
446 uint8 secId = 255;
447 rbac::RBACPermissionContainer* permissions = NULL;
448 do
449 {
450 Field* field = result->Fetch();
451 uint32 newId = field[0].GetUInt32();
452 if (secId != newId)
453 {
454 secId = newId;
455 permissions = &_defaultPermissions[secId];
456 }
457
458 permissions->insert(field[1].GetUInt32());
459 ++count3;
460 } while (result->NextRow());
461
462 SF_LOG_INFO("server.loading", ">> Loaded %u permission definitions, %u linked permissions and %u default permissions in %u ms", count1, count2, count3, GetMSTimeDiffToNow(oldMSTime));
463}
464
465void AccountMgr::UpdateAccountAccess(rbac::RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId)
466{
467 if (rbac && securityLevel == rbac->GetSecurityLevel())
468 rbac->SetSecurityLevel(securityLevel);
469
470 // Delete old security level from DB
471 if (realmId == -1)
472 {
473 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS);
474 stmt->setUInt32(0, accountId);
475 LoginDatabase.Execute(stmt);
476 }
477 else
478 {
480 stmt->setUInt32(0, accountId);
481 stmt->setUInt32(1, realmId);
482 LoginDatabase.Execute(stmt);
483 }
484
485 // Add new security level
486 if (securityLevel)
487 {
488 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS);
489 stmt->setUInt32(0, accountId);
490 stmt->setUInt8(1, securityLevel);
491 stmt->setInt32(2, realmId);
492 LoginDatabase.Execute(stmt);
493 }
494}
495
497{
498 SF_LOG_TRACE("rbac", "AccountMgr::GetRBACPermission: %u", permissionId);
499 rbac::RBACPermissionsContainer::const_iterator it = _permissions.find(permissionId);
500 if (it != _permissions.end())
501 return it->second;
502
503 return NULL;
504}
505
506bool AccountMgr::HasPermission(uint32 accountId, uint32 permissionId, uint32 realmId)
507{
508 if (!accountId)
509 {
510 SF_LOG_ERROR("rbac", "AccountMgr::HasPermission: Wrong accountId 0");
511 return false;
512 }
513
514 rbac::RBACData rbac(accountId, "", realmId);
515 rbac.LoadFromDB();
516 bool hasPermission = rbac.HasPermission(permissionId);
517
518 SF_LOG_DEBUG("rbac", "AccountMgr::HasPermission [AccountId: %u, PermissionId: %u, realmId: %d]: %u",
519 accountId, permissionId, realmId, hasPermission);
520 return hasPermission;
521}
522
524{
525 for (rbac::RBACPermissionsContainer::iterator itr = _permissions.begin(); itr != _permissions.end(); ++itr)
526 delete itr->second;
527
528 _permissions.clear();
529 _defaultPermissions.clear();
530}
531
533{
534 SF_LOG_TRACE("rbac", "AccountMgr::GetRBACDefaultPermissions: secLevel %u - size: %u", secLevel, uint32(_defaultPermissions[secLevel].size()));
535 return _defaultPermissions[secLevel];
536}
AccountOpResult
Definition AccountMgr.h:14
#define MAX_ACCOUNT_STR
Definition AccountMgr.h:31
#define MAX_EMAIL_STR
Definition AccountMgr.h:32
@ CHAR_DEL_CHARACTER_BAN
@ CHAR_DEL_TUTORIALS
@ CHAR_SEL_SUM_CHARS
@ CHAR_DEL_ACCOUNT_DATA
@ CHAR_SEL_CHARS_BY_ACCOUNT_ID
AccountTypes
Definition Common.h:129
@ SEC_ADMINISTRATOR
Definition Common.h:133
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_TRACE(filterType__,...)
Definition Log.h:131
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
@ LOGIN_GET_EMAIL_BY_ID
@ LOGIN_UPD_EMAIL
@ LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM
@ LOGIN_GET_ACCOUNT_ID_BY_USERNAME
@ LOGIN_UPD_REG_EMAIL
@ LOGIN_SEL_ACCOUNT_BY_ID
@ LOGIN_DEL_ACCOUNT_BANNED
@ LOGIN_UPD_ACCOUNT_BOOST
@ LOGIN_DEL_ACCOUNT_ACCESS
@ LOGIN_UPD_USERNAME
@ LOGIN_GET_GMLEVEL_BY_REALMID
@ LOGIN_UPD_LOGON
@ LOGIN_GET_USERNAME_BY_ID
@ LOGIN_DEL_ACCOUNT
@ LOGIN_INS_REALM_CHARACTERS_INIT
@ LOGIN_INS_ACCOUNT_ACCESS
@ LOGIN_DEL_REALM_CHARACTERS
@ LOGIN_SEL_CHECK_PASSWORD
@ LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL
@ LOGIN_INS_ACCOUNT
@ HIGHGUID_PLAYER
uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h)
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
Definition QueryResult.h:94
Skyfire::AutoPtr< ResultSet, Skyfire::Mutex > QueryResult
Definition QueryResult.h:48
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
Skyfire::AutoPtr< Transaction, Skyfire::Mutex > SQLTransaction
Definition Transaction.h:42
bool WStrToUtf8(wchar_t *wstr, size_t size, std::string &utf8str)
Definition Util.cpp:348
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:305
size_t utf8length(std::string &utf8str)
Definition Util.cpp:271
wchar_t wcharToUpperOnlyLatin(wchar_t wchar)
Definition Util.h:281
static AccountOpResult ChangeRegEmail(uint32 accountId, std::string newEmail)
void LoadRBAC()
static AccountOpResult DeleteAccount(uint32 accountId)
static bool CheckPassword(uint32 accountId, std::string password)
rbac::RBACPermissionsContainer _permissions
Definition AccountMgr.h:81
static AccountOpResult ChangeEmail(uint32 accountId, std::string newEmail)
static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword)
static uint32 GetCharactersCount(uint32 accountId)
void UpdateAccountAccess(rbac::RBACData *rbac, uint32 accountId, uint8 securityLevel, int32 realmId)
static bool IsAdminAccount(AccountTypes gmlevel)
void ClearRBAC()
static AccountTypes GetSecurity(uint32 accountId)
static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword)
static bool normalizeString(std::string &utf8String)
AccountOpResult CreateAccount(std::string username, std::string password, std::string email)
static uint32 GetId(std::string const &username)
rbac::RBACPermissionContainer const & GetRBACDefaultPermissions(uint8 secLevel)
static bool HasPermission(uint32 accountId, uint32 permission, uint32 realmId)
static bool GetEmail(uint32 accountId, std::string &email)
rbac::RBACDefaultPermissionsContainer _defaultPermissions
Definition AccountMgr.h:82
static bool IsConsoleAccount(AccountTypes gmlevel)
static bool IsPlayerAccount(AccountTypes gmlevel)
static bool CheckEmail(uint32 accountId, std::string newEmail)
rbac::RBACPermission const * GetRBACPermission(uint32 permission) const
static bool GetName(uint32 accountId, std::string &name)
Definition Field.h:16
uint32 GetUInt32() const
Definition Field.h:105
static Player * FindPlayer(uint64)
static void DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars=true, bool deleteFinally=false)
Definition Player.cpp:4775
void setBool(const uint8 index, const bool value)
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)
void setUInt8(const uint8 index, const uint8 value)
void setInt32(const uint8 index, const int32 value)
std::array< uint8, SALT_LENGTH > Salt
Definition SRP6.h:18
static bool CheckLogin(std::string const &username, std::string const &password, Salt const &salt, Verifier const &verifier)
Definition SRP6.h:30
static std::pair< Salt, Verifier > MakeRegistrationData(std::string const &username, std::string const &password)
Definition SRP6.cpp:15
std::array< uint8, VERIFIER_LENGTH > Verifier
Definition SRP6.h:20
static constexpr size_t VERIFIER_LENGTH
Definition SRP6.h:19
static constexpr size_t SALT_LENGTH
Definition SRP6.h:17
Player session in the World.
void LogoutPlayer(bool save)
Log the player out
void KickPlayer()
Kick a player out of the World.
void AddLinkedPermission(uint32 id)
Adds a new linked Permission.
Definition RBAC.h:741
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
#define sWorld
Definition World.h:910
@ CONFIG_BOOST_NEW_ACCOUNT
Definition World.h:169
std::set< uint32 > RBACPermissionContainer
Definition RBAC.h:725
LoginDatabaseWorkerPool LoginDatabase
Definition Main.cpp:54