singrdk/base/Windows/telnetd/Program.cs

174 lines
5.8 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
// Microsoft Research Singularity
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Project: telnet daemon (testing purposs only)
//
// NOTES / CAVEATS:
// - Doesn't echo keyboard input until carriage return.
// - Doesn't support control sequences (Ctrl-C, history, etc.)
// - Doesn't negotiate. Only works with the Windows XP telent client.
// - Doesn't shutdown gracefully.
// - Doesn't try to be robust (handle exceptions, etc.)
//
using System;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
namespace telnetd
{
class Program
{
private Process p;
private byte[] bufOutput;
private byte[] bufError;
private TcpClient client;
private NetworkStream stm;
private byte[] bufNet;
const byte IAC = 255; // telnet "interpret as command" escape
const byte CODE_WILL = 251; // telnet commands
const byte CODE_WONT = 252;
const byte CODE_DO = 253;
const byte CODE_DONT = 254;
const byte OPTION_ECHO = 0x01; // telnet command options
const byte OPTION_SUPPRESSGA = 0x03;
Program(TcpClient c)
{
client = c;
stm = client.GetStream();
}
void SendString(string s)
{
Byte[] data = System.Text.Encoding.ASCII.GetBytes(s);
stm.Write(data, 0, data.Length);
}
void SendOption(byte code, byte option)
{
byte[] data = new byte[3];
data[0] = IAC;
data[1] = code;
data[2] = option;
stm.Write(data, 0, data.Length);
}
void ReadOption(out byte code, out byte option)
{
int b1 = stm.ReadByte();
int b2 = stm.ReadByte();
int b3 = stm.ReadByte();
code = (byte)b2;
option = (byte)b3;
}
void StdOutCallback(IAsyncResult result)
{
int cb = p.StandardOutput.BaseStream.EndRead(result);
if (cb > 0) {
stm.Write(bufOutput, 0, cb);
}
p.StandardOutput.BaseStream.BeginRead(bufOutput, 0, bufOutput.Length, StdOutCallback, null);
}
void StdErrCallback(IAsyncResult result)
{
int cb = p.StandardError.BaseStream.EndRead(result);
if (cb > 0) {
stm.Write(bufError, 0, cb);
}
p.StandardError.BaseStream.BeginRead(bufError, 0, bufError.Length, StdErrCallback, null);
}
void NetworkReadCallback(IAsyncResult result)
{
int cb = stm.EndRead(result);
if (cb > 0) {
ProcessEscapes(bufNet, cb);
string s = System.Text.Encoding.ASCII.GetString(bufNet, 0, cb);
p.StandardInput.Write(s);
}
IAsyncResult res = stm.BeginRead(bufNet, 0, bufNet.Length, NetworkReadCallback, null);
}
int ProcessEscapes(byte[] buf, int cb)
{
// TODO:
//
//for (int i = 0; i < cb; i++) {
// if (bufNet[i] == IAC) {
// Debug.WriteLine("IAC " + bufNet[i + 1] + " " + bufNet[i + 2]);
// }
//}
//
return cb;
}
void Run()
{
// Negotiate
SendOption(CODE_WILL, OPTION_ECHO);
SendOption(CODE_WILL, OPTION_SUPPRESSGA);
byte code, option;
ReadOption(out code, out option);
ReadOption(out code, out option);
// Send welcome message
SendString("Welcome to the Singularity Telnet Service on ");
IPGlobalProperties ipGlobal = IPGlobalProperties.GetIPGlobalProperties();
SendString(ipGlobal.HostName);
SendString("\r\n\r\n");
// Create redirected command shell with ansi pipes
p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/A";
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.Start();
// Begin the async stdio reads
bufOutput = new byte[256];
bufError = new byte[256];
p.StandardOutput.BaseStream.BeginRead(bufOutput, 0, bufOutput.Length, StdOutCallback, null);
p.StandardError.BaseStream.BeginRead(bufError, 0, bufError.Length, StdErrCallback, null);
// Begin the async network reads
bufNet = new byte[256];
IAsyncResult res = stm.BeginRead(bufNet, 0, bufNet.Length, NetworkReadCallback, null);
// Wait for the shell to exit
p.WaitForExit();
client.Close();
}
static void Main(string[] args)
{
// Listen for incoming telnet sessions
TcpListener listener = null;
try {
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 23);
listener.Start();
while (true) {
TcpClient c = listener.AcceptTcpClient();
Program p = new Program(c);
p.Run();
}
}
catch (SocketException ex) {
Console.WriteLine("SocketException {0}", ex);
}
finally {
if (listener != null)
listener.Stop();
}
}
}
}