?? ssh2connection.cs
字號:
/* ---------------------------------------------------------------------------
*
* Copyright (c) Routrek Networks, Inc. All Rights Reserved..
*
* This file is a part of the Granados SSH Client Library that is subject to
* the license included in the distributed package.
* You may not use this file except in compliance with the license.
*
* ---------------------------------------------------------------------------
*/
using System;
using System.Collections;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Net.Sockets;
using System.Text;
using System.Security.Cryptography;
using Routrek.PKI;
using Routrek.SSHC;
using Routrek.Toolkit;
namespace Routrek.SSHCV2
{
public sealed class SSH2Connection : SSHConnection {
//packet count for transmission and reception
private int _tSequence;
//MAC for transmission and reception
private MAC _tMAC;
private SSH2PacketBuilder _packetBuilder;
//server info
private SSH2ConnectionInfo _cInfo;
private bool _waitingForPortForwardingResponse;
private KeyExchanger _asyncKeyExchanger;
public SSH2Connection(SSHConnectionParameter param, ISSHConnectionEventReceiver r, string serverversion, string clientversion) : base(param, r) {
_cInfo = new SSH2ConnectionInfo();
_cInfo._serverVersionString = serverversion;
_cInfo._clientVersionString = clientversion;
_packetBuilder = new SSH2PacketBuilder(new SynchronizedSSH2PacketHandler());
}
internal override IByteArrayHandler PacketBuilder {
get {
return _packetBuilder;
}
}
public override SSHConnectionInfo ConnectionInfo {
get {
return _cInfo;
}
}
internal override AuthenticationResult Connect(AbstractSocket s) {
_stream = s;
KeyExchanger kex = new KeyExchanger(this, null);
if(!kex.SynchronousKexExchange()) {
_stream.Close();
return AuthenticationResult.Failure;
}
//Step3 user authentication
ServiceRequest("ssh-userauth");
_authenticationResult = UserAuth();
return _authenticationResult;
}
private void ServiceRequest(string servicename) {
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_SERVICE_REQUEST);
wr.Write(servicename);
TransmitPacket(wr.ToByteArray());
byte[] response = ReceivePacket().Data;
SSH2DataReader re = new SSH2DataReader(response);
PacketType t = re.ReadPacketType();
if(t!=PacketType.SSH_MSG_SERVICE_ACCEPT) {
throw new SSHException("service establishment failed "+t);
}
string s = Encoding.ASCII.GetString(re.ReadString());
if(servicename!=s)
throw new SSHException("protocol error");
}
private AuthenticationResult UserAuth() {
string sn = "ssh-connection";
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_USERAUTH_REQUEST);
wr.Write(_param.UserName);
if(_param.AuthenticationType==AuthenticationType.Password) {
//Password authentication
wr.Write(sn);
wr.Write("password");
wr.Write(false);
wr.Write(_param.Password);
}
else if(_param.AuthenticationType==AuthenticationType.KeyboardInteractive) {
wr.Write(sn);
wr.Write("keyboard-interactive");
wr.Write(""); //lang
wr.Write(""); //submethod
}
else {
//public key authentication
SSH2UserAuthKey kp = SSH2UserAuthKey.FromSECSHStyleFile(_param.IdentityFile, _param.Password);
SSH2DataWriter signsource = new SSH2DataWriter();
signsource.WriteAsString(_sessionID);
signsource.WritePacketType(PacketType.SSH_MSG_USERAUTH_REQUEST);
signsource.Write(_param.UserName);
signsource.Write(sn);
signsource.Write("publickey");
signsource.Write(true);
signsource.Write(SSH2Util.PublicKeyAlgorithmName(kp.Algorithm));
signsource.WriteAsString(kp.GetPublicKeyBlob());
SSH2DataWriter signpack = new SSH2DataWriter();
signpack.Write(SSH2Util.PublicKeyAlgorithmName(kp.Algorithm));
signpack.WriteAsString(kp.Sign(signsource.ToByteArray()));
wr.Write(sn);
wr.Write("publickey");
wr.Write(true);
wr.Write(SSH2Util.PublicKeyAlgorithmName(kp.Algorithm));
wr.WriteAsString(kp.GetPublicKeyBlob());
wr.WriteAsString(signpack.ToByteArray());
}
TransmitPacket(wr.ToByteArray());
_authenticationResult = ProcessAuthenticationResponse();
if(_authenticationResult==AuthenticationResult.Failure)
throw new SSHException(Strings.GetString("AuthenticationFailed"));
return _authenticationResult;
}
private AuthenticationResult ProcessAuthenticationResponse() {
do {
SSH2DataReader response = new SSH2DataReader(ReceivePacket().Data);
PacketType h = response.ReadPacketType();
if(h==PacketType.SSH_MSG_USERAUTH_FAILURE) {
string msg = Encoding.ASCII.GetString(response.ReadString());
return AuthenticationResult.Failure;
}
else if(h==PacketType.SSH_MSG_USERAUTH_BANNER) {
Debug.WriteLine("USERAUTH_BANNER");
}
else if(h==PacketType.SSH_MSG_USERAUTH_SUCCESS) {
_packetBuilder.Handler = new CallbackSSH2PacketHandler(this);
return AuthenticationResult.Success; //successfully exit
}
else if(h==PacketType.SSH_MSG_USERAUTH_INFO_REQUEST) {
string name = Encoding.ASCII.GetString(response.ReadString());
string inst = Encoding.ASCII.GetString(response.ReadString());
string lang = Encoding.ASCII.GetString(response.ReadString());
int num = response.ReadInt32();
string[] prompts = new string[num];
for(int i=0; i<num; i++) {
prompts[i] = Encoding.ASCII.GetString(response.ReadString());
bool echo = response.ReadBool();
}
_eventReceiver.OnAuthenticationPrompt(prompts);
return AuthenticationResult.Prompt;
}
else
throw new SSHException("protocol error: unexpected packet type "+h);
} while(true);
}
public AuthenticationResult DoKeyboardInteractiveAuth(string[] input) {
if(_param.AuthenticationType!=AuthenticationType.KeyboardInteractive)
throw new SSHException("DoKeyboardInteractiveAuth() must be called with keyboard-interactive authentication");
SSH2DataWriter re = new SSH2DataWriter();
re.WritePacketType(PacketType.SSH_MSG_USERAUTH_INFO_RESPONSE);
re.Write(input.Length);
foreach(string t in input)
re.Write(t);
TransmitPacket(re.ToByteArray());
_authenticationResult = ProcessAuthenticationResponse();
//try again on failure
if(_authenticationResult==AuthenticationResult.Failure) {
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_USERAUTH_REQUEST);
wr.Write(_param.UserName);
wr.Write("ssh-connection");
wr.Write("keyboard-interactive");
wr.Write(""); //lang
wr.Write(""); //submethod
TransmitPacket(wr.ToByteArray());
_authenticationResult = ProcessAuthenticationResponse();
}
return _authenticationResult;
}
public override SSHChannel OpenShell(ISSHChannelEventReceiver receiver) {
//open channel
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN);
wr.Write("session");
int local_channel = this.RegisterChannelEventReceiver(null, receiver)._localID;
wr.Write(local_channel);
wr.Write(_param.WindowSize); //initial window size
int windowsize = _param.WindowSize;
wr.Write(_param.MaxPacketSize); //max packet size
SSH2Channel channel = new SSH2Channel(this, ChannelType.Shell, local_channel);
TransmitPacket(wr.ToByteArray());
return channel;
}
public override SSHChannel ForwardPort(ISSHChannelEventReceiver receiver, string remote_host, int remote_port, string originator_host, int originator_port) {
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN);
wr.Write("direct-tcpip");
int local_id = RegisterChannelEventReceiver(null, receiver)._localID;
wr.Write(local_id);
wr.Write(_param.WindowSize); //initial window size
int windowsize = _param.WindowSize;
wr.Write(_param.MaxPacketSize); //max packet size
wr.Write(remote_host);
wr.Write(remote_port);
wr.Write(originator_host);
wr.Write(originator_port);
SSH2Channel channel = new SSH2Channel(this, ChannelType.ForwardedLocalToRemote, local_id);
TransmitPacket(wr.ToByteArray());
return channel;
}
public override void ListenForwardedPort(string allowed_host, int bind_port) {
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_GLOBAL_REQUEST);
wr.Write("tcpip-forward");
wr.Write(true);
wr.Write(allowed_host);
wr.Write(bind_port);
_waitingForPortForwardingResponse = true;
TransmitPacket(wr.ToByteArray());
}
public override void CancelForwardedPort(string host, int port) {
SSH2DataWriter wr = new SSH2DataWriter();
wr.WritePacketType(PacketType.SSH_MSG_GLOBAL_REQUEST);
wr.Write("cancel-tcpip-forward");
wr.Write(true);
wr.Write(host);
wr.Write(port);
TransmitPacket(wr.ToByteArray());
}
private void ProcessPortforwardingRequest(ISSHConnectionEventReceiver receiver, SSH2DataReader reader) {
string method = Encoding.ASCII.GetString(reader.ReadString());
int remote_channel = reader.ReadInt32();
int window_size = reader.ReadInt32(); //skip initial window size
int servermaxpacketsize = reader.ReadInt32();
string host = Encoding.ASCII.GetString(reader.ReadString());
int port = reader.ReadInt32();
string originator_ip = Encoding.ASCII.GetString(reader.ReadString());
int originator_port = reader.ReadInt32();
PortForwardingCheckResult r = receiver.CheckPortForwardingRequest(host,port,originator_ip,originator_port);
SSH2DataWriter wr = new SSH2DataWriter();
if(r.allowed) {
//send OPEN_CONFIRMATION
SSH2Channel channel = new SSH2Channel(this, ChannelType.ForwardedRemoteToLocal, RegisterChannelEventReceiver(null, r.channel)._localID, remote_channel, servermaxpacketsize);
wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
wr.Write(remote_channel);
wr.Write(channel.LocalChannelID);
wr.Write(_param.WindowSize); //initial window size
wr.Write(_param.MaxPacketSize); //max packet size
receiver.EstablishPortforwarding(r.channel, channel);
}
else {
wr.WritePacketType(PacketType.SSH_MSG_CHANNEL_OPEN_FAILURE);
wr.Write(remote_channel);
wr.Write(r.reason_code);
wr.Write(r.reason_message);
wr.Write(""); //lang tag
}
TransmitPacket(wr.ToByteArray());
}
internal SSH2Packet TransmitPacket(byte[] payload) {
lock(_tLockObject) {
SSH2Packet p = SSH2Packet.FromPlainPayload(payload, _tCipher==null? 8 : _tCipher.BlockSize, _param.Random);
if(_tMAC!=null) p.CalcHash(_tMAC, _tSequence);
_tSequence++;
p.WriteTo(_stream, _tCipher);
return p;
}
}
//synchronous reception
internal SSH2Packet ReceivePacket() {
while(true) {
SSH2Packet p = null;
SynchronizedSSH2PacketHandler handler = (SynchronizedSSH2PacketHandler)_packetBuilder.Handler;
if(!handler.HasPacket) {
handler.Wait();
if(handler.State==ReceiverState.Error)
throw new SSHException(handler.ErrorMessage);
else if(handler.State==ReceiverState.Closed)
throw new SSHException("socket closed");
}
p = handler.PopPacket();
SSH2DataReader r = new SSH2DataReader(p.Data);
PacketType pt = r.ReadPacketType();
if(pt==PacketType.SSH_MSG_IGNORE) {
if(_eventReceiver!=null) _eventReceiver.OnIgnoreMessage(r.ReadString());
}
else if(pt==PacketType.SSH_MSG_DEBUG) {
bool f = r.ReadBool();
if(_eventReceiver!=null) _eventReceiver.OnDebugMessage(f, r.ReadString());
}
else
return p;
}
}
internal void AsyncReceivePacket(SSH2Packet packet) {
try {
ProcessPacket(packet);
}
catch(Exception ex) {
//Debug.WriteLine(ex.StackTrace);
if(!_closed)
_eventReceiver.OnError(ex, ex.Message);
}
}
private bool ProcessPacket(SSH2Packet packet) {
//Debug.WriteLine("ProcessPacket pt="+pt);
SSH2DataReader r = new SSH2DataReader(packet.Data);
PacketType pt = r.ReadPacketType();
if(pt==PacketType.SSH_MSG_DISCONNECT) {
int errorcode = r.ReadInt32();
//string description = Encoding.ASCII.GetString(r.ReadString());
_eventReceiver.OnConnectionClosed();
return false;
}
else if(_waitingForPortForwardingResponse) {
if(pt!=PacketType.SSH_MSG_REQUEST_SUCCESS)
_eventReceiver.OnUnknownMessage((byte)pt, r.Image);
_waitingForPortForwardingResponse = false;
return true;
}
else if(pt==PacketType.SSH_MSG_CHANNEL_OPEN) {
ProcessPortforwardingRequest(_eventReceiver, r);
return true;
}
else if(pt>=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION && pt<=PacketType.SSH_MSG_CHANNEL_FAILURE) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -