Skip to content

Commit

Permalink
Merge pull request #639 from Learath2/dd_pr_rconauth2
Browse files Browse the repository at this point in the history
New auth system for rcon.
  • Loading branch information
heinrich5991 committed Mar 6, 2017
2 parents 28113c6 + 6302e4d commit 5b63a33
Show file tree
Hide file tree
Showing 10 changed files with 655 additions and 86 deletions.
58 changes: 58 additions & 0 deletions src/base/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,64 @@ void str_hex(char *dst, int dst_size, const void *data, int data_size)
}
}

static int hexval(char x)
{
switch(x)
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a':
case 'A': return 10;
case 'b':
case 'B': return 11;
case 'c':
case 'C': return 12;
case 'd':
case 'D': return 13;
case 'e':
case 'E': return 14;
case 'f':
case 'F': return 15;
default: return -1;
}
}

static int byteval(const char *byte, unsigned char *dst)
{
int v1 = -1, v2 = -1;
v1 = hexval(byte[0]);
v2 = hexval(byte[1]);

if(v1 < 0 || v2 < 0)
return 1;

*dst = v1 * 16 + v2;
return 0;
}

int str_hex_decode(unsigned char *dst, int dst_size, const char *src)
{
int len = str_length(src)/2;
int i;
if(len != dst_size)
return 2;

for(i = 0; i < len && dst_size; i++, dst_size--)
{
if(byteval(src + i * 2, dst++))
return 1;
}
return 0;
}

