From ff10a7cfb8965f9dfb18e92ce8a36b3e6beec7d2 Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 18 Dec 2011 05:20:05 +0000 Subject: [PATCH] remoteadmin system changes --- Scripts/Engines/RemoteAdmin/Network.cs | 67 ++++++--- Scripts/Engines/RemoteAdmin/PacketHandlers.cs | 127 +++++++++++++----- Scripts/Engines/RemoteAdmin/Packets.cs | 21 ++- .../Engines/RemoteAdmin/RemoteAdminLogging.cs | 101 ++++++++++++++ 4 files changed, 265 insertions(+), 51 deletions(-) create mode 100644 Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs diff --git a/Scripts/Engines/RemoteAdmin/Network.cs b/Scripts/Engines/RemoteAdmin/Network.cs index f614def55..0c8d26de9 100644 --- a/Scripts/Engines/RemoteAdmin/Network.cs +++ b/Scripts/Engines/RemoteAdmin/Network.cs @@ -9,6 +9,8 @@ namespace Server.RemoteAdmin { public class AdminNetwork { + private const string ProtocolVersion = "2"; + private static ArrayList m_Auth = new ArrayList(); private static bool m_NewLine = true; private static StringBuilder m_ConsoleData = new StringBuilder(); @@ -39,11 +41,9 @@ namespace Server.RemoteAdmin } m_ConsoleData.Append( outStr ); - if ( m_ConsoleData.Length >= 4096 ) - m_ConsoleData.Remove( 0, 2048 ); + RoughTrimConsoleData(); - for (int i=0;i= 4096 ) - m_ConsoleData.Remove( 0, 2048 ); + RoughTrimConsoleData(); } public static void OnConsoleLine( string line ) @@ -81,15 +76,43 @@ namespace Server.RemoteAdmin outStr = String.Format( "{0}{1}", line, Console.Out.NewLine ); m_ConsoleData.Append( outStr ); - if ( m_ConsoleData.Length >= 4096 ) - m_ConsoleData.Remove( 0, 2048 ); + RoughTrimConsoleData(); - for (int i=0;i= 4096 ) + m_ConsoleData.Remove( 0, 2048 ); + } + + static void TightTrimConsoleData() + { + if ( m_ConsoleData.Length > 1024 ) + m_ConsoleData.Remove( 0, m_ConsoleData.Length - 1024 ); + } + public static void OnReceive( NetState state, PacketReader pvSrc ) { byte cmd = pvSrc.ReadByte(); @@ -97,9 +120,14 @@ namespace Server.RemoteAdmin { Authenticate( state, pvSrc ); } + else if ( cmd == 0xFE ) + { + state.Send( new CompactServerInfo() ); + state.Dispose(); + } else if ( cmd == 0xFF ) { - string statStr = String.Format( ", Name={0}, Age={1}, Clients={2}, Items={3}, Chars={4}, Mem={5}K", Server.Misc.ServerList.ServerName, (int)(DateTime.Now-Server.Items.Clock.ServerStart).TotalHours, NetState.Instances.Count, World.Items.Count, World.Mobiles.Count, (int)(System.GC.GetTotalMemory(false)/1024) ); + string statStr = String.Format( ", Name={0}, Age={1}, Clients={2}, Items={3}, Chars={4}, Mem={5}K, Ver={6}", Server.Misc.ServerList.ServerName, (int)(DateTime.Now - Server.Items.Clock.ServerStart).TotalHours, NetState.Instances.Count, World.Items.Count, World.Mobiles.Count, (int)(System.GC.GetTotalMemory( false ) / 1024), ProtocolVersion ); state.Send( new UOGInfo( statStr ) ); state.Dispose(); } @@ -147,7 +175,7 @@ namespace Server.RemoteAdmin else if ( !a.CheckPassword( pw ) ) { state.Send( new Login( LoginResponse.BadPass ) ); - Console.WriteLine( "ADMIN: Invalid password '{0}' for user '{1}' from {2}", pw, user, state ); + Console.WriteLine( "ADMIN: Invalid password for user '{0}' from {1}", user, state ); DelayedDisconnect( state ); } else if ( a.AccessLevel < AccessLevel.Administrator || a.Banned ) @@ -164,6 +192,7 @@ namespace Server.RemoteAdmin a.LastLogin = DateTime.Now; state.Send( new Login( LoginResponse.OK ) ); + TightTrimConsoleData(); state.Send( Compress( new ConsoleData( m_ConsoleData.ToString() ) ) ); m_Auth.Add( state ); } @@ -194,7 +223,7 @@ namespace Server.RemoteAdmin if ( length > 100 && length < 60000 ) { - byte[] dest = new byte[(int)(length*1.001)+1]; + byte[] dest = new byte[(int)(length * 1.001) + 10]; int destSize = dest.Length; ZLibError error = Compression.Pack( dest, ref destSize, source, length, ZLibQuality.Default ); diff --git a/Scripts/Engines/RemoteAdmin/PacketHandlers.cs b/Scripts/Engines/RemoteAdmin/PacketHandlers.cs index 62fd86928..e9bdc0c1a 100644 --- a/Scripts/Engines/RemoteAdmin/PacketHandlers.cs +++ b/Scripts/Engines/RemoteAdmin/PacketHandlers.cs @@ -70,6 +70,8 @@ namespace Server.RemoteAdmin foreach ( Account a in Accounts.GetAccounts() ) { + if ( !CanAccessAccount( state.Account, a ) ) continue; + switch ( type ) { case AcctSearchType.Username: @@ -106,20 +108,36 @@ namespace Server.RemoteAdmin } } + 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" ) ); } @@ -127,47 +145,96 @@ namespace Server.RemoteAdmin 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 ) - a = new Account( username, pass ); - else if ( pass != "(hidden)" ) - a.SetPassword( pass ); - - if ( a != state.Account ) + if ( a != null && !CanAccessAccount( state.Account, a ) ) { - a.AccessLevel = (AccessLevel)pvSrc.ReadByte(); - a.Banned = pvSrc.ReadBoolean(); + state.Send( new MessageBoxMessage( "You cannot edit an account with an access level greater than or equal to your own.", "Account Access Exception" ) ); } else { - pvSrc.ReadInt16();//skip both - state.Send( new MessageBoxMessage( "Warning: When editing your own account, account status and accesslevel cannot be changed.", "Editing Own Account" ) ); - } - - ArrayList list = new ArrayList(); - ushort length = pvSrc.ReadUInt16(); - bool invalid = false; - for (int i=0;i= 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 - invalid = true; - } - - if ( list.Count > 0 ) - a.IPRestrictions = (string[])list.ToArray( typeof( string ) ); - else - a.IPRestrictions = new string[0]; + { + 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" ) ); + } - if ( invalid ) - state.Send( new MessageBoxMessage( "Warning: one or more of the IP Restrictions you specified was not valid.", "Invalid IP Restriction" ) ); - state.Send( new MessageBoxMessage( "Account updated successfully.", "Account Updated" ) ); + 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 = string.Format( "{0} Access level changed from {1} to {2}.", changes, oldAcessLevel, 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" ) ); + } } } } diff --git a/Scripts/Engines/RemoteAdmin/Packets.cs b/Scripts/Engines/RemoteAdmin/Packets.cs index 5abfc88d8..73348465d 100644 --- a/Scripts/Engines/RemoteAdmin/Packets.cs +++ b/Scripts/Engines/RemoteAdmin/Packets.cs @@ -84,7 +84,7 @@ namespace Server.RemoteAdmin m_Stream.Write( (int) Core.ScriptItems ); m_Stream.Write( (uint)(DateTime.Now - Clock.ServerStart).TotalSeconds ); - m_Stream.Write( (uint) GC.GetTotalMemory( false ) ); + m_Stream.Write( (uint) GC.GetTotalMemory( false ) ); // TODO: uint not sufficient for TotalMemory (long). Fix protocol. m_Stream.WriteAsciiNull( netVer ); m_Stream.WriteAsciiNull( os ); } @@ -110,7 +110,7 @@ namespace Server.RemoteAdmin m_Stream.WriteAsciiNull( pwToSend ); m_Stream.Write( (byte)a.AccessLevel ); m_Stream.Write( a.Banned ); - unchecked { m_Stream.Write( (uint)a.LastLogin.Ticks ); } + unchecked { m_Stream.Write( (uint)a.LastLogin.Ticks ); } // TODO: This doesn't work, uint.MaxValue is only 7 minutes of ticks. Fix protocol. m_Stream.Write( (ushort)a.LoginIPs.Length ); for (int i=0;i> 32) ); // Memory high bytes + m_Stream.Write( (uint)memory ); // Memory low bytes + } + } + public sealed class UOGInfo : Packet { public UOGInfo( string str ) : base( 0x52, str.Length+6 ) // 'R' diff --git a/Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs b/Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs new file mode 100644 index 000000000..ee32348f4 --- /dev/null +++ b/Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; +using Server; +using Server.Accounting; +using Server.Network; + +namespace Server.RemoteAdmin +{ + public class RemoteAdminLogging + { + const string LogBaseDirectory = "Logs"; + const string LogSubDirectory = "RemoteAdmin"; + + private static StreamWriter m_Output; + private static bool m_Enabled = true; + + public static bool Enabled { get { return m_Enabled; } set { m_Enabled = value; } } + + public static StreamWriter Output { get { return m_Output; } } + + private static bool Initialized = false; + public static void LazyInitialize() + { + if ( Initialized || !m_Enabled ) return; + Initialized = true; + + if ( !Directory.Exists( LogBaseDirectory ) ) + Directory.CreateDirectory( LogBaseDirectory ); + + string directory = Path.Combine( LogBaseDirectory, LogSubDirectory ); + + if ( !Directory.Exists( directory ) ) + Directory.CreateDirectory( directory ); + + try + { + m_Output = new StreamWriter( Path.Combine( directory, String.Format( LogSubDirectory + "{0}.log", DateTime.Now.ToString( "yyyyMMdd" ) ) ), true ); + + m_Output.AutoFlush = true; + + m_Output.WriteLine( "##############################" ); + m_Output.WriteLine( "Log started on {0}", DateTime.Now ); + m_Output.WriteLine(); + } + catch + { + Utility.PushColor( ConsoleColor.Red ); + Console.WriteLine( "RemoteAdminLogging: Failed to initialize LogWriter." ); + Utility.PopColor(); + m_Enabled = false; + } + } + + public static object Format( object o ) + { + o = Commands.CommandLogging.Format( o ); + if ( o == null ) + return "(null)"; + + return o; + } + + public static void WriteLine( NetState state, string format, params object[] args ) + { + for ( int i = 0; i < args.Length; i++ ) + args[i] = Commands.CommandLogging.Format( args[i] ); + + WriteLine( state, String.Format( format, args ) ); + } + + public static void WriteLine( NetState state, string text ) + { + LazyInitialize(); + + if ( !m_Enabled ) return; + + try + { + Account acct = state.Account as Account; + string name = acct == null ? "(UNKNOWN)" : acct.Username; + string accesslevel = acct == null ? "NoAccount" : acct.AccessLevel.ToString(); + string statestr = state == null ? "NULLSTATE" : state.ToString(); + + m_Output.WriteLine( "{0}: {1}: {2}: {3}", DateTime.Now, statestr, name, text ); + + string path = Core.BaseDirectory; + + Commands.CommandLogging.AppendPath( ref path, LogBaseDirectory ); + Commands.CommandLogging.AppendPath( ref path, LogSubDirectory ); + Commands.CommandLogging.AppendPath( ref path, accesslevel ); + path = Path.Combine( path, String.Format( "{0}.log", name ) ); + + using ( StreamWriter sw = new StreamWriter( path, true ) ) + sw.WriteLine( "{0}: {1}: {2}", DateTime.Now, statestr, text ); + } + catch + { + } + } + } +}