Initial checkin

This commit is contained in:
olegkap_cp
2010-08-10 18:20:43 +00:00
parent 8302a5fcb1
commit b86e465fd0
119 changed files with 6949 additions and 0 deletions
@@ -0,0 +1,7 @@
namespace Renci.SshClient.Algorithms
{
public abstract class Algorithm
{
public abstract string Name { get; }
}
}
@@ -0,0 +1,23 @@
namespace Renci.SshClient.Algorithms
{
public abstract class Compression : Algorithm
{
private class CompressionNone : Compression
{
public override string Name
{
get { return "none"; }
}
}
static Compression()
{
Compression.None = new CompressionNone
{
};
}
public static Compression None { get; private set; }
}
}
@@ -0,0 +1,456 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using Renci.SshClient.Common;
using Renci.SshClient.Messages;
using Renci.SshClient.Messages.Transport;
namespace Renci.SshClient.Algorithms
{
internal abstract class KeyExchange : Algorithm
{
/// <summary>
/// Creates the key exchange algorithm to be used for key exchange.
/// </summary>
/// <param name="message">The message.</param>
/// <returns></returns>
internal static KeyExchange Create(KeyExchangeInitMessage message, SessionInfo sessionInfo)
{
// TODO: Determine key exchange algorithm
var keyExchangeAlgorithm = (from s in message.KeyExchangeAlgorithms
from c in Settings.KeyExchangeAlgorithms.Keys
where s == c
select c).FirstOrDefault();
// TODO: If dont agree on algorithms then send disconnect message
if (keyExchangeAlgorithm == null)
{
throw new InvalidDataException("Failed to negotiate key exchange algorithm.");
}
return Settings.KeyExchangeAlgorithms[keyExchangeAlgorithm](sessionInfo);
}
/// <summary>
/// Specifies negotiated algorithm to encrypt information when sent to the server
/// </summary>
private Func<SymmetricAlgorithm> _clientEncryptionAlgorithm;
/// <summary>
/// Specifies negotiated algorithm to decrypt information from the server
/// </summary>
private Func<SymmetricAlgorithm> _serverDecryptionAlgorithm;
/// <summary>
/// Specifies negotiated HMAC algorithm to use for client
/// </summary>
private Func<IEnumerable<byte>, HMAC> _clientHmacAlgorithm;
/// <summary>
/// Specifies negotiated HMAC algorithm to use for server
/// </summary>
private Func<IEnumerable<byte>, HMAC> _serverHmacAlgorithm;
private IEnumerable<byte> _exchangeHash;
/// <summary>
/// Gets hash value
/// </summary>
public IEnumerable<byte> ExchangeHash
{
get
{
if (this._exchangeHash == null)
{
this._exchangeHash = this.CalculateHash();
}
return this._exchangeHash;
}
}
public HMAC ServerMac { get; set; }
public HMAC ClientMac { get; set; }
public ICryptoTransform Encryption { get; set; }
public ICryptoTransform Decryption { get; set; }
public Compression ServerDecompression { get; set; }
public Compression ClientCompression { get; set; }
public bool IsCompleted { get; protected set; }
public bool IsSuccessed { get; protected set; }
protected SessionInfo SessionInfo { get; private set; }
protected string ClientPayload { get; set; }
protected string ServerPayload { get; set; }
protected string HostKey { get; set; }
protected BigInteger ClientExchangeValue { get; set; }
protected BigInteger ServerExchangeValue { get; set; }
protected BigInteger SharedKey { get; set; }
protected string Signature { get; set; }
public event EventHandler<KeyExchangeCompletedEventArgs> Completed;
public event EventHandler<KeyExchangeFailedEventArgs> Failed;
public KeyExchange(SessionInfo sessionInfo)
{
this.SessionInfo = sessionInfo;
this.ServerDecompression = Compression.None;
this.ClientCompression = Compression.None;
}
public virtual void Start()
{
// TODO: If key exchange initiated by the client no need to send client message again
var clientMessage = new KeyExchangeInitMessage()
{
KeyExchangeAlgorithms = Settings.KeyExchangeAlgorithms.Keys,
ServerHostKeyAlgorithms = Settings.HostKeyAlgorithms.Keys,
EncryptionAlgorithmsClientToServer = Settings.Encryptions.Keys,
EncryptionAlgorithmsServerToClient = Settings.Encryptions.Keys,
MacAlgorithmsClientToSserver = Settings.HmacAlgorithms.Keys,
MacAlgorithmsServerToClient = Settings.HmacAlgorithms.Keys,
CompressionAlgorithmsClientToServer = new string[] { "none" },
CompressionAlgorithmsServerToClient = new string[] { "none" },
LanguagesClientToServer = new string[] { string.Empty },
LanguagesServerToClient = new string[] { string.Empty },
FirstKexPacketFollows = false,
Reserved = 0,
};
this.ClientPayload = clientMessage.GetBytes().GetSshString();
this.SendMessage(clientMessage);
}
public virtual void Start(KeyExchangeInitMessage message)
{
this.Start();
// Determine encryption algorithm
var clientEncryptionAlgorithmName = (from a in message.EncryptionAlgorithmsClientToServer
from b in Settings.Encryptions.Keys
where a == b
select a).FirstOrDefault();
if (string.IsNullOrEmpty(clientEncryptionAlgorithmName))
{
throw new InvalidOperationException("Client encryption algorithm not found");
}
this._clientEncryptionAlgorithm = Settings.Encryptions[clientEncryptionAlgorithmName];
// Determine encryption algorithm
var serverDecryptionAlgorithmName = (from a in message.EncryptionAlgorithmsServerToClient
from b in Settings.Encryptions.Keys
where a == b
select a).FirstOrDefault();
if (string.IsNullOrEmpty(serverDecryptionAlgorithmName))
{
throw new InvalidOperationException("Server decryption algorithm not found");
}
this._serverDecryptionAlgorithm = Settings.Encryptions[clientEncryptionAlgorithmName];
// Determine client hmac algorithm
var clientHmacAlgorithmName = (from a in message.MacAlgorithmsClientToSserver
from b in Settings.HmacAlgorithms.Keys
where a == b
select a).FirstOrDefault();
if (string.IsNullOrEmpty(clientHmacAlgorithmName))
{
throw new InvalidOperationException("Server HMAC algorithm not found");
}
this._clientHmacAlgorithm = Settings.HmacAlgorithms[clientHmacAlgorithmName];
// Determine server hmac algorithm
var serverHmacAlgorithmName = (from a in message.MacAlgorithmsServerToClient
from b in Settings.HmacAlgorithms.Keys
where a == b
select a).FirstOrDefault();
if (string.IsNullOrEmpty(serverHmacAlgorithmName))
{
throw new InvalidOperationException("Server HMAC algorithm not found");
}
this._serverHmacAlgorithm = Settings.HmacAlgorithms[serverHmacAlgorithmName];
}
public virtual void Finish()
{
// TODO: Validate that all required properties are set
if (this.SessionInfo.SessionId == null)
{
this.SessionInfo.SessionId = this.ExchangeHash;
}
// Set encryption
ICryptoTransform encryption;
using (var clientAlgorithm = this._clientEncryptionAlgorithm())
{
// Calculate client to server initial IV
var clientValue = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'A', this.SessionInfo.SessionId));
// Calculate client to server encryption
var clientKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'C', this.SessionInfo.SessionId));
clientKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, clientKey, clientAlgorithm.KeySize / 8);
clientAlgorithm.Mode = System.Security.Cryptography.CipherMode.CBC;
clientAlgorithm.Padding = System.Security.Cryptography.PaddingMode.None;
encryption = clientAlgorithm.CreateEncryptor(clientKey.Take(clientAlgorithm.KeySize / 8).ToArray(), clientValue.Take(clientAlgorithm.BlockSize / 8).ToArray());
}
// Set decryption
ICryptoTransform decryption;
using (var serverAlgorithm = this._serverDecryptionAlgorithm())
{
// Calculate server to client initial IV
var serverValue = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'B', this.SessionInfo.SessionId));
// Calculate server to client encryption
var serverKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'D', this.SessionInfo.SessionId));
serverKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, serverKey, serverAlgorithm.KeySize / 8);
serverAlgorithm.Mode = System.Security.Cryptography.CipherMode.CBC;
serverAlgorithm.Padding = System.Security.Cryptography.PaddingMode.None;
decryption = serverAlgorithm.CreateDecryptor(serverKey.Take(serverAlgorithm.KeySize / 8).ToArray(), serverValue.Take(serverAlgorithm.BlockSize / 8).ToArray());
}
// Calculate client to server integrity
var MACc2s = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'E', this.SessionInfo.SessionId));
var clientMac = this._clientHmacAlgorithm(MACc2s);
// Calculate server to client integrity
var MACs2c = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'F', this.SessionInfo.SessionId));
var serverMac = this._serverHmacAlgorithm(MACs2c);
// TODO: Create compression and decompression objects if any
this.Decryption = decryption;
this.Encryption = encryption;
this.ServerDecompression = Compression.None;
this.ClientCompression = Compression.None;
this.ServerMac = serverMac;
this.ClientMac = clientMac;
this.IsCompleted = true;
this.RaiseCompleted();
}
/// <summary>
/// Raises the Completed event.
/// </summary>
/// <param name="sessionId">The session id.</param>
/// <param name="decryption">The decryption to be used.</param>
/// <param name="encryption">The encryption to be used.</param>
/// <param name="serverDecompression">The server decompression.</param>
/// <param name="clientCompression">The client compression.</param>
/// <param name="serverMac">The server mac.</param>
/// <param name="clientMac">The client mac.</param>
protected void RaiseCompleted()
{
if (this.Completed != null)
{
this.Completed(this, new KeyExchangeCompletedEventArgs());
}
}
/// <summary>
/// Raises the Failed event.
/// </summary>
/// <param name="message">The fail reason message.</param>
protected void RaiseFailed(string message)
{
if (this.Failed != null)
{
this.Failed(this, new KeyExchangeFailedEventArgs(message));
}
}
protected virtual IEnumerable<byte> Hash(IEnumerable<byte> hashBytes)
{
using (var md = new System.Security.Cryptography.SHA1CryptoServiceProvider())
{
using (var cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, md, System.Security.Cryptography.CryptoStreamMode.Write))
{
var hashData = hashBytes.ToArray();
cs.Write(hashData, 0, hashData.Length);
cs.Close();
return md.Hash;
}
}
}
protected bool ValidateExchangeHash()
{
var bytes = this.HostKey.GetSshBytes();
var length = BitConverter.ToUInt32(bytes.Take(4).Reverse().ToArray(), 0);
var algorithmName = bytes.Skip(4).Take((int)length).GetSshString();
var data = bytes.Skip(4 + algorithmName.Length);
var signature = Settings.HostKeyAlgorithms[algorithmName](data);
return signature.ValidateSignature(this.ExchangeHash, this.Signature.GetSshBytes());
}
protected void SendMessage(Message message)
{
this.SessionInfo.SendMessage(message);
}
private IEnumerable<byte> CalculateHash()
{
var hashData = new _ExchangeHashData
{
ClientVersion = this.SessionInfo.ClientVersion,
ServerVersion = this.SessionInfo.ServerVersion,
ClientPayload = this.ClientPayload,
ServerPayload = this.ServerPayload,
HostKey = this.HostKey,
ClientExchangeValue = this.ClientExchangeValue,
ServerExchangeValue = this.ServerExchangeValue,
SharedKey = this.SharedKey,
}.GetBytes();
return this.Hash(hashData);
}
private IEnumerable<byte> GenerateSessionKey(BigInteger sharedKey, IEnumerable<byte> exchangeHash, IEnumerable<byte> key, int size)
{
var result = new List<byte>(key);
while (size > result.Count)
{
result.AddRange(this.Hash(new _SessionKeyAdjustment
{
SharedKey = sharedKey,
ExcahngeHash = exchangeHash,
Key = key,
}.GetBytes()));
}
return result;
}
private IEnumerable<byte> GenerateSessionKey(BigInteger sharedKey, IEnumerable<byte> exchangeHash, char p, IEnumerable<byte> sessionId)
{
return new _SessionKeyGeneration
{
SharedKey = sharedKey,
ExchangeHash = exchangeHash,
Char = p,
SessionId = sessionId,
}.GetBytes();
}
private class _ExchangeHashData : SshData
{
public string ServerVersion { get; set; }
public string ClientVersion { get; set; }
public string ClientPayload { get; set; }
public string ServerPayload { get; set; }
public string HostKey { get; set; }
public UInt32? MinimumGroupSize { get; set; }
public UInt32? PreferredGroupSize { get; set; }
public UInt32? MaximumGroupSize { get; set; }
public IEnumerable<byte> Prime { get; set; }
public BigInteger ClientExchangeValue { get; set; }
public BigInteger ServerExchangeValue { get; set; }
public BigInteger SharedKey { get; set; }
protected override void LoadData()
{
throw new System.NotImplementedException();
}
protected override void SaveData()
{
this.Write(this.ClientVersion);
this.Write(this.ServerVersion);
this.Write(this.ClientPayload);
this.Write(this.ServerPayload);
this.Write(this.HostKey);
if (this.MinimumGroupSize.HasValue)
this.Write(this.MinimumGroupSize.Value);
if (this.PreferredGroupSize.HasValue)
this.Write(this.PreferredGroupSize.Value);
if (this.MaximumGroupSize.HasValue)
this.Write(this.MaximumGroupSize.Value);
if (this.Prime != null)
this.Write(this.Prime);
this.Write(this.ClientExchangeValue);
this.Write(this.ServerExchangeValue);
this.Write(this.SharedKey);
}
}
private class _SessionKeyGeneration : SshData
{
public BigInteger SharedKey { get; set; }
public IEnumerable<byte> ExchangeHash { get; set; }
public char Char { get; set; }
public IEnumerable<byte> SessionId { get; set; }
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
this.Write(this.SharedKey);
this.Write(this.ExchangeHash);
this.Write((byte)this.Char);
this.Write(this.SessionId);
}
}
private class _SessionKeyAdjustment : SshData
{
public BigInteger SharedKey { get; set; }
public IEnumerable<byte> ExcahngeHash { get; set; }
public IEnumerable<byte> Key { get; set; }
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
this.Write(this.SharedKey);
this.Write(this.ExcahngeHash);
this.Write(this.Key);
}
}
}
}
@@ -0,0 +1,8 @@
using System;
namespace Renci.SshClient.Algorithms
{
internal class KeyExchangeCompletedEventArgs : EventArgs
{
}
}
@@ -0,0 +1,125 @@
using System;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using Renci.SshClient.Common;
using Renci.SshClient.Messages;
using Renci.SshClient.Messages.Transport;
namespace Renci.SshClient.Algorithms
{
internal class KeyExchangeDiffieHellman : KeyExchange
{
private static RNGCryptoServiceProvider _randomizer = new System.Security.Cryptography.RNGCryptoServiceProvider();
private static BigInteger _prime = new BigInteger(new byte[] { (byte)0x00,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xC9,(byte)0x0F,(byte)0xDA,(byte)0xA2,(byte)0x21,(byte)0x68,(byte)0xC2,(byte)0x34,
(byte)0xC4,(byte)0xC6,(byte)0x62,(byte)0x8B,(byte)0x80,(byte)0xDC,(byte)0x1C,(byte)0xD1,
(byte)0x29,(byte)0x02,(byte)0x4E,(byte)0x08,(byte)0x8A,(byte)0x67,(byte)0xCC,(byte)0x74,
(byte)0x02,(byte)0x0B,(byte)0xBE,(byte)0xA6,(byte)0x3B,(byte)0x13,(byte)0x9B,(byte)0x22,
(byte)0x51,(byte)0x4A,(byte)0x08,(byte)0x79,(byte)0x8E,(byte)0x34,(byte)0x04,(byte)0xDD,
(byte)0xEF,(byte)0x95,(byte)0x19,(byte)0xB3,(byte)0xCD,(byte)0x3A,(byte)0x43,(byte)0x1B,
(byte)0x30,(byte)0x2B,(byte)0x0A,(byte)0x6D,(byte)0xF2,(byte)0x5F,(byte)0x14,(byte)0x37,
(byte)0x4F,(byte)0xE1,(byte)0x35,(byte)0x6D,(byte)0x6D,(byte)0x51,(byte)0xC2,(byte)0x45,
(byte)0xE4,(byte)0x85,(byte)0xB5,(byte)0x76,(byte)0x62,(byte)0x5E,(byte)0x7E,(byte)0xC6,
(byte)0xF4,(byte)0x4C,(byte)0x42,(byte)0xE9,(byte)0xA6,(byte)0x37,(byte)0xED,(byte)0x6B,
(byte)0x0B,(byte)0xFF,(byte)0x5C,(byte)0xB6,(byte)0xF4,(byte)0x06,(byte)0xB7,(byte)0xED,
(byte)0xEE,(byte)0x38,(byte)0x6B,(byte)0xFB,(byte)0x5A,(byte)0x89,(byte)0x9F,(byte)0xA5,
(byte)0xAE,(byte)0x9F,(byte)0x24,(byte)0x11,(byte)0x7C,(byte)0x4B,(byte)0x1F,(byte)0xE6,
(byte)0x49,(byte)0x28,(byte)0x66,(byte)0x51,(byte)0xEC,(byte)0xE6,(byte)0x53,(byte)0x81,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}.Reverse().ToArray());
private static BigInteger _group = new BigInteger(new byte[] { 2 });
private BigInteger _randomValue;
public override string Name
{
get { return "diffie-hellman-group1-sha1"; }
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyExchangeDiffieHellman"/> class.
/// </summary>
/// <param name="sessionInfo">The session information.</param>
internal KeyExchangeDiffieHellman(SessionInfo sessionInfo)
: base(sessionInfo)
{
}
public override void Start(KeyExchangeInitMessage message)
{
base.Start(message);
// TODO: Calculate random value correctly, enforce limits
var clientExchangeValue = BigInteger.Zero;
while (clientExchangeValue < 1 || clientExchangeValue > ((KeyExchangeDiffieHellman._prime - 1) / 2))
{
this._randomValue = new BigInteger(new Random().NextDouble() * long.MaxValue);
clientExchangeValue = System.Numerics.BigInteger.ModPow(KeyExchangeDiffieHellman._group, this._randomValue, KeyExchangeDiffieHellman._prime);
}
this.ServerPayload = message.GetBytes().GetSshString();
this.ClientExchangeValue = clientExchangeValue;
// Register expected message replies
Message.RegisterMessageType<KeyExchangeDhReplyMessage>(MessageTypes.KeyExchangeDhReply);
this.SendMessage(new KeyExchangeDhInitMessage
{
E = this.ClientExchangeValue,
});
this.SessionInfo.MessageReceived += SessionInfo_MessageReceived;
}
public override void Finish()
{
base.Finish();
this.SessionInfo.MessageReceived -= SessionInfo_MessageReceived;
}
private void SessionInfo_MessageReceived(object sender, MessageReceivedEventArgs e)
{
this.HandleMessage((dynamic)e.Message);
}
private void HandleMessage<T>(T message) where T : Message, new()
{
// Do nothing, handle only known messages
}
/// <summary>
/// Handles the KeyExchangeDhReplyMessage message.
/// </summary>
/// <param name="message">The message.</param>
private void HandleMessage(KeyExchangeDhReplyMessage message)
{
// Unregister message once received
Message.UnRegisterMessageType(MessageTypes.KeyExchangeDhReply);
var sharedKey = System.Numerics.BigInteger.ModPow(message.F, this._randomValue, KeyExchangeDiffieHellman._prime);
this.ServerExchangeValue = message.F;
this.HostKey = message.HostKey;
this.SharedKey = sharedKey;
this.Signature = message.Signature;
// Validate hash value
if (this.ValidateExchangeHash())
{
this.IsSuccessed = true;
this.SendMessage(new NewKeysMessage());
}
else
{
this.IsSuccessed = false;
this.RaiseFailed("Key negotiationed failed.");
}
}
}
}
@@ -0,0 +1,14 @@
using System;
namespace Renci.SshClient.Algorithms
{
internal class KeyExchangeFailedEventArgs : EventArgs
{
public string Message { get; private set; }
public KeyExchangeFailedEventArgs(string message)
{
this.Message = message;
}
}
}
@@ -0,0 +1,15 @@
using System;
using Renci.SshClient.Messages;
namespace Renci.SshClient.Algorithms
{
internal class KeyExchangeSendMessageEventArgs : EventArgs
{
public KeyExchangeSendMessageEventArgs(Message message)
{
this.Message = message;
}
public Message Message { get; private set; }
}
}
@@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace Renci.SshClient.Algorithms
{
internal abstract class Signature : Algorithm
{
protected IEnumerable<byte> Data { get; private set; }
public Signature(IEnumerable<byte> data)
{
this.Data = data;
}
public abstract bool ValidateSignature(IEnumerable<byte> hash, IEnumerable<byte> signature);
}
}
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
namespace Renci.SshClient.Algorithms
{
internal class SignatureDss : Signature
{
public override string Name
{
get { return "ssh-dss"; }
}
public SignatureDss(IEnumerable<byte> data)
: base(data)
{
}
public override bool ValidateSignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
{
var pLength = BitConverter.ToUInt32(this.Data.Take(4).Reverse().ToArray(), 0);
var pData = this.Data.Skip(4).Take((int)pLength).ToArray();
var qLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)pLength).Take(4).Reverse().ToArray(), 0);
var qData = this.Data.Skip(4 + (int)pLength + 4).Take((int)qLength).ToArray();
var gLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)pLength + 4 + (int)qLength).Take(4).Reverse().ToArray(), 0);
var gData = this.Data.Skip(4 + (int)pLength + 4 + (int)qLength + 4).Take((int)gLength).ToArray();
var xLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)pLength + 4 + (int)qLength + 4 + (int)gLength).Take(4).Reverse().ToArray(), 0);
var xData = this.Data.Skip(4 + (int)pLength + 4 + (int)qLength + 4 + (int)xLength + 4).Take((int)xLength).ToArray();
using (var sha1 = new SHA1CryptoServiceProvider())
{
using (var cs = new CryptoStream(System.IO.Stream.Null, sha1, CryptoStreamMode.Write))
{
var data = hash.ToArray();
cs.Write(data, 0, data.Length);
cs.Close();
}
using (var dsa = new DSACryptoServiceProvider())
{
dsa.ImportParameters(new DSAParameters
{
X = xData.TrimLeadinZero().ToArray(),
P = pData.TrimLeadinZero().ToArray(),
Q = qData.TrimLeadinZero().ToArray(),
G = gData.TrimLeadinZero().ToArray(),
});
var dsaDeformatter = new DSASignatureDeformatter(dsa);
dsaDeformatter.SetHashAlgorithm("SHA1");
long i = 0;
long j = 0;
byte[] tmp;
var sig = signature.ToArray();
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0)
{
long i1 = (sig[i++] << 24) & 0xff000000;
long i2 = (sig[i++] << 16) & 0x00ff0000;
long i3 = (sig[i++] << 8) & 0x0000ff00;
long i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
i += j;
i1 = (sig[i++] << 24) & 0xff000000;
i2 = (sig[i++] << 16) & 0x00ff0000;
i3 = (sig[i++] << 8) & 0x0000ff00;
i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
tmp = new byte[j];
Array.Copy(sig, i, tmp, 0, j);
sig = tmp;
}
return dsaDeformatter.VerifySignature(sha1, sig);
}
}
}
}
}
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
namespace Renci.SshClient.Algorithms
{
internal class SignatureRsa : Signature
{
public override string Name
{
get { return "ssh-rsa"; }
}
public SignatureRsa(IEnumerable<byte> data)
: base(data)
{
}
public override bool ValidateSignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
{
var exponentLength = BitConverter.ToUInt32(this.Data.Take(4).Reverse().ToArray(), 0);
var exponentData = this.Data.Skip(4).Take((int)exponentLength).ToArray();
var modulusLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)exponentLength).Take(4).Reverse().ToArray(), 0);
var modulusData = this.Data.Skip(4 + (int)exponentLength + 4).Take((int)modulusLength).ToArray();
using (var sha1 = new SHA1CryptoServiceProvider())
{
using (var cs = new CryptoStream(System.IO.Stream.Null, sha1, CryptoStreamMode.Write))
{
var data = hash.ToArray();
cs.Write(data, 0, data.Length);
cs.Close();
}
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(new RSAParameters
{
Exponent = exponentData,
Modulus = modulusData.TrimLeadinZero().ToArray(),
});
var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA1");
long i = 0;
long j = 0;
byte[] tmp;
var sig = signature.ToArray();
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0)
{
long i1 = (sig[i++] << 24) & 0xff000000;
long i2 = (sig[i++] << 16) & 0x00ff0000;
long i3 = (sig[i++] << 8) & 0x0000ff00;
long i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
i += j;
i1 = (sig[i++] << 24) & 0xff000000;
i2 = (sig[i++] << 16) & 0x00ff0000;
i3 = (sig[i++] << 8) & 0x0000ff00;
i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
tmp = new byte[j];
Array.Copy(sig, i, tmp, 0, j);
sig = tmp;
}
return rsaDeformatter.VerifySignature(sha1, sig);
}
}
}
}
}
@@ -0,0 +1,257 @@
using System;
using System.Text;
using System.Threading;
using Renci.SshClient.Common;
using Renci.SshClient.Messages;
using Renci.SshClient.Messages.Connection;
namespace Renci.SshClient.Channels
{
internal abstract class Channel
{
private static uint _channelCounter = 0;
private static object _lock = new object();
private EventWaitHandle _channelOpenWaitHandle = new AutoResetEvent(false);
private EventWaitHandle _channelClosedWaitHandle = new AutoResetEvent(false);
private uint _initialWindowSize = 0x100000;
//private uint _maximumPacketSize = 0x4000;
private uint _maximumPacketSize = 1024;
protected StringBuilder ChannelData { get; private set; }
protected StringBuilder ChannelExtendedData { get; private set; }
public abstract ChannelTypes ChannelType { get; }
public uint ClientChannelNumber { get; set; }
public uint ServerChannelNumber { get; set; }
public uint WindowSize { get; set; }
public uint PacketSize { get; set; }
public bool IsOpen { get; protected set; }
protected SessionInfo SessionInfo { get; private set; }
public Channel(SessionInfo sessionInfo, uint windowSize, uint packetSize)
{
this._initialWindowSize = windowSize;
this._maximumPacketSize = Math.Max(packetSize, 0x8000); // Ensure minimum maximum packet size of 0x8000 bytes
Message.RegisterMessageType<ChannelOpenConfirmationMessage>(MessageTypes.ChannelOpenConfirmation);
Message.RegisterMessageType<ChannelOpenFailureMessage>(MessageTypes.ChannelOpenFailure);
Message.RegisterMessageType<ChannelWindowAdjustMessage>(MessageTypes.ChannelWindowAdjust);
Message.RegisterMessageType<ChannelExtendedDataMessage>(MessageTypes.ChannelExtendedData);
Message.RegisterMessageType<ChannelRequestMessage>(MessageTypes.ChannelRequest);
Message.RegisterMessageType<ChannelSuccessMessage>(MessageTypes.ChannelSuccess);
Message.RegisterMessageType<ChannelDataMessage>(MessageTypes.ChannelData);
Message.RegisterMessageType<ChannelEofMessage>(MessageTypes.ChannelEof);
Message.RegisterMessageType<ChannelCloseMessage>(MessageTypes.ChannelClose);
lock (_lock)
{
// TODO: Refactor to make channel number to come from the session, to avoid situation where new session will be open and first channel number will not be 0
this.ClientChannelNumber = _channelCounter++;
}
this.SessionInfo = sessionInfo;
this.ChannelData = new StringBuilder((int)this._initialWindowSize);
this.ChannelExtendedData = new StringBuilder((int)this._initialWindowSize);
this.WindowSize = this._initialWindowSize; // Initial window size
this.PacketSize = this._maximumPacketSize; // Maximum packet size
}
public Channel(SessionInfo sessionInfo)
: this(sessionInfo, 0x100000, 0x8000)
{
}
public virtual void Open()
{
this.SessionInfo.MessageReceived += SessionInfo_MessageReceived;
// Open session channel
if (!this.IsOpen)
{
this.SendMessage(new ChannelOpenMessage
{
ChannelName = "session",
ChannelNumber = this.ClientChannelNumber,
InitialWindowSize = this.WindowSize,
MaximumPacketSize = this.PacketSize,
});
this.SessionInfo.WaitHandle(this._channelOpenWaitHandle);
}
}
public virtual void Close()
{
if (this.IsOpen)
{
this.SendMessage(new ChannelCloseMessage
{
ChannelNumber = this.ServerChannelNumber,
});
// Wait for channel to be closed
this.SessionInfo.WaitHandle(this._channelClosedWaitHandle);
}
this.CloseCleanup();
}
protected virtual void OnChannelData(string data)
{
}
protected virtual void OnChannelExtendedData(string data, uint dataTypeCode)
{
}
protected virtual void OnChannelSuccess()
{
}
protected virtual void OnChannelEof()
{
}
protected virtual void OnChannelClose()
{
}
protected void SendMessage(Message message)
{
this.SessionInfo.SendMessage(message);
}
private void SessionInfo_MessageReceived(object sender, MessageReceivedEventArgs e)
{
ChannelMessage message = e.Message as ChannelMessage;
// Handle only messages belong to this channel or channel open confirmation
if (message.ChannelNumber == this.ClientChannelNumber || e.Message is ChannelOpenConfirmationMessage)
{
this.HandleMessage((dynamic)e.Message);
}
}
#region Message handlers
private void HandleMessage<T>(T message) where T : Message
{
throw new NotSupportedException(string.Format("Message type '{0}' is not supported.", message.MessageType));
}
private void HandleMessage(ChannelOpenConfirmationMessage message)
{
// Make sure we open channel only for requested channel number
if (this.ClientChannelNumber != message.ChannelNumber)
return;
this.ServerChannelNumber = message.ServerChannelNumber;
this.IsOpen = true;
this.WindowSize = message.InitialWindowSize;
this.PacketSize = message.MaximumPacketSize;
this._channelOpenWaitHandle.Set();
}
private void HandleMessage(ChannelOpenFailureMessage message)
{
this.IsOpen = false;
this._channelOpenWaitHandle.Set();
}
private void HandleMessage(ChannelWindowAdjustMessage message)
{
this.WindowSize += message.BytesToAdd;
}
private void HandleMessage(ChannelDataMessage message)
{
this.AdjustDataWindow(message.Data);
this.OnChannelData(message.Data);
}
private void HandleMessage(ChannelExtendedDataMessage message)
{
this.AdjustDataWindow(message.Data);
this.OnChannelExtendedData(message.Data, message.DataTypeCode);
}
private void HandleMessage(ChannelRequestMessage message)
{
Message replyMessage = new ChannelFailureMessage()
{
ChannelNumber = message.ChannelNumber,
};
if (message.RequestName == RequestNames.ExitStatus)
{
var exitStatus = message.ExitStatus;
replyMessage = new ChannelSuccessMessage()
{
ChannelNumber = message.ChannelNumber,
};
}
if (message.WantReply)
{
this.SendMessage(replyMessage);
}
}
private void HandleMessage(ChannelSuccessMessage message)
{
this.OnChannelSuccess();
}
private void HandleMessage(ChannelEofMessage message)
{
this.OnChannelEof();
}
private void HandleMessage(ChannelCloseMessage message)
{
// TODO: Handle this message
this.CloseCleanup();
this._channelClosedWaitHandle.Set();
}
private void AdjustDataWindow(string messageData)
{
this.WindowSize -= (uint)messageData.Length;
// Adjust window if window size is too low
if (this.WindowSize < this._initialWindowSize / 2)
{
this.SendMessage(new ChannelWindowAdjustMessage
{
ChannelNumber = this.ServerChannelNumber,
BytesToAdd = this._initialWindowSize - this.WindowSize,
});
this.WindowSize = this._initialWindowSize;
}
}
#endregion
private void CloseCleanup()
{
this.IsOpen = false;
this.SessionInfo.MessageReceived -= SessionInfo_MessageReceived;
}
}
}
@@ -0,0 +1,65 @@
using System.Text;
using System.Threading;
using Renci.SshClient.Messages.Connection;
namespace Renci.SshClient.Channels
{
internal class ChannelSession : Channel
{
private EventWaitHandle _channelEofWaitHandle = new AutoResetEvent(false);
private StringBuilder _response = new StringBuilder();
public override ChannelTypes ChannelType
{
get { return ChannelTypes.Session; }
}
public ChannelSession(SessionInfo sessionInfo)
: base(sessionInfo, 0x100000, 0x1000)
{
}
internal string Execute(string command)
{
this.Open();
// Send channel command request
this.SendMessage(new ChannelRequestMessage
{
ChannelNumber = this.ServerChannelNumber,
RequestName = RequestNames.Exec,
WantReply = false,
Command = command,
});
this.SessionInfo.WaitHandle(this._channelEofWaitHandle);
this.Close();
return this._response.ToString();
}
protected override void OnChannelEof()
{
base.OnChannelEof();
// TODO: All wait handles add timeout and then throw an exception or monitor connection closed event
this._channelEofWaitHandle.Set();
}
protected override void OnChannelData(string data)
{
base.OnChannelData(data);
this._response.Append(data);
}
private void Init()
{
this.ChannelData.Length = 0;
this.ChannelExtendedData.Length = 0;
}
}
}
@@ -0,0 +1,547 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Renci.SshClient.Common;
using Renci.SshClient.Messages.Connection;
using Renci.SshClient.Messages.Sftp;
namespace Renci.SshClient.Channels
{
internal class ChannelSftp : Channel
{
private EventWaitHandle _channelRequestSuccessWaitHandle = new AutoResetEvent(false);
private EventWaitHandle _testWaitHandle = new AutoResetEvent(false);
private EventWaitHandle _responseMessageReceivedWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
private uint _requestId;
private SftpMessage _responseMessage;
private string _remoteCurrentDir;
private string _localCurentDir;
private StringBuilder _packetData;
public override ChannelTypes ChannelType
{
get { return ChannelTypes.Session; }
}
public ChannelSftp(SessionInfo sessionInfo, uint windowSize, uint packetSize)
: base(sessionInfo, windowSize, packetSize)
{
}
public ChannelSftp(SessionInfo sessionInfo)
: base(sessionInfo, 0x100000, 0x4000)
{
}
public override void Open()
{
base.Open();
// Send channel command request
this.SendMessage(new ChannelRequestMessage
{
ChannelNumber = this.ServerChannelNumber,
RequestName = RequestNames.Subsystem,
WantReply = true,
SubsystemName = "sftp",
});
this.SessionInfo.WaitHandle(this._channelRequestSuccessWaitHandle);
this.SendMessage(new InitMessage
{
Version = 6,
});
var versionMessage = this.ReceiveMessage<VersionMessage>();
if (versionMessage == null)
{
throw new InvalidOperationException("Version message expected.");
}
if (versionMessage.Version != 3)
{
throw new NotSupportedException(string.Format("Server SFTP version {0} is not supported.", versionMessage.Version));
}
// Get default current directories
var files = this.GetRealPath(".");
this._remoteCurrentDir = files.First().Name;
this._localCurentDir = Directory.GetCurrentDirectory();
}
public void UploadFile(Stream source, string destination)
{
this.Open();
string handle = string.Empty;
try
{
handle = this.OpenRemoteFile(destination, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate);
var buffer = new byte[1024];
ulong offset = 0;
while (source.Read(buffer, 0, buffer.Length) > 0)
{
this.RemoteWrite(handle, offset, buffer.GetSshString());
offset += (ulong)buffer.Length;
}
}
finally
{
if (!string.IsNullOrEmpty(handle))
this.CloseRemoteHandle(handle);
}
this.Close();
}
internal void DownloadFile(string fileName, Stream destination)
{
this.Open();
string handle = string.Empty;
try
{
handle = this.OpenRemoteFile(fileName, Flags.Read);
ulong offset = 0;
uint bufferSize = 1024;
string data;
while ((data = this.RemoteRead(handle, offset, bufferSize)) != null)
{
var fileData = data.GetSshBytes().ToArray();
destination.Write(fileData, 0, (int)bufferSize);
destination.Flush();
offset += (ulong)fileData.Length;
}
}
finally
{
if (!string.IsNullOrEmpty(handle))
this.CloseRemoteHandle(handle);
}
this.Close();
}
public void CreateDirectory(string directoryName)
{
this.Open();
this.CreateRemoteDirectory(directoryName);
this.Close();
}
public void RemoveDirectory(string directoryName)
{
this.Open();
this.RemoveRemoteDirectory(directoryName);
this.Close();
}
public void RemoveFile(string fileName)
{
this.Open();
this.RemoveRemoteFile(fileName);
this.Close();
}
public void RenameFile(string oldFileName, string newFileName)
{
this.Open();
this.RenameRemoteFile(oldFileName, newFileName);
this.Close();
}
public IEnumerable<FtpFileInfo> ListDirectory(string path)
{
// Open channel
this.Open();
string handle = string.Empty;
IEnumerable<FtpFileInfo> files = null;
try
{
// Open directory
handle = this.OpenRemoteDirectory(path);
// Read directory data
files = this.ReadRemoteDirectory(handle);
}
finally
{
// Close directory
if (!string.IsNullOrEmpty(handle))
this.CloseRemoteHandle(handle);
}
// Read directory
this.Close();
return files;
}
protected override void OnChannelSuccess()
{
base.OnChannelSuccess();
this._channelRequestSuccessWaitHandle.Set();
}
protected override void OnChannelData(string data)
{
base.OnChannelData(data);
if (this._packetData == null)
{
var packetLength = BitConverter.ToUInt32(data.GetSshBytes().Take(4).Reverse().ToArray(), 0);
this._packetData = new StringBuilder((int)packetLength, (int)packetLength);
this._packetData.Append(data.GetSshBytes().Skip(4).GetSshString());
}
else
{
this._packetData.Append(data);
}
if (this._packetData.Length < this._packetData.MaxCapacity)
{
// Wait for more packet data
return;
}
dynamic sftpMessage = SftpMessage.Load(this._packetData.ToString().GetSshBytes());
this._packetData = null;
// TODO: Handle SSH_FXP_STATUS here
// TODO: Validate message request id is correct
this._responseMessage = sftpMessage;
this._responseMessageReceivedWaitHandle.Set();
}
private T ReceiveMessage<T>() where T : SftpMessage
{
var message = this.ReceiveMessage() as T;
if (message == null)
{
throw new InvalidOperationException(string.Format("Message of type '{0}' expected in this context.", typeof(T).Name));
}
return message;
}
private SftpMessage ReceiveMessage()
{
this.SessionInfo.WaitHandle(this._responseMessageReceivedWaitHandle);
var statusMessage = this._responseMessage as StatusMessage;
if (statusMessage != null)
{
// Handle error status messages
switch (statusMessage.StatusCode)
{
case StatusCodes.Ok:
break;
case StatusCodes.Eof:
break;
case StatusCodes.NoSuchFile:
throw new FileNotFoundException("File or directory not found on the remote server.");
case StatusCodes.PermissionDenied:
throw new NotImplementedException();
case StatusCodes.Failure:
throw new InvalidOperationException("Operation failed.");
case StatusCodes.BadMessage:
throw new NotImplementedException();
case StatusCodes.NoConnection:
throw new NotImplementedException();
case StatusCodes.ConnectionLost:
throw new NotImplementedException();
case StatusCodes.OperationUnsupported:
throw new NotSupportedException("Operation is not supported.");
default:
break;
}
}
return this._responseMessage;
}
private void SendMessage(SftpMessage sftpMessage)
{
sftpMessage.RequestId = this._requestId++;
var message = new SftpDataMessage
{
ChannelNumber = this.ServerChannelNumber,
Data = sftpMessage,
};
this.SendMessage(message);
this._responseMessageReceivedWaitHandle.Reset();
}
private string OpenRemoteFile(string fileName, Flags flags)
{
this.SendMessage(new OpenMessage
{
Filename = fileName,
Flags = flags,
});
var handleMessage = this.ReceiveMessage<HandleMessage>();
return handleMessage.Handle;
}
private string RemoteRead(string handle, ulong offset, uint length)
{
this.SendMessage(new ReadMessage
{
Handle = handle,
Offset = offset,
Length = length,
});
var message = this.ReceiveMessage();
var statusMessage = message as StatusMessage;
var dataMessage = message as DataMessage;
if (statusMessage != null)
{
if (statusMessage.StatusCode == StatusCodes.Eof)
{
return null;
}
throw new InvalidOperationException("Invalid status code.");
}
else if (dataMessage != null)
{
return dataMessage.Data;
}
else
{
throw new InvalidOperationException(string.Format("Message type '{0}' is not valid in this context.", message.SftpMessageType));
}
}
private void RemoteWrite(string handle, ulong offset, string data)
{
this.SendMessage(new WriteMessage
{
Handle = handle,
Offset = offset,
Data = data,
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private void RemoveRemoteFile(string fileName)
{
this.SendMessage(new RemoveMessage
{
Filename = fileName,
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private void RenameRemoteFile(string oldFileName, string newFileName)
{
this.SendMessage(new RenameMessage
{
OldPath = oldFileName,
NewPath = newFileName,
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private void CreateRemoteDirectory(string directoryName)
{
this.SendMessage(new MkDirMessage
{
Path = directoryName,
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private void RemoveRemoteDirectory(string directoryName)
{
this.SendMessage(new RmDirMessage
{
Path = directoryName,
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private string OpenRemoteDirectory(string path)
{
this.SendMessage(new OpenDirMessage
{
Path = path,
});
var handleMessage = this.ReceiveMessage<HandleMessage>();
return handleMessage.Handle;
}
private IEnumerable<FtpFileInfo> ReadRemoteDirectory(string handle)
{
this.SendMessage(new ReadDirMessage
{
Handle = handle,
});
var message = this.ReceiveMessage<NameMessage>();
return message.Files;
}
private void CloseRemoteHandle(string handle)
{
this.SendMessage(new CloseMessage
{
Handle = handle,
});
var status = this.ReceiveMessage<StatusMessage>();
// TODO: If close is fails wait a litle a try to close it again, in case server fluashed data into the file during close
}
private Attributes GetRemoteFileAttributes(string filename)
{
this.SendMessage(new StatMessage
{
Path = filename,
});
var message = this.ReceiveMessage<AttrsMessage>();
return message.Attributes;
}
private Attributes GetRemoteLinkFileAttributes(string filename)
{
this.SendMessage(new LStatMessage
{
Path = filename,
});
var message = this.ReceiveMessage<AttrsMessage>();
return message.Attributes;
}
private Attributes GetRemoteOpenFileAttributes(string handle)
{
this.SendMessage(new FStatMessage
{
Handle = handle,
});
var message = this.ReceiveMessage<AttrsMessage>();
return message.Attributes;
}
private void SetRemoteFileAttributes(string filename, Attributes attributes)
{
this.SendMessage(new SetStatMessage
{
Path = filename,
Attributes = attributes
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private void SetRemoteOpenFileAttributes(string handle, Attributes attributes)
{
this.SendMessage(new FSetStatMessage
{
Handle = handle,
Attributes = attributes
});
var message = this.ReceiveMessage<StatusMessage>();
this.EnsureStatusCode(message, StatusCodes.Ok);
}
private IEnumerable<FtpFileInfo> GetRealPath(string path)
{
this.SendMessage(new RealPathMessage
{
Path = path,
});
var message = this.ReceiveMessage<NameMessage>();
return message.Files;
}
private void EnsureStatusCode(StatusMessage message, StatusCodes code)
{
if (message.StatusCode == code)
{
return;
}
else
{
throw new InvalidOperationException("Invalid status code.");
}
}
}
}
@@ -0,0 +1,28 @@
namespace Renci.SshClient.Channels
{
/// <summary>
///
/// </summary>
internal enum ChannelTypes
{
/// <summary>
/// session
/// </summary>
Session,
/// <summary>
/// x11
/// </summary>
X11,
/// <summary>
/// forwarded-tcpip
/// </summary>
ForwardedTcpip,
/// <summary>
/// direct-tcpip
/// </summary>
DirectTcpip,
}
}
@@ -0,0 +1,14 @@
using System;
namespace Renci.SshClient.Common
{
internal class DataReceivedEventArgs : EventArgs
{
public string Data { get; private set; }
public DataReceivedEventArgs(string data)
{
this.Data = data;
}
}
}
@@ -0,0 +1,123 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Renci.SshClient
{
public static class Extensions
{
/// <summary>
/// Checks whether a collection is the same as another collection
/// </summary>
/// <param name="value">The current instance object</param>
/// <param name="compareList">The collection to compare with</param>
/// <param name="comparer">The comparer object to use to compare each item in the collection. If null uses EqualityComparer(T).Default</param>
/// <returns>True if the two collections contain all the same items in the same order</returns>
public static bool IsEqualTo<TSource>(this IEnumerable<TSource> value, IEnumerable<TSource> compareList, IEqualityComparer<TSource> comparer)
{
if (value == compareList)
{
return true;
}
else if (value == null || compareList == null)
{
return false;
}
else
{
if (comparer == null)
{
comparer = EqualityComparer<TSource>.Default;
}
IEnumerator<TSource> enumerator1 = value.GetEnumerator();
IEnumerator<TSource> enumerator2 = compareList.GetEnumerator();
bool enum1HasValue = enumerator1.MoveNext();
bool enum2HasValue = enumerator2.MoveNext();
try
{
while (enum1HasValue && enum2HasValue)
{
if (!comparer.Equals(enumerator1.Current, enumerator2.Current))
{
return false;
}
enum1HasValue = enumerator1.MoveNext();
enum2HasValue = enumerator2.MoveNext();
}
return !(enum1HasValue || enum2HasValue);
}
finally
{
if (enumerator1 != null) enumerator1.Dispose();
if (enumerator2 != null) enumerator2.Dispose();
}
}
}
public static bool IsEqualTo<TSource>(this IEnumerable<TSource> value, IEnumerable<TSource> compareList)
{
return IsEqualTo(value, compareList, null);
}
public static bool IsEqualTo(this IEnumerable value, IEnumerable compareList)
{
return IsEqualTo<object>(value.OfType<object>(), compareList.OfType<object>());
}
public static void DebugPrint(this IEnumerable<byte> bytes)
{
foreach (var b in bytes)
{
Debug.Write(string.Format("0x{0:x2}, ", b));
}
Debug.WriteLine(string.Empty);
}
public static string GetSshString(this IEnumerable<byte> data)
{
List<char> bytes = new List<char>();
foreach (var b in data)
{
bytes.Add((char)b);
}
return new string(bytes.ToArray());
}
public static IEnumerable<byte> GetSshBytes(this string data)
{
List<byte> bytes = new List<byte>();
foreach (var c in data.ToCharArray())
{
bytes.Add((byte)c);
}
return bytes.ToArray();
}
public static IEnumerable<byte> TrimLeadinZero(this IEnumerable<byte> data)
{
bool leadingZero = true;
foreach (var item in data)
{
if (item == 0 & leadingZero)
{
continue;
}
else
{
leadingZero = false;
}
yield return item;
}
}
}
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
namespace Renci.SshClient.Common
{
public class FtpFileInfo
{
public string Name { get; set; }
public string FullName { get; set; }
public DateTime CreationTime { get; set; }
public DateTime LastAccessTime { get; set; }
public DateTime LastModifyTime { get; set; }
public ulong Size { get; set; }
public uint UserId { get; set; }
public uint GroupId { get; set; }
public uint Permissions { get; set; }
public IDictionary<string, string> Extentions { get; set; }
}
}
@@ -0,0 +1,15 @@
using System;
using Renci.SshClient.Messages;
namespace Renci.SshClient.Common
{
internal class MessageReceivedEventArgs : EventArgs
{
public Message Message { get; private set; }
public MessageReceivedEventArgs(Message message)
{
this.Message = message;
}
}
}
@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
namespace Renci.SshClient.Common
{
public abstract class SshData
{
/// <summary>
/// Data byte array that hold message unencrypted data
/// </summary>
private IList<byte> _data;
private int _readerIndex;
public bool IsEndOfData
{
get
{
return this._readerIndex >= this._data.Count();
}
}
public virtual IEnumerable<byte> GetBytes()
{
this._data = new List<byte>();
this.SaveData();
return this._data;
}
protected abstract void LoadData();
protected abstract void SaveData();
protected void LoadBytes(IEnumerable<byte> bytes)
{
this.ResetReader();
this._data = new List<byte>(bytes);
}
protected void ResetReader()
{
this._readerIndex = 1; // Set to 1 to skip first byte which specifies message type
}
protected IEnumerable<byte> ReadBytes(int length)
{
var result = this._data.Skip(this._readerIndex).Take(length);
this._readerIndex += length;
return result;
}
protected byte ReadByte()
{
return this.ReadBytes(1).FirstOrDefault();
}
protected bool ReadBoolean()
{
return this.ReadByte() == 0 ? false : true;
}
protected UInt16 ReadUInt16()
{
return BitConverter.ToUInt16(this.ReadBytes(2).Reverse().ToArray(), 0);
}
protected UInt32 ReadUInt32()
{
return BitConverter.ToUInt32(this.ReadBytes(4).Reverse().ToArray(), 0);
}
protected UInt64 ReadUInt64()
{
return BitConverter.ToUInt64(this.ReadBytes(8).Reverse().ToArray(), 0);
}
protected Int64 ReadInt64()
{
return BitConverter.ToInt64(this.ReadBytes(8).Reverse().ToArray(), 0);
}
protected string ReadString()
{
var length = this.ReadUInt32();
if (length > (UInt32)int.MaxValue)
{
throw new NotSupportedException(string.Format("String that longer that {0} are not supported.", int.MaxValue));
}
var result = this._data.Skip(this._readerIndex).Take((int)length).GetSshString();
this._readerIndex += (int)length;
return result;
}
protected BigInteger ReadBigInteger()
{
var length = this.ReadUInt32();
var data = this.ReadBytes((int)length);
return new BigInteger(data.Reverse().ToArray());
}
protected IEnumerable<string> ReadNamesList()
{
var namesList = this.ReadString();
return namesList.Split(',');
}
protected IDictionary<string, string> ReadExtensionPair()
{
Dictionary<string, string> result = new Dictionary<string, string>();
while (this._readerIndex < this._data.Count)
{
var extensionName = this.ReadString();
var extensionData = this.ReadString();
result.Add(extensionName, extensionData);
}
return result;
}
protected void Write(IEnumerable<byte> data)
{
foreach (var b in data)
this.Write(b);
}
protected void Write(byte data)
{
this._data.Add(data);
}
protected void Write(bool data)
{
if (data)
{
this.Write(1);
}
else
{
this.Write(0);
}
}
protected void Write(UInt16 data)
{
this.Write(BitConverter.GetBytes(data).Reverse());
}
protected void Write(UInt32 data)
{
this.Write(BitConverter.GetBytes(data).Reverse());
}
protected void Write(UInt64 data)
{
this.Write(BitConverter.GetBytes(data).Reverse());
}
protected void Write(Int64 data)
{
this.Write(BitConverter.GetBytes(data).Reverse());
}
protected void Write(string data, Encoding encoding)
{
this.Write((uint)data.Length);
this.Write(encoding.GetBytes(data));
}
protected void Write(string data)
{
this.Write((uint)data.Length);
this.Write(data.GetSshBytes());
}
protected void Write(BigInteger data)
{
var bytes = data.ToByteArray().Reverse().ToList();
this.Write((uint)bytes.Count);
this.Write(bytes);
}
protected void Write(IEnumerable<string> data)
{
this.Write(string.Join(",", data));
}
protected void Write(IDictionary<string, string> data)
{
foreach (var item in data)
{
this.Write(item.Key);
this.Write(item.Value);
}
}
}
}
@@ -0,0 +1,51 @@
namespace Renci.SshClient
{
public class Connection
{
private Session _session;
public ConnectionInfo ConnectionInfo { get; private set; }
private Shell _shell;
public Shell Shell
{
get
{
if (this._shell == null)
{
this._shell = new Shell(this._session);
}
return this._shell;
}
}
private Sftp _sftp;
public Sftp Sftp
{
get
{
if (this._sftp == null)
{
this._sftp = new Sftp(this._session);
}
return this._sftp;
}
}
public Connection(ConnectionInfo connectionInfo)
{
this._session = Session.CreateSession(connectionInfo);
}
public void Connect()
{
this._session.Connect();
}
public void Disconnect()
{
this._session.Disconnect();
}
}
}
@@ -0,0 +1,21 @@
namespace Renci.SshClient
{
public class ConnectionInfo
{
public string Host { get; set; }
public int Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public KeyFile KeyFile { get; set; }
public ConnectionInfo()
{
// Set default connection values
this.Port = 22;
}
}
}
+134
View File
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace Renci.SshClient
{
public class KeyFile
{
private Regex _beginKeyLine = new Regex(@"----[ ]*BEGIN (?<keyName>.+) PRIVATE KEY[ ]*----");
private Regex _headerLine = new Regex(@"(?<headerTag>[^:]{1,64}):[ ](?<headerValue>[^:]+(?<continue>\\)?)");
private Regex _headerLineContinue = new Regex(@"(?<headerValue>[^:]+(?<continue>\\)?)");
private Regex _endKeyLine = new Regex(@"----[ ]*END (?<keyName>.+) PRIVATE KEY[ ]*----");
private PrivateKey _key;
public string AlgorithmName
{
get
{
return this._key.AlgorithmName;
}
}
public IEnumerable<byte> PublicKey
{
get
{
return this._key.PublicKey;
}
}
public IEnumerable<byte> GetSignature(IEnumerable<byte> sessionId)
{
return this._key.GetSignature(sessionId);
}
public KeyFile()
{
}
public void Open(string fileName)
{
using (var keyFile = File.OpenText(fileName))
{
var headerTag = string.Empty;
var headerValue = string.Empty;
var headerValueContinue = false;
var data = new StringBuilder();
var keyName = string.Empty;
var fileLine = string.Empty;
while ((fileLine = keyFile.ReadLine()) != null)
{
var match = _beginKeyLine.Match(fileLine);
if (match.Success)
{
keyName = match.Result("${keyName}");
continue;
}
match = _endKeyLine.Match(fileLine);
if (match.Success)
{
var endKeyName = match.Result("${keyName}");
if (!endKeyName.Equals(keyName))
throw new InvalidDataException("Invalid data key file.");
break;
}
// Ignore everything if BEGIN was not found yet
if (string.IsNullOrEmpty(keyName))
{
continue;
}
match = _headerLine.Match(fileLine);
if (match.Success)
{
headerTag = match.Result("${headerTag}");
headerValue = match.Result("${headerValue}");
if (match.Result("${continue}") == @"\")
{
headerValueContinue = true;
}
else
{
headerValueContinue = false;
}
continue;
}
if (headerValueContinue)
{
headerValue += fileLine;
if (match.Result("${continue}") == @"\")
{
headerValueContinue = true;
}
else
{
headerValueContinue = false;
}
continue;
}
data.Append(fileLine);
}
if (string.IsNullOrEmpty(keyName))
{
throw new InvalidDataException("Invalid Public key file");
}
switch (keyName)
{
case "RSA":
this._key = new PrivateKeyRsa(System.Convert.FromBase64String(data.ToString()));
break;
case "DSA":
this._key = new PrivateKeyDsa(System.Convert.FromBase64String(data.ToString()));
break;
default:
throw new NotSupportedException(string.Format("Key '{0}' is not supported.", keyName));
}
}
}
}
}
@@ -0,0 +1,28 @@
using System.Text;
namespace Renci.SshClient.Messages.Authentication
{
internal class BannerMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationBanner; }
}
public string Message { get; set; }
public string Language { get; set; }
protected override void LoadData()
{
this.Message = this.ReadString();
this.Language = this.ReadString();
}
protected override void SaveData()
{
this.Write(this.Message, Encoding.UTF8);
this.Write(this.Language);
}
}
}
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
namespace Renci.SshClient.Messages.Authentication
{
internal class FailureMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationFailure; }
}
public IEnumerable<string> AllowedAuthentications { get; set; }
public string Message { get; set; }
public bool PartialSuccess { get; set; }
protected override void LoadData()
{
this.AllowedAuthentications = this.ReadNamesList();
this.PartialSuccess = this.ReadBoolean();
if (this.PartialSuccess)
{
this.Message = string.Join(",", this.AllowedAuthentications);
}
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,33 @@
namespace Renci.SshClient.Messages.Authentication
{
internal class HostRequestMessage : RequestMessage
{
}
//byte SSH_MSG_USERAUTH_REQUEST
//string user name
//string service name
//string "hostbased"
//string public key algorithm for host key
//string public host key and certificates for client host
//string client host name expressed as the FQDN in US-ASCII
//string user name on the client host in ISO-10646 UTF-8 encoding
// [RFC3629]
//string signature
//string session identifier
//byte SSH_MSG_USERAUTH_REQUEST
//string user name
//string service name
//string "hostbased"
//string public key algorithm for host key
//string public host key and certificates for client host
//string client host name expressed as the FQDN in US-ASCII
//string user name on the client host in ISO-10646 UTF-8 encoding
// [RFC3629]
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Authentication
{
internal class InformationRequestMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationInformationRequest; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Authentication
{
internal class InformationResponseMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationInformationResponse; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,10 @@
namespace Renci.SshClient.Messages.Authentication
{
public enum Methods
{
None,
PublicKey,
Password,
Hostbased
}
}
@@ -0,0 +1,27 @@
namespace Renci.SshClient.Messages.Authentication
{
internal class PasswordChangeRequiredMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationPasswordChangeRequired; }
}
public string Message { get; set; }
public string Language { get; set; }
protected override void LoadData()
{
this.Message = this.ReadString();
this.Language = this.ReadString();
}
protected override void SaveData()
{
this.Write(this.Message);
this.Write(this.Language);
}
}
}
@@ -0,0 +1,34 @@
using System.Text;
namespace Renci.SshClient.Messages.Authentication
{
internal class PasswordRequestMessage : RequestMessage
{
public override string MethodName
{
get
{
return "password";
}
}
public string Password { get; set; }
public string NewPassword { get; set; }
protected override void SaveData()
{
base.SaveData();
this.Write(!string.IsNullOrEmpty(this.NewPassword));
this.Write(this.Password, Encoding.UTF8);
if (!string.IsNullOrEmpty(this.NewPassword))
{
this.Write(this.NewPassword, Encoding.UTF8);
}
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Authentication
{
internal class PublicKeyMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationPublicKey; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,39 @@
using System.Collections.Generic;
namespace Renci.SshClient.Messages.Authentication
{
internal class PublicKeyRequestMessage : RequestMessage
{
public override string MethodName
{
get
{
return "publickey";
}
}
public string PublicKeyAlgorithmName { get; set; }
public IEnumerable<byte> PublicKeyData { get; set; }
public IEnumerable<byte> Signature { get; set; }
protected override void SaveData()
{
base.SaveData();
if (this.Signature == null)
{
this.Write(false);
}
else
{
this.Write(true);
}
this.Write(this.PublicKeyAlgorithmName);
this.Write(this.PublicKeyData.GetSshString());
if (this.Signature != null)
this.Write(this.Signature.GetSshString());
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Text;
namespace Renci.SshClient.Messages.Authentication
{
internal class RequestMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationRequest; }
}
public string Username { get; set; }
public ServiceNames ServiceName { get; set; }
public virtual string MethodName { get { return "none"; } }
protected override void LoadData()
{
throw new InvalidOperationException("Load data is not supported.");
}
protected override void SaveData()
{
this.Write(this.Username, Encoding.UTF8);
switch (this.ServiceName)
{
case ServiceNames.UserAuthentication:
this.Write("ssh-userauth", Encoding.UTF8);
break;
case ServiceNames.Connection:
this.Write("ssh-connection", Encoding.UTF8);
break;
default:
throw new NotSupportedException("Not supported service name");
}
this.Write(this.MethodName, Encoding.ASCII);
}
}
}
@@ -0,0 +1,19 @@
namespace Renci.SshClient.Messages.Authentication
{
internal class SuccessMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.UserAuthenticationSuccess; }
}
protected override void LoadData()
{
}
protected override void SaveData()
{
}
}
}
@@ -0,0 +1,11 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelCloseMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelClose; }
}
}
}
@@ -0,0 +1,24 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelDataMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelData; }
}
public string Data { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Data = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Data);
}
}
}
@@ -0,0 +1,10 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelEofMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelEof; }
}
}
}
@@ -0,0 +1,29 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelExtendedDataMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelExtendedData; }
}
public uint DataTypeCode { get; set; }
public string Data { get; set; }
protected override void LoadData()
{
base.LoadData();
this.DataTypeCode = this.ReadUInt32();
this.Data = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.DataTypeCode);
this.Write(this.Data);
}
}
}
@@ -0,0 +1,11 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelFailureMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelFailure; }
}
}
}
@@ -0,0 +1,18 @@
namespace Renci.SshClient.Messages.Connection
{
internal abstract class ChannelMessage : Message
{
public uint ChannelNumber { get; set; }
protected override void LoadData()
{
this.ChannelNumber = this.ReadUInt32();
}
protected override void SaveData()
{
this.Write(this.ChannelNumber);
}
}
}
@@ -0,0 +1,32 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelOpenConfirmationMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelOpenConfirmation; }
}
public uint ServerChannelNumber { get; set; }
public uint InitialWindowSize { get; set; }
public uint MaximumPacketSize { get; set; }
protected override void LoadData()
{
base.LoadData();
this.ServerChannelNumber = this.ReadUInt32();
this.InitialWindowSize = this.ReadUInt32();
this.MaximumPacketSize = this.ReadUInt32();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.ServerChannelNumber);
this.Write(this.InitialWindowSize);
this.Write(this.MaximumPacketSize);
}
}
}
@@ -0,0 +1,32 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelOpenFailureMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelOpenFailure; }
}
public uint ReasconCode { get; set; }
public string Description { get; set; }
public string Language { get; set; }
protected override void LoadData()
{
base.LoadData();
this.ReasconCode = this.ReadUInt32();
this.Description = this.ReadString();
this.Language = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.ReasconCode);
this.Write(this.Description);
this.Write(this.Language);
}
}
}
@@ -0,0 +1,22 @@
namespace Renci.SshClient.Messages.Connection
{
internal enum ChannelOpenFailureReasons : uint
{
/// <summary>
/// SSH_OPEN_ADMINISTRATIVELY_PROHIBITED
/// </summary>
AdministativelyProhibited = 1,
/// <summary>
/// SSH_OPEN_CONNECT_FAILED
/// </summary>
ConnectFailed = 2,
/// <summary>
/// SSH_OPEN_UNKNOWN_CHANNEL_TYPE
/// </summary>
UnknownChannelType = 3,
/// <summary>
/// SSH_OPEN_RESOURCE_SHORTAGE
/// </summary>
ResourceShortage = 4
}
}
@@ -0,0 +1,33 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelOpenMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelOpen; }
}
public string ChannelName { get; set; }
public uint InitialWindowSize { get; set; }
public uint MaximumPacketSize { get; set; }
protected override void LoadData()
{
this.ChannelName = this.ReadString();
this.ChannelNumber = this.ReadUInt32();
this.InitialWindowSize = this.ReadUInt32();
this.MaximumPacketSize = this.ReadUInt32();
}
protected override void SaveData()
{
this.Write(this.ChannelName);
this.Write(this.ChannelNumber);
this.Write(this.InitialWindowSize);
this.Write(this.MaximumPacketSize);
}
}
}
@@ -0,0 +1,106 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelRequestMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelRequest; }
}
public RequestNames RequestName { get; set; }
public bool WantReply { get; set; }
public string Command { get; set; }
public string SubsystemName { get; set; }
public uint ExitStatus { get; set; }
protected override void LoadData()
{
base.LoadData();
var requestName = this.ReadString();
switch (requestName)
{
case "pty-req":
break;
case "x11-req":
break;
case "env":
break;
case "shell":
break;
case "exec":
this.RequestName = RequestNames.Exec;
this.WantReply = this.ReadBoolean();
this.Command = this.ReadString();
break;
case "subsystem":
this.RequestName = RequestNames.Subsystem;
this.WantReply = this.ReadBoolean();
this.SubsystemName = this.ReadString();
break;
case "window-change":
break;
case "xon-xoff":
break;
case "signal":
break;
case "exit-status":
this.RequestName = RequestNames.ExitStatus;
this.WantReply = this.ReadBoolean();
this.ExitStatus = this.ReadUInt32();
break;
case "exit-signal":
break;
default:
break;
}
}
protected override void SaveData()
{
base.SaveData();
switch (this.RequestName)
{
case RequestNames.PseudoTerminal:
break;
case RequestNames.X11Forwarding:
break;
case RequestNames.EnvironmentVariable:
break;
case RequestNames.Shell:
break;
case RequestNames.Exec:
this.Write("exec");
this.Write(this.WantReply);
this.Write(this.Command);
break;
case RequestNames.Subsystem:
this.Write("subsystem");
this.Write(this.WantReply);
this.Write(this.SubsystemName);
break;
case RequestNames.WindowChange:
break;
case RequestNames.XonXoff:
break;
case RequestNames.Signal:
break;
case RequestNames.ExitStatus:
this.Write("exit-status");
this.Write(this.WantReply);
this.Write(this.ExitStatus);
break;
case RequestNames.ExitSignal:
break;
default:
break;
}
}
}
}
@@ -0,0 +1,11 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelSuccessMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelSuccess; }
}
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Connection
{
internal class ChannelWindowAdjustMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelWindowAdjust; }
}
public uint BytesToAdd { get; set; }
protected override void LoadData()
{
base.LoadData();
this.BytesToAdd = this.ReadUInt32();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.BytesToAdd);
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Connection
{
internal class GlobalRequestMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.GlobalRequest; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Connection
{
internal class RequestFailureMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.RequestFailure; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,49 @@
namespace Renci.SshClient.Messages.Connection
{
internal enum RequestNames
{
/// <summary>
/// pty-req
/// </summary>
PseudoTerminal,
///x11-req
X11Forwarding,
/// <summary>
/// env
/// </summary>
EnvironmentVariable,
/// <summary>
/// shell
/// </summary>
Shell,
/// <summary>
/// exec
/// </summary>
Exec,
/// <summary>
/// subsystem
/// </summary>
Subsystem,
/// <summary>
/// window-change
/// </summary>
WindowChange,
/// <summary>
/// xon-xoff
/// </summary>
XonXoff,
/// <summary>
/// signal
/// </summary>
Signal,
/// <summary>
/// exit-status
/// </summary>
ExitStatus,
/// <summary>
/// exit-signal
/// </summary>
ExitSignal
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Connection
{
internal class RequestSuccessMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.RequestSuccess; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Renci.SshClient.Common;
namespace Renci.SshClient.Messages
{
public delegate void SendMessageDelegate(Message message);
public abstract class Message : SshData
{
private static object _lock = new object();
private delegate T LoadFunc<out T>(IEnumerable<byte> data);
public abstract MessageTypes MessageType { get; }
private static IDictionary<MessageTypes, LoadFunc<Message>> _registeredMessageTypes = new Dictionary<MessageTypes, LoadFunc<Message>>();
/// <summary>
/// Registers the message type. This will allow message type to be recognized by and handled by the system.
/// </summary>
/// <remarks>Some message types are not allowed during cirtain times or same code can be used for different type of message</remarks>
/// <typeparam name="T"></typeparam>
/// <param name="messageType">Type of the message.</param>
public static void RegisterMessageType<T>(MessageTypes messageType) where T : Message, new()
{
lock (_lock)
{
if (Message._registeredMessageTypes.ContainsKey(messageType))
{
Message.UnRegisterMessageType(messageType);
}
Message._registeredMessageTypes.Add(messageType, new LoadFunc<Message>(Load<T>));
}
}
public static void UnRegisterMessageType(MessageTypes messageType)
{
Message._registeredMessageTypes.Remove(messageType);
}
public static Message Load(IEnumerable<byte> data)
{
var messageType = (MessageTypes)data.FirstOrDefault();
return Load(data, messageType);
}
private static Message Load(IEnumerable<byte> data, MessageTypes messageType)
{
lock (_lock)
{
if (Message._registeredMessageTypes.ContainsKey(messageType))
{
return Message._registeredMessageTypes[messageType](data);
}
else
{
throw new NotSupportedException(string.Format("Message type '{0}' is not registered.", messageType));
}
}
}
private static T Load<T>(IEnumerable<byte> data) where T : Message, new()
{
var messageType = (MessageTypes)data.FirstOrDefault();
T message = new T();
message.LoadBytes(data);
message.ResetReader();
message.LoadData();
return message;
}
public override IEnumerable<byte> GetBytes()
{
var data = new List<byte>(base.GetBytes());
data.Insert(0, (byte)this.MessageType);
return data;
}
}
}
@@ -0,0 +1,150 @@
namespace Renci.SshClient.Messages
{
/// <summary>
///
/// </summary>
public enum MessageTypes : byte
{
/// <summary>
/// {35A90EBF-F421-44A3-BE3A-47C72AFE47FE}
/// </summary>
None = 0,
/// <summary>
/// SSH_MSG_DISCONNECT
/// </summary>
Disconnect = 1,
/// <summary>
/// SSH_MSG_IGNORE
/// </summary>
Ignore = 2,
/// <summary>
/// SSH_MSG_UNIMPLEMENTED
/// </summary>
Unimplemented = 3,
/// <summary>
/// SSH_MSG_DEBUG
/// </summary>
Debug = 4,
/// <summary>
/// SSH_MSG_SERVICE_REQUEST
/// </summary>
ServiceRequest = 5,
/// <summary>
/// SSH_MSG_SERVICE_ACCEPT
/// </summary>
ServiceAcceptRequest = 6,
/// <summary>
/// SSH_MSG_KEXINIT
/// </summary>
KeyExchangeInit = 20,
/// <summary>
/// SSH_MSG_NEWKEYS
/// </summary>
NewKeys = 21,
/// <summary>
/// SSH_MSG_KEXDH_INIT
/// </summary>
DiffieHellmanKeyExchangeInit = 30,
/// <summary>
/// SSH_MSG_KEXDH_REPLY
/// </summary>
KeyExchangeDhReply = 31,
SSH_MSG_KEX_DH_GEX_GROUP = 31,
SSH_MSG_KEX_DH_GEX_INIT = 32,
SSH_MSG_KEX_DH_GEX_REPLY = 33,
SSH_MSG_KEX_DH_GEX_REQUEST = 34,
/// <summary>
/// SSH_MSG_USERAUTH_REQUEST
/// </summary>
UserAuthenticationRequest = 50,
/// <summary>
/// SSH_MSG_USERAUTH_FAILURE
/// </summary>
UserAuthenticationFailure = 51,
/// <summary>
/// SSH_MSG_USERAUTH_SUCCESS
/// </summary>
UserAuthenticationSuccess = 52,
/// <summary>
/// SSH_MSG_USERAUTH_BANNER
/// </summary>
UserAuthenticationBanner = 53,
/// <summary>
/// SSH_MSG_USERAUTH_INFO_REQUEST
/// </summary>
UserAuthenticationInformationRequest = 60,
/// <summary>
/// SSH_MSG_USERAUTH_INFO_RESPONSE
/// </summary>
UserAuthenticationInformationResponse = 61,
/// <summary>
/// SSH_MSG_USERAUTH_PK_OK
/// </summary>
UserAuthenticationPublicKey = 60,
/// <summary>
/// SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
/// </summary>
UserAuthenticationPasswordChangeRequired = 60,
/// <summary>
/// SSH_MSG_GLOBAL_REQUEST
/// </summary>
GlobalRequest = 80,
/// <summary>
/// SSH_MSG_REQUEST_SUCCESS
/// </summary>
RequestSuccess = 81,
/// <summary>
/// SSH_MSG_REQUEST_FAILURE
/// </summary>
RequestFailure = 82,
/// <summary>
/// SSH_MSG_CHANNEL_OPEN
/// </summary>
ChannelOpen = 90,
/// <summary>
/// SSH_MSG_CHANNEL_OPEN_CONFIRMATION
/// </summary>
ChannelOpenConfirmation = 91,
/// <summary>
/// SSH_MSG_CHANNEL_OPEN_FAILURE
/// </summary>
ChannelOpenFailure = 92,
/// <summary>
/// SSH_MSG_CHANNEL_WINDOW_ADJUST
/// </summary>
ChannelWindowAdjust = 93,
/// <summary>
/// SSH_MSG_CHANNEL_DATA
/// </summary>
ChannelData = 94,
/// <summary>
/// SSH_MSG_CHANNEL_EXTENDED_DATA
/// </summary>
ChannelExtendedData = 95,
/// <summary>
/// SSH_MSG_CHANNEL_EOF
/// </summary>
ChannelEof = 96,
/// <summary>
/// SSH_MSG_CHANNEL_CLOSE
/// </summary>
ChannelClose = 97,
/// <summary>
/// SSH_MSG_CHANNEL_REQUEST
/// </summary>
ChannelRequest = 98,
/// <summary>
/// SSH_MSG_CHANNEL_SUCCESS
/// </summary>
ChannelSuccess = 99,
/// <summary>
/// SSH_MSG_CHANNEL_FAILURE
/// </summary>
ChannelFailure = 100,
}
}
@@ -0,0 +1,15 @@
namespace Renci.SshClient.Messages
{
internal enum ServiceNames
{
/// <summary>
/// ssh-userauth
/// </summary>
UserAuthentication,
/// <summary>
/// ssh-connection
/// </summary>
Connection
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal enum AceMasks
{
ACE4_READ_DATA = 0x00000001,
ACE4_LIST_DIRECTORY = 0x00000001,
ACE4_WRITE_DATA = 0x00000002,
ACE4_ADD_FILE = 0x00000002,
ACE4_APPEND_DATA = 0x00000004,
ACE4_ADD_SUBDIRECTORY = 0x00000004,
ACE4_READ_NAMED_ATTRS = 0x00000008,
ACE4_WRITE_NAMED_ATTRS = 0x00000010,
ACE4_EXECUTE = 0x00000020,
ACE4_DELETE_CHILD = 0x00000040,
ACE4_READ_ATTRIBUTES = 0x00000080,
ACE4_WRITE_ATTRIBUTES = 0x00000100,
ACE4_DELETE = 0x00010000,
ACE4_READ_ACL = 0x00020000,
ACE4_WRITE_ACL = 0x00040000,
ACE4_WRITE_OWNER = 0x00080000,
ACE4_SYNCHRONIZE = 0x00100000
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
namespace Renci.SshClient.Messages.Sftp
{
internal class Attributes
{
public UInt32 Flag { get; set; }
public ulong Size { get; set; }
public uint UserId { get; set; }
public uint GroupId { get; set; }
public uint Permissions { get; set; }
public DateTime AccessTime { get; set; }
public DateTime ModifyTime { get; set; }
public IDictionary<string, string> Extentions { get; set; }
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class AttrsMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Attrs; }
}
public Attributes Attributes { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Attributes = this.ReadAttributes();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Attributes);
}
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class CloseMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Close; }
}
public string Handle { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
}
}
}
@@ -0,0 +1,35 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class DataMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Data; }
}
public string Data { get; set; }
public bool IsEof { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Data = this.ReadString();
if (!this.IsEndOfData)
{
this.IsEof = this.ReadBoolean();
}
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Data);
if (this.IsEof)
{
this.Write(this.IsEof);
}
}
}
}
@@ -0,0 +1,27 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class ExtendedMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Extended; }
}
public string ExtendedRequest { get; set; }
protected override void LoadData()
{
base.LoadData();
this.ExtendedRequest = this.ReadString();
// TODO: Read extended request data
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.ExtendedRequest);
// TODO: Save extended request data
}
}
}
@@ -0,0 +1,23 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class ExtendedReplyMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.ExtendedReply; }
}
protected override void LoadData()
{
base.LoadData();
// TODO: Load request specific reply
}
protected override void SaveData()
{
base.SaveData();
// TODO: Save request specific reply
}
}
}
@@ -0,0 +1,29 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class FSetStat : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.FSetStat; }
}
public string Handle { get; set; }
public Attributes Attributes { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
this.Attributes = this.ReadAttributes();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
this.Write(this.Attributes);
}
}
}
@@ -0,0 +1,29 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class FSetStatMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.FSetStat; }
}
public string Handle { get; set; }
public Attributes Attributes { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
this.Attributes = this.ReadAttributes();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
this.Write(this.Attributes);
}
}
}
@@ -0,0 +1,26 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class FStatMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.FStat; }
}
public string Handle { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
}
}
}
@@ -0,0 +1,30 @@
namespace Renci.SshClient.Messages.Sftp
{
internal enum Flags
{
/// <summary>
/// SSH_FXF_READ
/// </summary>
Read = 0x00000001,
/// <summary>
/// SSH_FXF_WRITE
/// </summary>
Write = 0x00000002,
/// <summary>
/// SSH_FXF_APPEND
/// </summary>
Append = 0x00000004,
/// <summary>
/// SSH_FXF_CREAT
/// </summary>
CreateNewOrOpen = 0x00000008,
/// <summary>
/// SSH_FXF_TRUNC
/// </summary>
Truncate = 0x00000010,
/// <summary>
/// SSH_FXF_EXCL
/// </summary>
CreateNew = 0x00000028
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class HandleMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Handle; }
}
public string Handle { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
}
}
}
@@ -0,0 +1,23 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class InitMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Init; }
}
public uint Version { get; set; }
protected override void LoadData()
{
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Version);
}
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class LStatMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.LStat; }
}
public string Path { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path);
}
}
}
@@ -0,0 +1,33 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class MkDirMessage : SftpMessage
{
public MkDirMessage()
{
this.Attributes = new Attributes();
}
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.MkDir; }
}
public string Path { get; set; }
public Attributes Attributes { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
this.Attributes = this.ReadAttributes();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path);
this.Write(this.Attributes);
}
}
}
@@ -0,0 +1,52 @@
using System.Collections.Generic;
using Renci.SshClient.Common;
namespace Renci.SshClient.Messages.Sftp
{
internal class NameMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Name; }
}
public uint Count { get; set; }
public IList<FtpFileInfo> Files { get; set; }
public NameMessage()
{
this.Files = new List<FtpFileInfo>();
}
protected override void LoadData()
{
base.LoadData();
this.Count = this.ReadUInt32();
for (int i = 0; i < this.Count; i++)
{
var fileName = this.ReadString();
var fullName = this.ReadString();
var attribute = this.ReadAttributes();
this.Files.Add(new FtpFileInfo
{
Name = fileName,
FullName = fullName,
Size = attribute.Size,
UserId = attribute.UserId,
GroupId = attribute.GroupId,
LastAccessTime = attribute.AccessTime,
LastModifyTime = attribute.ModifyTime,
Extentions = attribute.Extentions,
});
}
}
protected override void SaveData()
{
base.SaveData();
}
}
}
@@ -0,0 +1,26 @@
using System.Text;
namespace Renci.SshClient.Messages.Sftp
{
internal class OpenDirMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.OpenDir; }
}
public string Path { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path, Encoding.UTF8);
}
}
}
@@ -0,0 +1,32 @@
using System;
namespace Renci.SshClient.Messages.Sftp
{
internal class OpenMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Open; }
}
public string Filename { get; set; }
public Flags Flags { get; set; }
public Attributes Attributes { get; set; }
protected override void LoadData()
{
base.LoadData();
throw new NotSupportedException();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Filename);
this.Write((uint)this.Flags);
this.Write(this.Attributes);
}
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class ReadDirMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.ReadDir; }
}
public string Handle { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
}
}
}
@@ -0,0 +1,26 @@
using System.Text;
namespace Renci.SshClient.Messages.Sftp
{
internal class ReadLinkMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.ReadLink; }
}
public string Path { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path, Encoding.UTF8);
}
}
}
@@ -0,0 +1,34 @@
using System;
namespace Renci.SshClient.Messages.Sftp
{
internal class ReadMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Read; }
}
public string Handle { get; set; }
public UInt64 Offset { get; set; }
public UInt32 Length { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
this.Offset = this.ReadUInt64();
this.Length = this.ReadUInt32();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
this.Write(this.Offset);
this.Write(this.Length);
}
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class RealPathMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.RealPath; }
}
public string Path { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path);
}
}
}
@@ -0,0 +1,26 @@
using System.Text;
namespace Renci.SshClient.Messages.Sftp
{
internal class RemoveMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Remove; }
}
public string Filename { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Filename = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Filename, Encoding.UTF8);
}
}
}
@@ -0,0 +1,28 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class RenameMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Rename; }
}
public string OldPath { get; set; }
public string NewPath { get; set; }
protected override void LoadData()
{
base.LoadData();
this.OldPath = this.ReadString();
this.NewPath = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.OldPath);
this.Write(this.NewPath);
}
}
}
@@ -0,0 +1,26 @@
using System.Text;
namespace Renci.SshClient.Messages.Sftp
{
internal class RmDirMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.RmDir; }
}
public string Path { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path, Encoding.UTF8);
}
}
}
@@ -0,0 +1,29 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class SetStatMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.SetStat; }
}
public string Path { get; set; }
public Attributes Attributes { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
this.Attributes = this.ReadAttributes();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path);
this.Write(this.Attributes);
}
}
}
@@ -0,0 +1,23 @@
using System.Linq;
using Renci.SshClient.Messages.Connection;
namespace Renci.SshClient.Messages.Sftp
{
internal class SftpDataMessage : ChannelMessage
{
public override MessageTypes MessageType
{
get { return MessageTypes.ChannelData; }
}
public SftpMessage Data { get; set; }
protected override void SaveData()
{
base.SaveData();
var data = this.Data.GetBytes();
this.Write((uint)data.Count() + 4);
this.Write(data.GetSshString());
}
}
}
@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Renci.SshClient.Common;
namespace Renci.SshClient.Messages.Sftp
{
internal abstract class SftpMessage : SshData
{
private delegate T LoadFunc<out T>(IEnumerable<byte> data);
private static IDictionary<SftpMessageTypes, LoadFunc<SftpMessage>> _sftpMessageTypes = new Dictionary<SftpMessageTypes, LoadFunc<SftpMessage>>();
public static SftpMessage Load(IEnumerable<byte> data)
{
var messageType = (SftpMessageTypes)data.FirstOrDefault();
return Load(data, messageType);
}
static SftpMessage()
{
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Init, new LoadFunc<SftpMessage>(Load<InitMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Version, new LoadFunc<SftpMessage>(Load<VersionMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Open, new LoadFunc<SftpMessage>(Load<OpenMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Close, new LoadFunc<SftpMessage>(Load<CloseMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Read, new LoadFunc<SftpMessage>(Load<ReadMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Write, new LoadFunc<SftpMessage>(Load<WriteMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.LStat, new LoadFunc<SftpMessage>(Load<LStatMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.FStat, new LoadFunc<SftpMessage>(Load<FStatMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.SetStat, new LoadFunc<SftpMessage>(Load<SetStatMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.FSetStat, new LoadFunc<SftpMessage>(Load<FSetStatMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.OpenDir, new LoadFunc<SftpMessage>(Load<OpenDirMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.ReadDir, new LoadFunc<SftpMessage>(Load<ReadDirMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Remove, new LoadFunc<SftpMessage>(Load<RemoveMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.MkDir, new LoadFunc<SftpMessage>(Load<MkDirMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.RmDir, new LoadFunc<SftpMessage>(Load<RmDirMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.RealPath, new LoadFunc<SftpMessage>(Load<RealPathMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Stat, new LoadFunc<SftpMessage>(Load<StatMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Rename, new LoadFunc<SftpMessage>(Load<RenameMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.ReadLink, new LoadFunc<SftpMessage>(Load<ReadLinkMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.SymLink, new LoadFunc<SftpMessage>(Load<SymLinkMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Status, new LoadFunc<SftpMessage>(Load<StatusMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Handle, new LoadFunc<SftpMessage>(Load<HandleMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Data, new LoadFunc<SftpMessage>(Load<DataMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Name, new LoadFunc<SftpMessage>(Load<NameMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Attrs, new LoadFunc<SftpMessage>(Load<AttrsMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.Extended, new LoadFunc<SftpMessage>(Load<ExtendedMessage>));
SftpMessage._sftpMessageTypes.Add(SftpMessageTypes.ExtendedReply, new LoadFunc<SftpMessage>(Load<ExtendedReplyMessage>));
}
public abstract SftpMessageTypes SftpMessageType { get; }
public uint? RequestId { get; set; }
protected override void LoadData()
{
// SSH_FXP_INIT and SSH_FXP_VERSION doesnt have RequestID, all other messaages do
if (!(this.SftpMessageType == SftpMessageTypes.Init || this.SftpMessageType == SftpMessageTypes.Version))
{
this.RequestId = this.ReadUInt32();
}
}
protected override void SaveData()
{
this.Write((byte)this.SftpMessageType);
if (this.RequestId.HasValue)
this.Write(this.RequestId.Value);
}
protected Attributes ReadAttributes()
{
var attributes = new Attributes();
attributes.Flag = this.ReadUInt32();
var isSize = (attributes.Flag & 0x00000001) == 0x00000001; //SSH_FILEXFER_ATTR_SIZE 0x00000001
var isUidGid = (attributes.Flag & 0x00000002) == 0x00000002; //SSH_FILEXFER_ATTR_UIDGID 0x00000002
var isPermissions = (attributes.Flag & 0x00000004) == 0x00000004; //SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
var isAccessModifyTime = (attributes.Flag & 0x00000008) == 0x00000008; //SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
var isExtended = (attributes.Flag & 0x80000000) == 0x80000000; //SSH_FILEXFER_ATTR_EXTENDED 0x80000000
if (isSize)
{
attributes.Size = this.ReadUInt64();
}
if (isUidGid)
{
attributes.UserId = this.ReadUInt32();
attributes.GroupId = this.ReadUInt32();
}
if (isPermissions)
{
attributes.Permissions = this.ReadUInt32();
}
if (isAccessModifyTime)
{
var time = this.ReadUInt32();
attributes.AccessTime = DateTime.FromFileTime((time + 11644473600) * 10000000);
time = this.ReadUInt32();
attributes.ModifyTime = DateTime.FromFileTime((time + 11644473600) * 10000000);
}
if (isExtended)
{
var extendedCount = this.ReadUInt32();
attributes.Extentions = this.ReadExtensionPair();
}
return attributes;
}
protected void Write(Attributes attributes)
{
// TODO: Complete attribute serialization, at this point we pass no attributes
if (attributes == null)
{
this.Write((uint)0);
return;
}
else
{
// TODO: Need to be tested
throw new NotImplementedException();
var isSize = (attributes.Flag & 0x00000001) == 0x00000001; //SSH_FILEXFER_ATTR_SIZE 0x00000001
var isUidGid = (attributes.Flag & 0x00000002) == 0x00000002; //SSH_FILEXFER_ATTR_UIDGID 0x00000002
var isPermissions = (attributes.Flag & 0x00000004) == 0x00000004; //SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
var isAccessModifyTime = (attributes.Flag & 0x00000008) == 0x00000008; //SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
var isExtended = (attributes.Flag & 0x80000000) == 0x80000000; //SSH_FILEXFER_ATTR_EXTENDED 0x80000000
if (isSize)
{
this.Write(attributes.Size);
}
if (isUidGid)
{
this.Write(attributes.UserId);
this.Write(attributes.GroupId);
}
if (isPermissions)
{
this.Write(attributes.Permissions);
}
if (isAccessModifyTime)
{
uint time = (uint)(attributes.AccessTime.ToFileTime() - 11644473600) / 10000000;
this.Write(time);
time = (uint)(attributes.ModifyTime.ToFileTime() - 11644473600) / 10000000;
this.Write(time);
}
if (isExtended)
{
this.Write(attributes.Extentions);
}
}
}
private static SftpMessage Load(IEnumerable<byte> data, SftpMessageTypes messageType)
{
if (SftpMessage._sftpMessageTypes.ContainsKey(messageType))
{
return SftpMessage._sftpMessageTypes[messageType](data);
}
else
{
throw new NotSupportedException(string.Format("Message type '{0}' is not registered.", messageType));
}
}
private static T Load<T>(IEnumerable<byte> data) where T : SftpMessage, new()
{
var messageType = (SftpMessageTypes)data.FirstOrDefault();
T message = new T();
message.LoadBytes(data);
message.ResetReader();
message.LoadData();
return message;
}
}
}
@@ -0,0 +1,117 @@
namespace Renci.SshClient.Messages.Sftp
{
internal enum SftpMessageTypes : byte
{
/// <summary>
/// SSH_FXP_INIT
/// </summary>
Init = 1,
/// <summary>
/// SSH_FXP_VERSION
/// </summary>
Version = 2,
/// <summary>
/// SSH_FXP_OPEN
/// </summary>
Open = 3,
/// <summary>
/// SSH_FXP_CLOSE
/// </summary>
Close = 4,
/// <summary>
/// SSH_FXP_READ
/// </summary>
Read = 5,
/// <summary>
/// SSH_FXP_WRITE
/// </summary>
Write = 6,
/// <summary>
/// SSH_FXP_LSTAT
/// </summary>
LStat = 7,
/// <summary>
/// SSH_FXP_FSTAT
/// </summary>
FStat = 8,
/// <summary>
/// SSH_FXP_SETSTAT
/// </summary>
SetStat = 9,
/// <summary>
/// SSH_FXP_FSETSTAT
/// </summary>
FSetStat = 10,
/// <summary>
/// SSH_FXP_OPENDIR
/// </summary>
OpenDir = 11,
/// <summary>
/// SSH_FXP_READDIR
/// </summary>
ReadDir = 12,
/// <summary>
/// SSH_FXP_REMOVE
/// </summary>
Remove = 13,
/// <summary>
/// SSH_FXP_MKDIR
/// </summary>
MkDir = 14,
/// <summary>
/// SSH_FXP_RMDIR
/// </summary>
RmDir = 15,
/// <summary>
/// SSH_FXP_REALPATH
/// </summary>
RealPath = 16,
/// <summary>
/// SSH_FXP_STAT
/// </summary>
Stat = 17,
/// <summary>
/// SSH_FXP_RENAME
/// </summary>
Rename = 18,
/// <summary>
/// SSH_FXP_READLINK
/// </summary>
ReadLink = 19,
/// <summary>
/// SSH_FXP_SYMLINK
/// </summary>
SymLink = 20,
/// <summary>
/// SSH_FXP_STATUS
/// </summary>
Status = 101,
/// <summary>
/// SSH_FXP_HANDLE
/// </summary>
Handle = 102,
/// <summary>
/// SSH_FXP_DATA
/// </summary>
Data = 103,
/// <summary>
/// SSH_FXP_NAME
/// </summary>
Name = 104,
/// <summary>
/// SSH_FXP_ATTRS
/// </summary>
Attrs = 105,
/// <summary>
/// SSH_FXP_EXTENDED
/// </summary>
Extended = 200,
/// <summary>
/// SSH_FXP_EXTENDED_REPLY
/// </summary>
ExtendedReply = 201
}
}
@@ -0,0 +1,25 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class StatMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Stat; }
}
public string Path { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Path = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Path);
}
}
}
@@ -0,0 +1,43 @@
namespace Renci.SshClient.Messages.Sftp
{
internal enum StatusCodes : uint
{
/// <summary>
/// SSH_FX_OK
/// </summary>
Ok = 0,
/// <summary>
/// SSH_FX_EOF
/// </summary>
Eof = 1,
/// <summary>
/// SSH_FX_NO_SUCH_FILE
/// </summary>
NoSuchFile = 2,
/// <summary>
/// SSH_FX_PERMISSION_DENIED
/// </summary>
PermissionDenied = 3,
/// <summary>
/// SSH_FX_FAILURE
/// </summary>
Failure = 4,
/// <summary>
/// SSH_FX_BAD_MESSAGE
/// </summary>
BadMessage = 5,
/// <summary>
/// SSH_FX_NO_CONNECTION
/// </summary>
NoConnection = 6,
/// <summary>
/// SSH_FX_CONNECTION_LOST
/// </summary>
ConnectionLost = 7,
/// <summary>
/// SSH_FX_OP_UNSUPPORTED
/// </summary>
OperationUnsupported = 8,
}
}
@@ -0,0 +1,67 @@
namespace Renci.SshClient.Messages.Sftp
{
internal class StatusMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Status; }
}
public StatusCodes StatusCode { get; set; }
public string ErrorMessage { get; set; }
public string Language { get; set; }
protected override void LoadData()
{
base.LoadData();
this.StatusCode = (StatusCodes)this.ReadUInt32();
switch (this.StatusCode)
{
case StatusCodes.Ok:
break;
case StatusCodes.Eof:
break;
case StatusCodes.NoSuchFile:
break;
case StatusCodes.PermissionDenied:
break;
case StatusCodes.Failure:
break;
case StatusCodes.BadMessage:
break;
case StatusCodes.NoConnection:
break;
case StatusCodes.ConnectionLost:
break;
case StatusCodes.OperationUnsupported:
break;
default:
break;
}
if (!this.IsEndOfData)
{
this.ErrorMessage = this.ReadString();
this.Language = this.ReadString();
}
// TODO: Load error specific data
}
protected override void SaveData()
{
base.SaveData();
this.Write((uint)this.StatusCode);
if (this.StatusCode == StatusCodes.Ok)
{
// No more data need to be written
return;
}
this.Write(this.ErrorMessage);
this.Write(this.Language);
// TODO: Save error specific data
}
}
}
@@ -0,0 +1,34 @@
using System.Text;
namespace Renci.SshClient.Messages.Sftp
{
internal class SymLinkMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.SymLink; }
}
public string NewLinkPath { get; set; }
public string ExistingPath { get; set; }
public bool IsSymLink { get; set; }
protected override void LoadData()
{
base.LoadData();
this.NewLinkPath = this.ReadString();
this.ExistingPath = this.ReadString();
this.IsSymLink = this.ReadBoolean();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.NewLinkPath, Encoding.UTF8);
this.Write(this.ExistingPath, Encoding.UTF8);
this.Write(this.IsSymLink);
}
}
}
@@ -0,0 +1,36 @@
using System.Collections.Generic;
namespace Renci.SshClient.Messages.Sftp
{
internal class VersionMessage : SftpMessage
{
public VersionMessage()
{
this.Extentions = new Dictionary<string, string>();
}
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Version; }
}
public uint Version { get; set; }
public IDictionary<string, string> Extentions { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Version = this.ReadUInt32();
this.Extentions = this.ReadExtensionPair();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Version);
this.Write(this.Extentions);
}
}
}
@@ -0,0 +1,34 @@
using System;
namespace Renci.SshClient.Messages.Sftp
{
internal class WriteMessage : SftpMessage
{
public override SftpMessageTypes SftpMessageType
{
get { return SftpMessageTypes.Write; }
}
public string Handle { get; set; }
public UInt64 Offset { get; set; }
public string Data { get; set; }
protected override void LoadData()
{
base.LoadData();
this.Handle = this.ReadString();
this.Offset = this.ReadUInt64();
this.Data = this.ReadString();
}
protected override void SaveData()
{
base.SaveData();
this.Write(this.Handle);
this.Write(this.Offset);
this.Write(this.Data);
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Transport
{
internal class DebugMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.Debug; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,32 @@
using System.Text;
namespace Renci.SshClient.Messages.Transport
{
internal class DisconnectMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.Disconnect; }
}
public DisconnectReasonCodes ReasonCode { get; set; }
public string Description { get; set; }
public string Language { get; set; }
protected override void LoadData()
{
this.ReasonCode = (DisconnectReasonCodes)this.ReadUInt32();
this.Description = this.ReadString();
this.Language = this.ReadString();
}
protected override void SaveData()
{
this.Write((uint)this.ReasonCode);
this.Write(this.Description, Encoding.UTF8);
this.Write(this.Language ?? "en");
}
}
}
@@ -0,0 +1,66 @@
namespace Renci.SshClient.Messages.Transport
{
public enum DisconnectReasonCodes : uint
{
/// <summary>
/// SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT
/// </summary>
HostNotAllowedToConnect = 1,
/// <summary>
/// SSH_DISCONNECT_PROTOCOL_ERROR
/// </summary>
ProtocolError = 2,
/// <summary>
/// SSH_DISCONNECT_KEY_EXCHANGE_FAILED
/// </summary>
KeyExchangeFailed = 3,
/// <summary>
/// SSH_DISCONNECT_RESERVED
/// </summary>
Reserved = 4,
/// <summary>
/// SSH_DISCONNECT_MAC_ERROR
/// </summary>
MacError = 5,
/// <summary>
/// SSH_DISCONNECT_COMPRESSION_ERROR
/// </summary>
CompressionError = 6,
/// <summary>
/// SSH_DISCONNECT_SERVICE_NOT_AVAILABLE
/// </summary>
ServiceNotAvailable = 7,
/// <summary>
/// SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED
/// </summary>
ProtocolVersionNotSupported = 8,
/// <summary>
/// SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE
/// </summary>
HostKeyNotVerifiable = 9,
/// <summary>
/// SSH_DISCONNECT_CONNECTION_LOST
/// </summary>
ConnectionLost = 10,
/// <summary>
/// SSH_DISCONNECT_BY_APPLICATION
/// </summary>
ByApplication = 11,
/// <summary>
/// SSH_DISCONNECT_TOO_MANY_CONNECTIONS
/// </summary>
TooManyConnections = 12,
/// <summary>
/// SSH_DISCONNECT_AUTH_CANCELLED_BY_USER
/// </summary>
AuthenticationCancelledByUser = 13,
/// <summary>
/// SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE
/// </summary>
NoMoreAuthenticationMethodsAvailable = 14,
/// <summary>
/// SSH_DISCONNECT_ILLEGAL_USER_NAME
/// </summary>
IllegalUserName = 15,
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Transport
{
internal class IgnoreMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.Ignore; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,28 @@
using System.Numerics;
namespace Renci.SshClient.Messages.Transport
{
internal class KeyExchangeDhInitMessage : Message
{
public BigInteger E { get; set; }
public override MessageTypes MessageType
{
get
{
return MessageTypes.DiffieHellmanKeyExchangeInit;
}
}
protected override void LoadData()
{
this.ResetReader();
this.E = this.ReadBigInteger();
}
protected override void SaveData()
{
this.Write(this.E);
}
}
}
@@ -0,0 +1,46 @@
using System;
using System.Numerics;
namespace Renci.SshClient.Messages.Transport
{
internal class KeyExchangeDhReplyMessage : Message
{
/// <summary>
/// Gets server public host key and certificates
/// </summary>
/// <value>The host key.</value>
public string HostKey { get; private set; }
public BigInteger F { get; private set; }
/// <summary>
/// Gets the signature of H.
/// </summary>
/// <value>The signature.</value>
public string Signature { get; private set; }
public override MessageTypes MessageType
{
get
{
return MessageTypes.KeyExchangeDhReply;
}
}
protected override void LoadData()
{
this.ResetReader();
this.HostKey = this.ReadString();
this.F = this.ReadBigInteger();
this.Signature = this.ReadString();
// TODO: Determine which algorithms to use from signature
}
protected override void SaveData()
{
throw new NotSupportedException("SaveData is not supported for KeyExchangeDhReplyMessage class");
}
}
}
@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace Renci.SshClient.Messages.Transport
{
internal class KeyExchangeInitMessage : Message
{
private static RNGCryptoServiceProvider _randomizer = new System.Security.Cryptography.RNGCryptoServiceProvider();
public override MessageTypes MessageType
{
get { return MessageTypes.KeyExchangeInit; }
}
public KeyExchangeInitMessage()
{
var cookie = new byte[16];
_randomizer.GetBytes(cookie);
this.Cookie = cookie;
}
#region Message Properties
public IEnumerable<byte> Cookie { get; private set; }
public IEnumerable<string> KeyExchangeAlgorithms { get; set; }
public IEnumerable<string> ServerHostKeyAlgorithms { get; set; }
public IEnumerable<string> EncryptionAlgorithmsClientToServer { get; set; }
public IEnumerable<string> EncryptionAlgorithmsServerToClient { get; set; }
public IEnumerable<string> MacAlgorithmsClientToSserver { get; set; }
public IEnumerable<string> MacAlgorithmsServerToClient { get; set; }
public IEnumerable<string> CompressionAlgorithmsClientToServer { get; set; }
public IEnumerable<string> CompressionAlgorithmsServerToClient { get; set; }
public IEnumerable<string> LanguagesClientToServer { get; set; }
public IEnumerable<string> LanguagesServerToClient { get; set; }
public bool FirstKexPacketFollows { get; set; }
public UInt32 Reserved { get; set; }
#endregion
protected override void LoadData()
{
this.ResetReader();
this.Cookie = this.ReadBytes(16);
this.KeyExchangeAlgorithms = this.ReadNamesList();
this.ServerHostKeyAlgorithms = this.ReadNamesList();
this.EncryptionAlgorithmsClientToServer = this.ReadNamesList();
this.EncryptionAlgorithmsServerToClient = this.ReadNamesList();
this.MacAlgorithmsClientToSserver = this.ReadNamesList();
this.MacAlgorithmsServerToClient = this.ReadNamesList();
this.CompressionAlgorithmsClientToServer = this.ReadNamesList();
this.CompressionAlgorithmsServerToClient = this.ReadNamesList();
this.LanguagesClientToServer = this.ReadNamesList();
this.LanguagesServerToClient = this.ReadNamesList();
this.FirstKexPacketFollows = this.ReadBoolean();
this.Reserved = this.ReadUInt32();
}
protected override void SaveData()
{
this.Write(this.Cookie);
this.Write(this.KeyExchangeAlgorithms);
this.Write(this.ServerHostKeyAlgorithms);
this.Write(this.EncryptionAlgorithmsClientToServer);
this.Write(this.EncryptionAlgorithmsServerToClient);
this.Write(this.MacAlgorithmsClientToSserver);
this.Write(this.MacAlgorithmsServerToClient);
this.Write(this.CompressionAlgorithmsClientToServer);
this.Write(this.CompressionAlgorithmsServerToClient);
this.Write(this.LanguagesClientToServer);
this.Write(this.LanguagesServerToClient);
this.Write(this.FirstKexPacketFollows);
this.Write(this.Reserved);
}
}
}
@@ -0,0 +1,18 @@
namespace Renci.SshClient.Messages.Transport
{
internal class NewKeysMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.NewKeys; }
}
protected override void LoadData()
{
}
protected override void SaveData()
{
}
}
}
@@ -0,0 +1,38 @@
using System;
namespace Renci.SshClient.Messages.Transport
{
/// <summary>
/// SSH_MSG_SERVICE_ACCEPT
/// </summary>
internal class ServiceAcceptMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.ServiceAcceptRequest; }
}
public ServiceNames ServiceName { get; set; }
protected override void LoadData()
{
var serviceName = this.ReadString();
switch (serviceName)
{
case "ssh-userauth":
this.ServiceName = ServiceNames.UserAuthentication;
break;
case "ssh-connection":
this.ServiceName = ServiceNames.Connection;
break;
default:
break;
}
}
protected override void SaveData()
{
throw new InvalidOperationException("Save data is not supported.");
}
}
}
@@ -0,0 +1,38 @@
using System;
namespace Renci.SshClient.Messages.Transport
{
/// <summary>
/// Contains SSH_MSG_SERVICE_REQUEST message information
/// </summary>
internal class ServiceRequestMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.ServiceRequest; }
}
public ServiceNames ServiceName { get; set; }
protected override void LoadData()
{
throw new InvalidOperationException("Load data is not supported.");
}
protected override void SaveData()
{
switch (this.ServiceName)
{
case ServiceNames.UserAuthentication:
this.Write("ssh-userauth");
break;
case ServiceNames.Connection:
this.Write("ssh-connection");
break;
default:
throw new NotSupportedException("Not supported service name");
}
}
}
}
@@ -0,0 +1,22 @@
using System;
namespace Renci.SshClient.Messages.Transport
{
internal class UnimplementedMessage : Message
{
public override MessageTypes MessageType
{
get { return MessageTypes.Unimplemented; }
}
protected override void LoadData()
{
throw new NotImplementedException();
}
protected override void SaveData()
{
throw new NotImplementedException();
}
}
}

Some files were not shown because too many files have changed in this diff Show More