1#include "authmanager.h"
2#include <base/hash_ctxt.h>
3#include <base/system.h>
4#include <engine/shared/config.h>
5#include <game/generated/protocol.h>
6
7#define ADMIN_IDENT "default_admin"
8#define MOD_IDENT "default_mod"
9#define HELPER_IDENT "default_helper"
10
11static MD5_DIGEST HashPassword(const char *pPassword, const unsigned char aSalt[SALT_BYTES])
12{
13 // Hash the password and the salt
14 MD5_CTX Md5;
15 md5_init(ctxt: &Md5);
16 md5_update(ctxt: &Md5, data: (unsigned char *)pPassword, data_len: str_length(str: pPassword));
17 md5_update(ctxt: &Md5, data: aSalt, SALT_BYTES);
18 return md5_finish(ctxt: &Md5);
19}
20
21CAuthManager::CAuthManager()
22{
23 m_aDefault[0] = -1;
24 m_aDefault[1] = -1;
25 m_aDefault[2] = -1;
26 m_Generated = false;
27}
28
29void CAuthManager::Init()
30{
31 size_t NumDefaultKeys = 0;
32 if(g_Config.m_SvRconPassword[0])
33 NumDefaultKeys++;
34 if(g_Config.m_SvRconModPassword[0])
35 NumDefaultKeys++;
36 if(g_Config.m_SvRconHelperPassword[0])
37 NumDefaultKeys++;
38 if(m_vKeys.size() == NumDefaultKeys && !g_Config.m_SvRconPassword[0])
39 {
40 secure_random_password(buffer: g_Config.m_SvRconPassword, length: sizeof(g_Config.m_SvRconPassword), pw_length: 6);
41 AddDefaultKey(Level: AUTHED_ADMIN, pPw: g_Config.m_SvRconPassword);
42 m_Generated = true;
43 }
44}
45
46int CAuthManager::AddKeyHash(const char *pIdent, MD5_DIGEST Hash, const unsigned char *pSalt, int AuthLevel)
47{
48 if(FindKey(pIdent) >= 0)
49 return -1;
50
51 CKey Key;
52 str_copy(dst&: Key.m_aIdent, src: pIdent);
53 Key.m_Pw = Hash;
54 mem_copy(dest: Key.m_aSalt, source: pSalt, SALT_BYTES);
55 Key.m_Level = AuthLevel;
56
57 m_vKeys.push_back(x: Key);
58 return m_vKeys.size() - 1;
59}
60
61int CAuthManager::AddKey(const char *pIdent, const char *pPw, int AuthLevel)
62{
63 // Generate random salt
64 unsigned char aSalt[SALT_BYTES];
65 secure_random_fill(bytes: aSalt, SALT_BYTES);
66 return AddKeyHash(pIdent, Hash: HashPassword(pPassword: pPw, aSalt), pSalt: aSalt, AuthLevel);
67}
68
69void CAuthManager::RemoveKey(int Slot)
70{
71 m_vKeys.erase(position: m_vKeys.begin() + Slot);
72 // Update indices of default keys
73 for(int &Default : m_aDefault)
74 {
75 if(Default == Slot)
76 {
77 Default = -1;
78 }
79 else if(Default > Slot)
80 {
81 --Default;
82 }
83 }
84}
85
86int CAuthManager::FindKey(const char *pIdent) const
87{
88 for(size_t i = 0; i < m_vKeys.size(); i++)
89 if(!str_comp(a: m_vKeys[i].m_aIdent, b: pIdent))
90 return i;
91
92 return -1;
93}
94
95bool CAuthManager::CheckKey(int Slot, const char *pPw) const
96{
97 if(Slot < 0 || Slot >= (int)m_vKeys.size())
98 return false;
99 return m_vKeys[Slot].m_Pw == HashPassword(pPassword: pPw, aSalt: m_vKeys[Slot].m_aSalt);
100}
101
102int CAuthManager::DefaultKey(int AuthLevel) const
103{
104 if(AuthLevel < 0 || AuthLevel > AUTHED_ADMIN)
105 return 0;
106 return m_aDefault[AUTHED_ADMIN - AuthLevel];
107}
108
109int CAuthManager::KeyLevel(int Slot) const
110{
111 if(Slot < 0 || Slot >= (int)m_vKeys.size())
112 return false;
113 return m_vKeys[Slot].m_Level;
114}
115
116const char *CAuthManager::KeyIdent(int Slot) const
117{
118 if(Slot < 0 || Slot >= (int)m_vKeys.size())
119 return NULL;
120 return m_vKeys[Slot].m_aIdent;
121}
122
123void CAuthManager::UpdateKeyHash(int Slot, MD5_DIGEST Hash, const unsigned char *pSalt, int AuthLevel)
124{
125 if(Slot < 0 || Slot >= (int)m_vKeys.size())
126 return;
127
128 CKey *pKey = &m_vKeys[Slot];
129 pKey->m_Pw = Hash;
130 mem_copy(dest: pKey->m_aSalt, source: pSalt, SALT_BYTES);
131 pKey->m_Level = AuthLevel;
132}
133
134void CAuthManager::UpdateKey(int Slot, const char *pPw, int AuthLevel)
135{
136 if(Slot < 0 || Slot >= (int)m_vKeys.size())
137 return;
138
139 // Generate random salt
140 unsigned char aSalt[SALT_BYTES];
141 secure_random_fill(bytes: aSalt, SALT_BYTES);
142 UpdateKeyHash(Slot, Hash: HashPassword(pPassword: pPw, aSalt), pSalt: aSalt, AuthLevel);
143}
144
145void CAuthManager::ListKeys(FListCallback pfnListCallback, void *pUser)
146{
147 for(auto &Key : m_vKeys)
148 pfnListCallback(Key.m_aIdent, Key.m_Level, pUser);
149}
150
151void CAuthManager::AddDefaultKey(int Level, const char *pPw)
152{
153 if(Level < AUTHED_HELPER || Level > AUTHED_ADMIN)
154 return;
155
156 static const char s_aaIdents[3][sizeof(HELPER_IDENT)] = {ADMIN_IDENT, MOD_IDENT, HELPER_IDENT};
157 int Index = AUTHED_ADMIN - Level;
158 if(m_aDefault[Index] >= 0)
159 return; // already exists
160 m_aDefault[Index] = AddKey(pIdent: s_aaIdents[Index], pPw, AuthLevel: Level);
161}
162
163bool CAuthManager::IsGenerated() const
164{
165 return m_Generated;
166}
167
168int CAuthManager::NumNonDefaultKeys() const
169{
170 int DefaultCount = (m_aDefault[0] >= 0) + (m_aDefault[1] >= 0) + (m_aDefault[2] >= 0);
171 return m_vKeys.size() - DefaultCount;
172}
173