void str_timestamp_ex(time_t time_data, char *buffer, int buffer_size, const char *format)
{
struct tm *time_info;
Expand Down
18 changes: 18 additions & 0 deletions src/base/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,24 @@ const char *str_find(const char *haystack, const char *needle);
*/
void str_hex(char *dst, int dst_size, const void *data, int data_size);

/*
Function: str_hex_decode
Takes a hex string and returns a byte array.
Parameters:
dst - Buffer for the byte array
dst_size - size of the buffer
data - String to decode
Returns:
2 - String doesn't exactly fit the buffer
1 - Invalid character in string
0 - Success
Remarks:
- The contents of the buffer is only valid on success
*/
int str_hex_decode(unsigned char *dst, int dst_size, const char *src);
/*
Function: str_timestamp
Copies a time stamp in the format year-month-day_hour-minute-second to the string.
Expand Down
7 changes: 7 additions & 0 deletions src/engine/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2957,6 +2957,12 @@ void CClient::Con_RconAuth(IConsole::IResult *pResult, void *pUserData)
pSelf->RconAuth("", pResult->GetString(0));
}

void CClient::Con_RconLogin(IConsole::IResult *pResult, void *pUserData)
{
CClient *pSelf = (CClient *)pUserData;
pSelf->RconAuth(pResult->GetString(0), pResult->GetString(1));
}

void CClient::Con_AddFavorite(IConsole::IResult *pResult, void *pUserData)
{
CClient *pSelf = (CClient *)pUserData;
Expand Down Expand Up @@ -3286,6 +3292,7 @@ void CClient::RegisterCommands()
m_pConsole->Register("screenshot", "", CFGFLAG_CLIENT, Con_Screenshot, this, "Take a screenshot");
m_pConsole->Register("rcon", "r[rcon-command]", CFGFLAG_CLIENT, Con_Rcon, this, "Send specified command to rcon");
m_pConsole->Register("rcon_auth", "s[password]", CFGFLAG_CLIENT, Con_RconAuth, this, "Authenticate to rcon");
m_pConsole->Register("rcon_login", "s[username] s[password]", CFGFLAG_CLIENT, Con_RconLogin, this, "Authenticate to rcon with a username");
m_pConsole->Register("play", "r[file]", CFGFLAG_CLIENT|CFGFLAG_STORE, Con_Play, this, "Play the file specified");
m_pConsole->Register("record", "?s[file]", CFGFLAG_CLIENT, Con_Record, this, "Record to the file");
m_pConsole->Register("stoprecord", "", CFGFLAG_CLIENT, Con_StopRecord, this, "Stop recording");
Expand Down
1 change: 1 addition & 0 deletions src/engine/client/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
static void Con_Screenshot(IConsole::IResult *pResult, void *pUserData);
static void Con_Rcon(IConsole::IResult *pResult, void *pUserData);
static void Con_RconAuth(IConsole::IResult *pResult, void *pUserData);
static void Con_RconLogin(IConsole::IResult *pResult, void *pUserData);
static void Con_AddFavorite(IConsole::IResult *pResult, void *pUserData);
static void Con_RemoveFavorite(IConsole::IResult *pResult, void *pUserData);
static void Con_Play(IConsole::IResult *pResult, void *pUserData);
Expand Down
162 changes: 162 additions & 0 deletions src/engine/server/authmanager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#include <engine/external/md5/md5.h>

#include <engine/shared/config.h>
#include "authmanager.h"

#define ADMIN_IDENT "default_admin"
#define MOD_IDENT "default_mod"
#define HELPER_IDENT "default_helper"

CAuthManager::CAuthManager()
{
m_aDefault[0] = -1;
m_aDefault[1] = -1;
m_aDefault[2] = -1;
m_Generated = false;
}

void CAuthManager::Init()
{
if(m_aKeys.size() == 0 && !g_Config.m_SvRconPassword[0])
{
secure_random_password(g_Config.m_SvRconPassword, sizeof(g_Config.m_SvRconPassword), 6);
m_Generated = true;
}

if(g_Config.m_SvRconPassword[0])
AddDefaultKey(AUTHED_ADMIN, g_Config.m_SvRconPassword);
if(g_Config.m_SvRconModPassword[0])
AddDefaultKey(AUTHED_MOD, g_Config.m_SvRconModPassword);
if (g_Config.m_SvRconHelperPassword[0])
AddDefaultKey(AUTHED_HELPER, g_Config.m_SvRconHelperPassword);
}

int CAuthManager::AddKeyHash(const char *pIdent, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel)
{
if(FindKey(pIdent) > 0)
return -1;

CKey Key;
str_copy(Key.m_aIdent, pIdent, sizeof(Key.m_aIdent));
mem_copy(Key.m_aPw, pHash, MD5_BYTES);
mem_copy(Key.m_aSalt, pSalt, SALT_BYTES);
Key.m_Level = AuthLevel;

return m_aKeys.add(Key);
}

int CAuthManager::AddKey(const char *pIdent, const char *pPw, int AuthLevel)
{
md5_state_t ctx;
unsigned char aHash[MD5_BYTES];
unsigned char aSalt[SALT_BYTES];

// Generate random salt
secure_random_fill(aSalt, SALT_BYTES);

// Hash the password and the salt
md5_init(&ctx);
md5_append(&ctx, (unsigned char *)pPw, str_length(pPw));
md5_append(&ctx, aSalt, SALT_BYTES);
md5_finish(&ctx, aHash);

return AddKeyHash(pIdent, aHash, aSalt, AuthLevel);
}

int CAuthManager::RemoveKey(int Slot)
{
m_aKeys.remove_index_fast(Slot);
return m_aKeys.size();
}

int CAuthManager::FindKey(const char *pIdent)
{
for(int i = 0; i < m_aKeys.size(); i++)
if(!str_comp(m_aKeys[i].m_aIdent, pIdent))
return i;

return -1;
}

bool CAuthManager::CheckKey(int Slot, const char *pPw)
{
dbg_assert(Slot >= 0 || Slot < m_aKeys.size(), "indice out of bounds");

md5_state_t ctx;
unsigned char aHash[MD5_BYTES];

// Hash the password and the salt
md5_init(&ctx);
md5_append(&ctx, (unsigned char*)pPw, str_length(pPw));
md5_append(&ctx, m_aKeys[Slot].m_aSalt, SALT_BYTES);
md5_finish(&ctx, aHash);

return !mem_comp(m_aKeys[Slot].m_aPw, aHash, MD5_BYTES);
}

int CAuthManager::DefaultKey(int AuthLevel)
{
dbg_assert(AuthLevel >= 0 || AuthLevel <= AUTHED_ADMIN, "auth level invalid");
return m_aDefault[AUTHED_ADMIN - AuthLevel];
}

int CAuthManager::KeyLevel(int Slot)
{
dbg_assert(Slot >= 0 || Slot < m_aKeys.size(), "indice out of bounds");
return m_aKeys[Slot].m_Level;
}

const char *CAuthManager::KeyIdent(int Slot)
{
dbg_assert(Slot >= 0 || Slot < m_aKeys.size(), "indice out of bounds");
return m_aKeys[Slot].m_aIdent;
}

void CAuthManager::UpdateKeyHash(int Slot, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel)
{
dbg_assert(Slot >= 0 || Slot < m_aKeys.size(), "indice out of bounds");

CKey *pKey = &m_aKeys[Slot];
mem_copy(pKey->m_aPw, pHash, MD5_BYTES);
mem_copy(pKey->m_aSalt, pSalt, SALT_BYTES);
pKey->m_Level = AuthLevel;
}

void CAuthManager::UpdateKey(int Slot, const char *pPw, int AuthLevel)
{
dbg_assert(Slot >= 0 || Slot < m_aKeys.size(), "indice out of bounds");

md5_state_t ctx;
unsigned char aHash[MD5_BYTES];
unsigned char aSalt[SALT_BYTES];

// Generate random salt
secure_random_fill(aSalt, SALT_BYTES);

// Hash the password and the salt
md5_init(&ctx);
md5_append(&ctx, (unsigned char *)pPw, str_length(pPw));
md5_append(&ctx, aSalt, SALT_BYTES);
md5_finish(&ctx, aHash);

UpdateKeyHash(Slot, aHash, aSalt, AuthLevel);
}

void CAuthManager::ListKeys(FListCallback pfnListCallback, void *pUser)
{
for(int i = 0; i < m_aKeys.size(); i++)
pfnListCallback(m_aKeys[i].m_aIdent, m_aKeys[i].m_Level, pUser);
}

void CAuthManager::AddDefaultKey(int Level, const char *pPw)
{
dbg_assert(AUTHED_HELPER <= Level && Level <= AUTHED_ADMIN, "level out of range");
static const char IDENTS[3][sizeof(HELPER_IDENT)] = {ADMIN_IDENT, MOD_IDENT, HELPER_IDENT};
int Index = AUTHED_ADMIN - Level;
m_aDefault[Index] = AddKey(IDENTS[Index], pPw, Level);
}

bool CAuthManager::IsGenerated()
{
return m_Generated;
}
50 changes: 50 additions & 0 deletions src/engine/server/authmanager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef ENGINE_SERVER_AUTH_MANAGER_H
#define ENGINE_SERVER_AUTH_MANAGER_H

#include <base/tl/array.h>

#define MD5_BYTES 16
#define SALT_BYTES 8

class CAuthManager
{
private:
enum { //:(
AUTHED_NO = 0,
AUTHED_HELPER,
AUTHED_MOD,
AUTHED_ADMIN
};
struct CKey
{
char m_aIdent[64];
unsigned char m_aPw[MD5_BYTES];
unsigned char m_aSalt[SALT_BYTES];
int m_Level;
};
array<CKey> m_aKeys;

int m_aDefault[3];
bool m_Generated;
public:
typedef void (*FListCallback)(const char *pIdent, int Level, void *pUser);

CAuthManager();

void Init();
int AddKeyHash(const char *pIdent, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel);
int AddKey(const char *pIdent, const char *pPw, int AuthLevel);
int RemoveKey(int Slot); // Returns the old key slot that is now in the named one.
int FindKey(const char *pIdent);
bool CheckKey(int Slot, const char *pPw);
int DefaultKey(int AuthLevel);
int KeyLevel(int Slot);
const char *KeyIdent(int Slot);
void UpdateKeyHash(int Slot, const unsigned char *pHash, const unsigned char *pSalt, int AuthLevel);
void UpdateKey(int Slot, const char *pPw, int AuthLevel);
void ListKeys(FListCallback pfnListCallbac, void *pUser);
void AddDefaultKey(int Level, const char *pPw);
bool IsGenerated();
};

#endif //ENGINE_SERVER_AUTH_MANAGER_H
Loading

0 comments on commit 5b63a33

Please sign in to comment.