using System; using System.Collections; using Server.Network; using Server.Accounting; namespace Server.RemoteAdmin { public class RemoteAdminHandlers { public enum AcctSearchType : byte { Username = 0, IP = 1, } private static OnPacketReceive[] m_Handlers = new OnPacketReceive[256]; static RemoteAdminHandlers() { //0x02 = login request, handled by AdminNetwork Register( 0x04, ServerInfoRequest ); Register( 0x05, AccountSearch ); Register( 0x06, RemoveAccount ); Register( 0x07, UpdateAccount ); } public static void Register( byte command, OnPacketReceive handler ) { m_Handlers[command] = handler; } public static bool Handle( byte command, NetState state, PacketReader pvSrc ) { if ( m_Handlers[command] == null ) { Console.WriteLine( "ADMIN: Invalid packet 0x{0:X2} from {1}, disconnecting", command, state ); return false; } m_Handlers[command]( state, pvSrc ); return true; } private static void ServerInfoRequest( NetState state, PacketReader pvSrc ) { state.Send( AdminNetwork.Compress( new ServerInfo() ) ); } private static void AccountSearch( NetState state, PacketReader pvSrc ) { AcctSearchType type = (AcctSearchType)pvSrc.ReadByte(); string term = pvSrc.ReadString(); if ( type == AcctSearchType.IP && !Utility.IsValidIP( term ) ) { state.Send( new MessageBoxMessage( "Invalid search term.\nThe IP sent was not valid.", "Invalid IP" ) ); return; } term = term.ToUpper(); ArrayList list = new ArrayList(); foreach ( Account a in Accounts.GetAccounts() ) { if ( !CanAccessAccount( state.Account, a ) ) continue; switch ( type ) { case AcctSearchType.Username: { if ( a.Username.ToUpper().IndexOf( term ) != -1 ) list.Add( a ); break; } case AcctSearchType.IP: { for( int i=0;i 0 ) { if ( list.Count <= 25 ) state.Send( AdminNetwork.Compress( new AccountSearchResults( list ) ) ); else state.Send( new MessageBoxMessage( "There were more than 25 matches to your search.\nNarrow the search parameters and try again.", "Too Many Results" ) ); } else { state.Send( new MessageBoxMessage( "There were no results to your search.\nPlease try again.", "No Matches" ) ); } } static bool CanAccessAccount( IAccount beholder, IAccount beheld ) { return beholder.AccessLevel == AccessLevel.Owner || beheld.AccessLevel < beholder.AccessLevel; // Cannot see accounts of equal or greater access level unless Owner } private static void RemoveAccount( NetState state, PacketReader pvSrc ) { if ( state.Account.AccessLevel < AccessLevel.Administrator ) { state.Send( new MessageBoxMessage( "You do not have permission to delete accounts.", "Account Access Exception" ) ); return; } IAccount a = Accounts.GetAccount( pvSrc.ReadString() ); if ( a == null ) { state.Send( new MessageBoxMessage( "The account could not be found (and thus was not deleted).", "Account Not Found" ) ); } else if ( !CanAccessAccount( state.Account, a ) ) { state.Send( new MessageBoxMessage( "You cannot delete an account with an access level greater than or equal to your own.", "Account Access Exception" ) ); } else if ( a == state.Account ) { state.Send( new MessageBoxMessage( "You may not delete your own account.", "Not Allowed" ) ); } else { RemoteAdminLogging.WriteLine( state, "Deleted Account {0}", a ); a.Delete(); state.Send( new MessageBoxMessage( "The requested account (and all it's characters) has been deleted.", "Account Deleted" ) ); } } private static void UpdateAccount( NetState state, PacketReader pvSrc ) { if ( state.Account.AccessLevel < AccessLevel.Administrator ) { state.Send( new MessageBoxMessage( "You do not have permission to edit accounts.", "Account Access Exception" ) ); return; } string username = pvSrc.ReadString(); string pass = pvSrc.ReadString(); Account a = Accounts.GetAccount( username ) as Account; if ( a != null && !CanAccessAccount( state.Account, a ) ) { state.Send( new MessageBoxMessage( "You cannot edit an account with an access level greater than or equal to your own.", "Account Access Exception" ) ); } else { bool CreatedAccount = false; bool UpdatedPass = false; bool oldbanned = a?.Banned ?? false; AccessLevel oldAcessLevel = a?.AccessLevel ?? 0; if ( a == null ) { a = new Account( username, pass ); CreatedAccount = true; } else if ( pass != "(hidden)" ) { a.SetPassword( pass ); UpdatedPass = true; } if ( a != state.Account ) { AccessLevel newAccessLevel = (AccessLevel)pvSrc.ReadByte(); if ( a.AccessLevel != newAccessLevel ) { if ( newAccessLevel >= state.Account.AccessLevel ) state.Send( new MessageBoxMessage( "Warning: You may not set an access level greater than or equal to your own.", "Account Access Level update denied." ) ); else a.AccessLevel = newAccessLevel; } bool newBanned = pvSrc.ReadBoolean(); if ( newBanned != a.Banned ) { oldbanned = a.Banned; a.Banned = newBanned; a.Comments.Add( new AccountComment( state.Account.Username, newBanned ? "Banned via Remote Admin" : "Unbanned via Remote Admin" ) ); } } else { pvSrc.ReadInt16();//skip both state.Send( new MessageBoxMessage( "Warning: When editing your own account, Account Status and Access Level cannot be changed.", "Editing Own Account" ) ); } ArrayList list = new ArrayList(); ushort length = pvSrc.ReadUInt16(); bool invalid = false; for (int i=0;i 0 ) a.IPRestrictions = (string[])list.ToArray( typeof( string ) ); else a.IPRestrictions = new string[0]; if ( invalid ) state.Send( new MessageBoxMessage( "Warning: one or more of the IP Restrictions you specified was not valid.", "Invalid IP Restriction" ) ); if ( CreatedAccount ) RemoteAdminLogging.WriteLine( state, "Created account {0} with Access Level {1}", a.Username, a.AccessLevel ); else { string changes = string.Empty; if ( UpdatedPass ) changes += " Password Changed."; if ( oldAcessLevel != a.AccessLevel ) changes = $"{changes} Access level changed from {oldAcessLevel} to {a.AccessLevel}."; if ( oldbanned != a.Banned ) changes += a.Banned ? " Banned." : " Unbanned."; RemoteAdminLogging.WriteLine( state, "Updated account {0}:{1}", a.Username, changes ); } state.Send( new MessageBoxMessage( "Account updated successfully.", "Account Updated" ) ); } } } }