288 lines
9.0 KiB
C#
288 lines
9.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using Server.Accounting;
|
|
using Server.Network;
|
|
|
|
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 readonly StringBuilder m_ConsoleData = new StringBuilder();
|
|
|
|
private const string DateFormat = "MMMM dd hh:mm:ss.f tt";
|
|
|
|
public static void Configure()
|
|
{
|
|
PacketHandlers.Register(0xF1, 0, false, new OnPacketReceive(OnReceive));
|
|
|
|
Core.MultiConsoleOut.Add(new EventTextWriter(new EventTextWriter.OnConsoleChar(OnConsoleChar), new EventTextWriter.OnConsoleLine(OnConsoleLine), new EventTextWriter.OnConsoleStr(OnConsoleString)));
|
|
Timer.DelayCall(TimeSpan.FromMinutes(2.5), TimeSpan.FromMinutes(2.5), new TimerCallback(CleanUp));
|
|
}
|
|
|
|
public static void OnConsoleString(string str)
|
|
{
|
|
string outStr;
|
|
if (m_NewLine)
|
|
{
|
|
outStr = String.Format("[{0}]: {1}", DateTime.UtcNow.ToString(DateFormat), str);
|
|
m_NewLine = false;
|
|
}
|
|
else
|
|
{
|
|
outStr = str;
|
|
}
|
|
|
|
m_ConsoleData.Append(outStr);
|
|
RoughTrimConsoleData();
|
|
|
|
SendToAll(outStr);
|
|
}
|
|
|
|
public static void OnConsoleChar(char ch)
|
|
{
|
|
if (m_NewLine)
|
|
{
|
|
string outStr;
|
|
outStr = String.Format("[{0}]: {1}", DateTime.UtcNow.ToString(DateFormat), ch);
|
|
|
|
m_ConsoleData.Append(outStr);
|
|
SendToAll(outStr);
|
|
|
|
m_NewLine = false;
|
|
}
|
|
else
|
|
{
|
|
m_ConsoleData.Append(ch);
|
|
SendToAll(ch);
|
|
}
|
|
|
|
RoughTrimConsoleData();
|
|
}
|
|
|
|
public static void OnConsoleLine(string line)
|
|
{
|
|
string outStr;
|
|
if (m_NewLine)
|
|
outStr = String.Format("[{0}]: {1}{2}", DateTime.UtcNow.ToString(DateFormat), line, Console.Out.NewLine);
|
|
else
|
|
outStr = String.Format("{0}{1}", line, Console.Out.NewLine);
|
|
|
|
m_ConsoleData.Append(outStr);
|
|
RoughTrimConsoleData();
|
|
|
|
SendToAll(outStr);
|
|
|
|
m_NewLine = true;
|
|
}
|
|
|
|
static void SendToAll(string outStr)
|
|
{
|
|
SendToAll(new ConsoleData(outStr));
|
|
}
|
|
|
|
static void SendToAll(char ch)
|
|
{
|
|
SendToAll(new ConsoleData(ch));
|
|
}
|
|
|
|
static void SendToAll(ConsoleData packet)
|
|
{
|
|
packet.Acquire();
|
|
for (int i = 0; i < m_Auth.Count; i++)
|
|
((NetState)m_Auth[i]).Send(packet);
|
|
packet.Release();
|
|
}
|
|
|
|
static void RoughTrimConsoleData()
|
|
{
|
|
if (m_ConsoleData.Length >= 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();
|
|
if (cmd == 0x02)
|
|
{
|
|
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, Ver={6}", Server.Misc.ServerList.ServerName, (int)(DateTime.UtcNow - 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();
|
|
}
|
|
else if (!IsAuth(state))
|
|
{
|
|
Console.WriteLine("ADMIN: Unauthorized packet from {0}, disconnecting", state);
|
|
Disconnect(state);
|
|
}
|
|
else
|
|
{
|
|
if (!RemoteAdminHandlers.Handle(cmd, state, pvSrc))
|
|
Disconnect(state);
|
|
}
|
|
}
|
|
|
|
private static void DelayedDisconnect(NetState state)
|
|
{
|
|
Timer.DelayCall(TimeSpan.FromSeconds(15.0), new TimerStateCallback(Disconnect), state);
|
|
}
|
|
|
|
private static void Disconnect(object state)
|
|
{
|
|
m_Auth.Remove(state);
|
|
((NetState)state).Dispose();
|
|
}
|
|
|
|
public static void Authenticate(NetState state, PacketReader pvSrc)
|
|
{
|
|
string user = pvSrc.ReadString(30);
|
|
string pw = pvSrc.ReadString(30);
|
|
|
|
Account a = Accounts.GetAccount(user) as Account;
|
|
if (a == null)
|
|
{
|
|
state.Send(new Login(LoginResponse.NoUser));
|
|
Console.WriteLine("ADMIN: Invalid username '{0}' from {1}", user, state);
|
|
DelayedDisconnect(state);
|
|
}
|
|
else if (!a.HasAccess(state))
|
|
{
|
|
state.Send(new Login(LoginResponse.BadIP));
|
|
Console.WriteLine("ADMIN: Access to '{0}' from {1} denied.", user, state);
|
|
DelayedDisconnect(state);
|
|
}
|
|
else if (!a.CheckPassword(pw))
|
|
{
|
|
state.Send(new Login(LoginResponse.BadPass));
|
|
Console.WriteLine("ADMIN: Invalid password for user '{0}' from {1}", user, state);
|
|
DelayedDisconnect(state);
|
|
}
|
|
else if (a.AccessLevel < AccessLevel.Administrator || a.Banned)
|
|
{
|
|
Console.WriteLine("ADMIN: Account '{0}' does not have admin access. Connection Denied.", user);
|
|
state.Send(new Login(LoginResponse.NoAccess));
|
|
DelayedDisconnect(state);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("ADMIN: Access granted to '{0}' from {1}", user, state);
|
|
state.Account = a;
|
|
a.LogAccess(state);
|
|
a.LastLogin = DateTime.UtcNow;
|
|
|
|
state.Send(new Login(LoginResponse.OK));
|
|
TightTrimConsoleData();
|
|
state.Send(Compress(new ConsoleData(m_ConsoleData.ToString())));
|
|
m_Auth.Add(state);
|
|
}
|
|
}
|
|
|
|
public static bool IsAuth(NetState state)
|
|
{
|
|
return m_Auth.Contains(state);
|
|
}
|
|
|
|
private static void CleanUp()
|
|
{ //remove dead instances from m_Auth
|
|
ArrayList list = new ArrayList();
|
|
for (int i = 0; i < m_Auth.Count; i++)
|
|
{
|
|
NetState ns = (NetState)m_Auth[i];
|
|
if (ns.Running)
|
|
list.Add(ns);
|
|
}
|
|
|
|
m_Auth = list;
|
|
}
|
|
|
|
public static Packet Compress(Packet p)
|
|
{
|
|
int length;
|
|
byte[] source = p.Compile(false, out length);
|
|
|
|
if (length > 100 && length < 60000)
|
|
{
|
|
byte[] dest = new byte[(int)(length * 1.001) + 10];
|
|
int destSize = dest.Length;
|
|
|
|
ZLibError error = Compression.Pack(dest, ref destSize, source, length, ZLibQuality.Default);
|
|
|
|
if (error != ZLibError.Okay)
|
|
{
|
|
Console.WriteLine("WARNING: Unable to compress admin packet, zlib error: {0}", error);
|
|
return p;
|
|
}
|
|
else
|
|
{
|
|
return new AdminCompressedPacket(dest, destSize, length);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return p;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class EventTextWriter : System.IO.TextWriter
|
|
{
|
|
public delegate void OnConsoleChar(char ch);
|
|
public delegate void OnConsoleLine(string line);
|
|
public delegate void OnConsoleStr(string str);
|
|
|
|
private readonly OnConsoleChar m_OnChar;
|
|
private readonly OnConsoleLine m_OnLine;
|
|
private readonly OnConsoleStr m_OnStr;
|
|
|
|
public EventTextWriter(OnConsoleChar onChar, OnConsoleLine onLine, OnConsoleStr onStr)
|
|
{
|
|
this.m_OnChar = onChar;
|
|
this.m_OnLine = onLine;
|
|
this.m_OnStr = onStr;
|
|
}
|
|
|
|
public override void Write(char ch)
|
|
{
|
|
if (this.m_OnChar != null)
|
|
this.m_OnChar(ch);
|
|
}
|
|
|
|
public override void Write(string str)
|
|
{
|
|
if (this.m_OnStr != null)
|
|
this.m_OnStr(str);
|
|
}
|
|
|
|
public override void WriteLine(string line)
|
|
{
|
|
if (this.m_OnLine != null)
|
|
this.m_OnLine(line);
|
|
}
|
|
|
|
public override System.Text.Encoding Encoding
|
|
{
|
|
get
|
|
{
|
|
return System.Text.Encoding.ASCII;
|
|
}
|
|
}
|
|
}
|
|
} |