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 | |
11 | static 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 | |
21 | CAuthManager::CAuthManager() |
22 | { |
23 | m_aDefault[0] = -1; |
24 | m_aDefault[1] = -1; |
25 | m_aDefault[2] = -1; |
26 | m_Generated = false; |
27 | } |
28 | |
29 | void 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 | |
46 | int 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 | |
61 | int 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 | |
69 | void 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 | |
86 | int 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 | |
95 | bool 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 | |
102 | int 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 | |
109 | int 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 | |
116 | const 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 | |
123 | void 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 | |
134 | void 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 | |
145 | void CAuthManager::ListKeys(FListCallback pfnListCallback, void *pUser) |
146 | { |
147 | for(auto &Key : m_vKeys) |
148 | pfnListCallback(Key.m_aIdent, Key.m_Level, pUser); |
149 | } |
150 | |
151 | void 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 | |
163 | bool CAuthManager::IsGenerated() const |
164 | { |
165 | return m_Generated; |
166 | } |
167 | |
168 | int 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 | |