@@ -407,9 +407,19 @@ void CServer::AuthTick()
407407 nullptr );
408408
409409 {
410+ EAccessLevel AccessLevel{EAccessLevel::USER};
411+ for (const SAccountAccessInfo &AccessInfo : m_vAccountsAccessInfo)
412+ {
413+ if (AccessInfo.UserId == UserId)
414+ {
415+ AccessLevel = AccessInfo.AccessLevel ;
416+ SetClientAccessLevel (ClientId, AccessInfo.AccessLevel , true );
417+ }
418+ }
419+
410420 char aBuf[256 ];
411- str_format (aBuf, sizeof (aBuf), " ClientId=%d authed as %s (UserId %d)" ,
412- ClientId, pUsername, UserId);
421+ str_format (aBuf, sizeof (aBuf), " ClientId=%d authed as %s (UserId %d, %s )" ,
422+ ClientId, pUsername, UserId, toString (AccessLevel) );
413423 Console ()->Print (IConsole::OUTPUT_LEVEL_ADDINFO, " accounts" , aBuf);
414424 }
415425 }
@@ -2056,7 +2066,6 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
20562066 return ;
20572067 }
20582068
2059- std::optional<int > LoggedInAuthLevel;
20602069 if (pName[0 ])
20612070 {
20622071 char aTrimmedName[MAX_NAME_LENGTH];
@@ -2086,79 +2095,20 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
20862095 return ;
20872096 }
20882097
2098+ std::optional<EAccessLevel> LoggedInAccessLevel;
20892099 if (g_Config.m_SvRconPassword [0 ] && str_comp (pPw, g_Config.m_SvRconPassword ) == 0 )
20902100 {
2091- LoggedInAuthLevel = AUTHED_ADMIN ;
2101+ LoggedInAccessLevel = EAccessLevel::ADMIN ;
20922102 }
20932103 else if (g_Config.m_SvRconModPassword [0 ] && str_comp (pPw, g_Config.m_SvRconModPassword ) == 0 )
20942104 {
2095- LoggedInAuthLevel = AUTHED_MOD ;
2105+ LoggedInAccessLevel = EAccessLevel::MOD ;
20962106 }
20972107
2098- if (LoggedInAuthLevel .has_value ())
2108+ if (LoggedInAccessLevel .has_value ())
20992109 {
2100- if (m_aClients[ClientId].m_Authed != LoggedInAuthLevel.value ())
2101- {
2102- if (!IsSixup (ClientId))
2103- {
2104- CMsgPacker Msgp (NETMSG_RCON_AUTH_STATUS, true );
2105- Msgp.AddInt (1 ); // authed
2106- Msgp.AddInt (1 ); // cmdlist
2107- SendMsg (&Msgp, MSGFLAG_VITAL, ClientId);
2108- }
2109- else
2110- {
2111- CMsgPacker Msgp (protocol7::NETMSG_RCON_AUTH_ON, true , true );
2112- SendMsg (&Msgp, MSGFLAG_VITAL, ClientId);
2113- }
2114-
2115- m_aClients[ClientId].m_Authed = LoggedInAuthLevel.value ();
2116- bool SendRconCmds = IsSixup (ClientId) ? true : (Unpacker.GetInt () > 0 );
2117- if (!Unpacker.Error () && SendRconCmds)
2118- {
2119- EAccessLevel ConsoleAccessLevel{};
2120- switch (LoggedInAuthLevel.value ())
2121- {
2122- case AUTHED_ADMIN:
2123- ConsoleAccessLevel = EAccessLevel::ADMIN;
2124- break ;
2125- case AUTHED_MOD:
2126- ConsoleAccessLevel = EAccessLevel::MOD;
2127- break ;
2128- default :
2129- ConsoleAccessLevel = EAccessLevel::USER;
2130- break ;
2131- }
2132-
2133- m_aClients[ClientId].m_pRconCmdToSend = Console ()->FirstCommandInfo (ConsoleAccessLevel, CFGFLAG_SERVER);
2134- }
2135-
2136- char aBuf[256 ];
2137- switch (LoggedInAuthLevel.value ())
2138- {
2139- case AUTHED_ADMIN:
2140- {
2141- SendRconLine (ClientId, " Admin authentication successful. Full remote console access granted." );
2142- str_format (aBuf, sizeof (aBuf), " ClientId=%d authed (admin)" , ClientId);
2143- break ;
2144- }
2145- case AUTHED_MOD:
2146- {
2147- SendRconLine (ClientId, " Moderator authentication successful. Limited remote console access granted." );
2148- str_format (aBuf, sizeof (aBuf), " ClientId=%d authed (moderator)" , ClientId);
2149- break ;
2150- }
2151- case AUTHED_HELPER:
2152- {
2153- SendRconLine (ClientId, " Helper authentication successful. Limited remote console access granted." );
2154- str_format (aBuf, sizeof (aBuf), " ClientId=%d authed (helper)" , ClientId);
2155- break ;
2156- }
2157- }
2158- Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " server" , aBuf);
2159-
2160- GameServer ()->OnSetAuthed (ClientId, m_aClients[ClientId].m_Authed );
2161- }
2110+ bool SendRconCmds = IsSixup (ClientId) ? true : (Unpacker.GetInt () > 0 );
2111+ SetClientAccessLevel (ClientId, LoggedInAccessLevel.value (), !Unpacker.Error () && SendRconCmds);
21622112 }
21632113 else if (Config ()->m_SvRconMaxTries )
21642114 {
@@ -3875,12 +3825,18 @@ void CServer::ConAccounts(IConsole::IResult *pResult)
38753825 Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " help" );
38763826 Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " status" );
38773827 Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " set_salt [string, at least 3 characters]" );
3828+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " set_access_level [user_id number] [0: admin, 1: moderator]" );
3829+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " reset_access_level [user_id number]" );
3830+ };
3831+ auto InsufficientArguments = [this ]() {
3832+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " Insufficient arguments." );
38783833 };
38793834
38803835 const char *pOptionStr = pResult->GetString (0 );
38813836 if (!pOptionStr || !pOptionStr[0 ] || (str_comp (pOptionStr, " status" ) == 0 ))
38823837 {
38833838 PrintStatus ();
3839+ PrintHelp ();
38843840 }
38853841 else if (str_comp (pOptionStr, " help" ) == 0 )
38863842 {
@@ -3902,6 +3858,92 @@ void CServer::ConAccounts(IConsole::IResult *pResult)
39023858 Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " Error: the salt should be at least 3 characters in length" );
39033859 }
39043860 }
3861+ else
3862+ {
3863+ InsufficientArguments ();
3864+ PrintHelp ();
3865+ }
3866+ }
3867+ else if (str_comp (pOptionStr, " set_access_level" ) == 0 )
3868+ {
3869+ if (pResult->NumArguments () > 2 )
3870+ {
3871+ const int UserId = pResult->GetInteger (1 );
3872+ const int RawLevel = pResult->GetInteger (2 );
3873+ EAccessLevel AccessLevel = static_cast <EAccessLevel>(RawLevel);
3874+ if (RawLevel < 0 || RawLevel > 1 )
3875+ {
3876+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " Error: the access level must be a positive number [0: admin, 1: moderator]" );
3877+ }
3878+ else if (UserId <= 0 )
3879+ {
3880+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " Error: the user id must be a positive number" );
3881+ }
3882+ else
3883+ {
3884+ bool Set{};
3885+ for (SAccountAccessInfo &AccountAccessLevel : m_vAccountsAccessInfo)
3886+ {
3887+ if (AccountAccessLevel.UserId == UserId)
3888+ {
3889+ AccountAccessLevel.AccessLevel = AccessLevel;
3890+ Set = true ;
3891+ }
3892+ }
3893+
3894+ if (!Set)
3895+ {
3896+ m_vAccountsAccessInfo.push_back ({
3897+ .UserId = UserId,
3898+ .AccessLevel = AccessLevel,
3899+ });
3900+ }
3901+
3902+ char aBuf[128 ];
3903+ str_format (aBuf, sizeof (aBuf), " User %d access level is now set to %s" , UserId, toString (AccessLevel));
3904+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , aBuf);
3905+ }
3906+ }
3907+ else
3908+ {
3909+ InsufficientArguments ();
3910+ PrintHelp ();
3911+ }
3912+ }
3913+ else if (str_comp (pOptionStr, " reset_access_level" ) == 0 )
3914+ {
3915+ if (pResult->NumArguments () > 1 )
3916+ {
3917+ const int UserId = pResult->GetInteger (1 );
3918+ if (UserId <= 0 )
3919+ {
3920+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " Error: the user id must be a positive number" );
3921+ }
3922+ else
3923+ {
3924+ auto InfoIt = std::find_if (std::begin (m_vAccountsAccessInfo), std::end (m_vAccountsAccessInfo), [UserId](const SAccountAccessInfo &Info) {
3925+ return Info.UserId == UserId;
3926+ });
3927+ if (InfoIt == m_vAccountsAccessInfo.end ())
3928+ {
3929+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , " The given user didn't have a custom access level" );
3930+ }
3931+ else
3932+ {
3933+ EAccessLevel AccessLevel = InfoIt->AccessLevel ;
3934+ m_vAccountsAccessInfo.erase (InfoIt);
3935+
3936+ char aBuf[128 ];
3937+ str_format (aBuf, sizeof (aBuf), " '%s' access revoked from user %d" , toString (AccessLevel), UserId);
3938+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " accounts" , aBuf);
3939+ }
3940+ }
3941+ }
3942+ else
3943+ {
3944+ InsufficientArguments ();
3945+ PrintHelp ();
3946+ }
39053947 }
39063948 else
39073949 {
@@ -4160,7 +4202,7 @@ void CServer::RegisterCommands()
41604202 Console ()->Register (" logout" , " " , CFGFLAG_SERVER, ConLogout, this , " Logout of rcon" );
41614203 Console ()->Register (" show_ips" , " ?i[show]" , CFGFLAG_SERVER, ConShowIps, this , " Show IP addresses in rcon commands (1 = on, 0 = off)" );
41624204
4163- Console ()->Register (" accounts" , " ?s[command] ?s[arg1]" , CFGFLAG_SERVER, ConAccounts, this , " Manage accounts" );
4205+ Console ()->Register (" accounts" , " ?s[command] ?s[arg1] ?s[arg2] " , CFGFLAG_SERVER, ConAccounts, this , " Manage accounts" );
41644206
41654207 Console ()->Register (" record" , " ?s[file]" , CFGFLAG_SERVER | CFGFLAG_STORE, ConRecord, this , " Record to a file" );
41664208 Console ()->Register (" stoprecord" , " " , CFGFLAG_SERVER, ConStopRecord, this , " Stop recording" );
@@ -6209,6 +6251,75 @@ void CServer::TakeUserName(int ClientId)
62096251 }
62106252}
62116253
6254+ int toAuthed (EAccessLevel AccessLevel)
6255+ {
6256+ switch (AccessLevel)
6257+ {
6258+ case EAccessLevel::ADMIN:
6259+ return AUTHED_ADMIN;
6260+ case EAccessLevel::MOD:
6261+ return AUTHED_MOD;
6262+ case EAccessLevel::HELPER:
6263+ return AUTHED_HELPER;
6264+ case EAccessLevel::USER:
6265+ break ;
6266+ }
6267+
6268+ return AUTHED_NO;
6269+ }
6270+
6271+ void CServer::SetClientAccessLevel (int ClientId, EAccessLevel AccessLevel, bool SendRconCmds)
6272+ {
6273+ int Authed = toAuthed (AccessLevel);
6274+ if (m_aClients[ClientId].m_Authed == Authed)
6275+ return ;
6276+
6277+ if (AccessLevel > EAccessLevel::MOD)
6278+ {
6279+ return ;
6280+ }
6281+
6282+ if (!IsSixup (ClientId))
6283+ {
6284+ CMsgPacker Msgp (NETMSG_RCON_AUTH_STATUS, true );
6285+ Msgp.AddInt (1 ); // authed
6286+ Msgp.AddInt (1 ); // cmdlist
6287+ SendMsg (&Msgp, MSGFLAG_VITAL, ClientId);
6288+ }
6289+ else
6290+ {
6291+ CMsgPacker Msgp (protocol7::NETMSG_RCON_AUTH_ON, true , true );
6292+ SendMsg (&Msgp, MSGFLAG_VITAL, ClientId);
6293+ }
6294+
6295+ m_aClients[ClientId].m_Authed = Authed;
6296+ if (SendRconCmds)
6297+ {
6298+ m_aClients[ClientId].m_pRconCmdToSend = Console ()->FirstCommandInfo (AccessLevel, CFGFLAG_SERVER);
6299+ }
6300+
6301+ char aBuf[256 ];
6302+ switch (AccessLevel)
6303+ {
6304+ case EAccessLevel::ADMIN:
6305+ SendRconLine (ClientId, " Admin authentication successful. Full remote console access granted." );
6306+ break ;
6307+ case EAccessLevel::MOD:
6308+ SendRconLine (ClientId, " Moderator authentication successful. Limited remote console access granted." );
6309+ break ;
6310+ case EAccessLevel::HELPER:
6311+ SendRconLine (ClientId, " Helper authentication successful. Limited remote console access granted." );
6312+ break ;
6313+ case EAccessLevel::USER:
6314+ break ;
6315+ }
6316+
6317+ str_format (aBuf, sizeof (aBuf), " ClientId=%d authed (%s)" , ClientId, toString (AccessLevel));
6318+ Console ()->Print (IConsole::OUTPUT_LEVEL_STANDARD, " server" , aBuf);
6319+
6320+ GameServer ()->OnSetAuthed (ClientId, m_aClients[ClientId].m_Authed );
6321+ }
6322+
62126323void CServer::SetErrorShutdown (const char *pReason)
62136324{
62146325 str_copy (m_aErrorShutdownReason, pReason);
0 commit comments