diff --git a/SharpSSH/AssemblyInfo.cs b/SharpSSH/AssemblyInfo.cs new file mode 100644 index 00000000..742c8ce0 --- /dev/null +++ b/SharpSSH/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("SharpSSH")] +[assembly: AssemblyDescription("SSH library for .NET")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("tamirgal.com")] +[assembly: AssemblyProduct("SharpSSH")] +[assembly: AssemblyCopyright("Tamir Gal (c) 2007 and jcraft.com")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.1.1.13")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/SharpSSH/ExecTest.cs b/SharpSSH/ExecTest.cs new file mode 100644 index 00000000..eca57b38 --- /dev/null +++ b/SharpSSH/ExecTest.cs @@ -0,0 +1,43 @@ +using System; +using Tamir.SharpSsh.jsch; +using System.Collections; +using System.IO; + +namespace Tamir.SharpSsh +{ + /// + /// Summary description for ExecTest. + /// + public class ExecTest + { + public static void Run() + { + JSch jsch=new JSch(); + Session session=jsch.getSession("root", "rhmanage", 22); + session.setPassword( "cisco" ); + + Hashtable config=new Hashtable(); + config.Add("StrictHostKeyChecking", "no"); + session.setConfig(config); + + session.connect(); + + Channel channel=session.openChannel("exec"); + ((ChannelExec)channel).setCommand("ifconfig"); + + StreamReader sr = new StreamReader( channel.getInputStream() ); + + channel.connect(); + + string line; + + while( (line=sr.ReadLine()) != null ) + { + Console.WriteLine( line ); + } + + channel.disconnect(); + session.disconnect(); + } + } +} diff --git a/SharpSSH/ITransferProtocol.cs b/SharpSSH/ITransferProtocol.cs new file mode 100644 index 00000000..6987c21a --- /dev/null +++ b/SharpSSH/ITransferProtocol.cs @@ -0,0 +1,61 @@ +using System; + +/* + * ITransferProtocol.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.SharpSsh +{ + /// + /// Summary description for ITransferProtocol. + /// + public interface ITransferProtocol + { + void Connect(); + void Close(); + void Cancel(); + void Get(string fromFilePath, string toFilePath); + void Put(string fromFilePath, string toFilePath); + void Mkdir(string directory); + /// + /// Triggered when protocol transfer is starting + /// + event FileTransferEvent OnTransferStart; + /// + /// Triggered when protocol transfer ends + /// + event FileTransferEvent OnTransferEnd; + /// + /// Triggered on every interval with the transfer progress iformation. + /// + event FileTransferEvent OnTransferProgress; + } + + public delegate void FileTransferEvent(string src, string dst, int transferredBytes, int totalBytes, string message); +} diff --git a/SharpSSH/Main.cs b/SharpSSH/Main.cs new file mode 100644 index 00000000..446d51e2 --- /dev/null +++ b/SharpSSH/Main.cs @@ -0,0 +1,372 @@ +using System; +using System.IO; +using Tamir.Streams; +using Tamir.SharpSsh.jsch; +using Tamir.SharpSsh.jsch.examples; + +namespace Tamir +{ + /// + /// Summary description for Main. + /// + public class MainClass + { + public static void Main() + { + Console.WriteLine("sharpSsh 1.0"); + + //testSsh(); + //test(); + //testSig(); + //testSig2(); + //testSigFromJava(); + //testDump(); + //testDumpBase64(); + //testHMacMD5(); + testExamples(); + //jarAndScp(); + + + } + public static void test() + { + JSch jsch = new JSch(); + DH dh1 = null; + DH dh2 = null; + try + { + Type t=Type.GetType(jsch.getConfig("dh")); + dh1=(DH)(Activator.CreateInstance(t)); + dh1.init(); + dh2=(DH)(Activator.CreateInstance(t)); + dh2.init(); + } + catch(Exception ee) + { + Console.WriteLine(ee); + } + + dh1.setP(DHG1.p); + dh1.setG(DHG1.g); + dh2.setP(DHG1.p); + dh2.setG(DHG1.g); + + // The client responds with: + // byte SSH_MSG_KEXDH_INIT(30) + // mpint e <- g^x mod p + // x is a random number (1 < x < (p-1)/2) + + byte[] e=dh1.getE(); + byte[] f=dh2.getE(); + Console.WriteLine("Private1 = {0}", hex(e)); + Console.WriteLine(); + Console.WriteLine("Private2 = {0}", hex(f)); + Console.WriteLine(); + dh1.setF(f); + dh2.setF(e); + byte[] k1 = dh1.getK(); + byte[] k2 = dh2.getK(); + Console.WriteLine("Public1 = {0}", hex(k1)); + Console.WriteLine(); + Console.WriteLine("Public2 = {0}", hex(k2)); + Console.WriteLine(); + } + + public static void testSig() + { + byte[] hash = Util.getBytes( "Tamir" ); + Tamir.SharpSsh.jsch.jce.SignatureRSA enc_rsa = new Tamir.SharpSsh.jsch.jce.SignatureRSA(); + Tamir.SharpSsh.jsch.jce.SignatureRSA dec_rsa = new Tamir.SharpSsh.jsch.jce.SignatureRSA(); + Tamir.SharpSsh.jsch.jce.KeyPairGenRSA gen = new Tamir.SharpSsh.jsch.jce.KeyPairGenRSA(); + gen.init(512); + + enc_rsa.init(); + enc_rsa.setPrvKey(gen.KeyInfo); + enc_rsa.update(hash); + byte[] sig = enc_rsa.sign(); + + dump(gen.getE(), gen.getN(), sig, hash); + + dec_rsa.init(); + dec_rsa.setPubKey(gen.getE(), gen.getN()); + dec_rsa.update(hash); + + + + Console.WriteLine( dec_rsa.verify(sig) ); + } + + public static void testSigFromJava() + { + FileStream fs = File.OpenRead("e.bin"); + byte[] e = new byte[fs.Length]; + fs.Read(e, 0, e.Length); + fs.Close(); + + fs = File.OpenRead("n.bin"); + byte[] n = new byte[fs.Length]; + fs.Read(n, 0, n.Length); + fs.Close(); + + fs = File.OpenRead("sig.bin"); + byte[] sig = new byte[fs.Length]; + fs.Read(sig, 0, sig.Length); + fs.Close(); + + Console.Write("E: "); + Console.WriteLine( hex(e) ); + Console.Write("N: "); + Console.WriteLine( hex(n) ); + Console.Write("SIG: "); + Console.WriteLine( hex(sig) ); + + byte[] hash = Util.getBytes( "Tamir" ); + Tamir.SharpSsh.jsch.jce.SignatureRSA dec_rsa = new Tamir.SharpSsh.jsch.jce.SignatureRSA(); + dec_rsa.init(); + dec_rsa.setPubKey(e, n); + dec_rsa.update(hash); + Console.WriteLine( dec_rsa.verify(sig) ); + + + } + + public static void dump(byte[] e, byte[] n, byte[] sig, byte[] hash) + { + String fname = "e.bin"; + if(File.Exists(fname)) File.Delete(fname); + FileStream fs = File.OpenWrite(fname); + fs.Write(e, 0, e.Length); + fs.Close(); + + + fname = "n.bin"; + if(File.Exists(fname)) File.Delete(fname); + fs = File.OpenWrite(fname); + fs.Write(n, 0, n.Length); + fs.Close(); + + + fname = "sig.bin"; + if(File.Exists(fname)) File.Delete(fname); + fs = File.OpenWrite(fname); + fs.Write(sig, 0, sig.Length); + fs.Close(); + + fname = "hash.bin"; + if(File.Exists(fname)) File.Delete(fname); + fs = File.OpenWrite(fname); + fs.Write(hash, 0, hash.Length); + fs.Close(); + + + Console.Write("E: "); + Console.WriteLine( hex(e) ); + Console.WriteLine(); + Console.Write("N: "); + Console.WriteLine( hex(n) ); + Console.WriteLine(); + Console.Write("SIG: "); + Console.WriteLine( hex(sig) ); + Console.WriteLine(); + Console.Write("HASH: "); + Console.WriteLine( hex(hash) ); + Console.WriteLine(); + } + + public static void testDump() + { + String fname = "e.bin"; + FileStream fs = File.OpenRead(fname); + byte[] e = new byte[fs.Length]; + fs.Read(e, 0, e.Length); + fs.Close(); + + fname = "n.bin"; + fs = File.OpenRead(fname); + byte[] n = new byte[fs.Length]; + fs.Read(n, 0, n.Length); + fs.Close(); + + fname = "sig.bin"; + fs = File.OpenRead(fname); + byte[] sig = new byte[fs.Length]; + fs.Read(sig, 0, sig.Length); + fs.Close(); + + fname = "hash.bin"; + fs = File.OpenRead(fname); + byte[] hash = new byte[fs.Length]; + fs.Read(hash, 0, hash.Length); + fs.Close(); + + print("E", e); + print("N", n); + print("SIG", sig); + print("HASH", hash); + + Tamir.SharpSsh.jsch.jce.SignatureRSA dec_rsa = new Tamir.SharpSsh.jsch.jce.SignatureRSA(); + dec_rsa.init(); + dec_rsa.setPubKey(e, n); + dec_rsa.update(hash); + + Console.WriteLine( dec_rsa.verify(sig) ); + Console.WriteLine(); + } + + public static void testDumpBase64() + { + String fname = "e.bin"; + StreamReader fs = File.OpenText(fname); + string base64 = fs.ReadToEnd(); + byte[] e = Convert.FromBase64String( base64 ); + fs.Close(); + + fname = "n.bin"; + fs = File.OpenText(fname); + base64 = fs.ReadToEnd(); + byte[] n = Convert.FromBase64String( base64 ); + fs.Close(); + + fname = "sig.bin"; + fs = File.OpenText(fname); + base64 = fs.ReadToEnd(); + byte[] sig = Convert.FromBase64String( base64 ); + fs.Close(); + + fname = "hash.bin"; + fs = File.OpenText(fname); + base64 = fs.ReadToEnd(); + byte[] hash = Convert.FromBase64String( base64 ); + fs.Close(); + + print("E", e); + print("N", n); + print("SIG", sig); + print("HASH", hash); + + Tamir.SharpSsh.jsch.jce.SignatureRSA dec_rsa = new Tamir.SharpSsh.jsch.jce.SignatureRSA(); + dec_rsa.init(); + dec_rsa.setPubKey(e, n); + dec_rsa.update(hash); + + Console.WriteLine( dec_rsa.verify(sig) ); + Console.WriteLine(); + } + + public static void testHMacMD5() + { + byte[] msg = Util.getBytes("Tamir"); + byte[] key = new byte[]{1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6}; + Tamir.SharpSsh.jsch.jce.HMACMD5 md5 = new Tamir.SharpSsh.jsch.jce.HMACMD5(); + md5.init( key ); + md5.update(msg, 0, msg.Length); + byte[] hash = md5.doFinal(); + Console.WriteLine(hex(hash)); + } + + public static void testExamples() + { + //String[] arg = new string[]{"rsa", "key", "sharpSSH"}; + //KeyGen.RunExample(arg); + +// String[] arg = new string[]{"key"}; +// ChangePassphrase.RunExample(arg); + + //UserAuthPubKey.RunExample(null); + + Tamir.SharpSsh.jsch.examples.KnownHosts.RunExample(null); + +// String[] arg = new string[]{"C:\\untitled.db", "root@rhclient8:/root/mng/tamir/file"}; +// Tamir.SharpSsh.jsch.examples.ScpTo.RunExample(arg); + +// String[] arg = new string[]{"root@rhclient8:/root/mng/tamir/file", "file.txt"}; +// Tamir.SharpSsh.jsch.examples.ScpFrom.RunExample(arg); + +// Tamir.SharpSsh.jsch.examples.Sftp.RunExample(null); + } + + public static void jarAndScp() + { + TextReader r = File.OpenText( "jarAndScp.txt" ); + string dir = r.ReadLine(); + string host = r.ReadLine(); + string path = r.ReadLine(); + string user = r.ReadLine(); + string pass = r.ReadLine(); + r.Close(); + string file = dir+".jar"; + string jarFile = "\""+dir+".jar\""; + //dir = "\""+dir+"\""; + System.Diagnostics.ProcessStartInfo p = new System.Diagnostics.ProcessStartInfo(@"D:\Program Files\Java\jdk1.5.0_03\bin\jar.exe"); + p.WorkingDirectory = Directory.GetParent(dir).FullName; + p.Arguments = "-cf "+jarFile+" "+ Path.GetFileName(dir); + p.UseShellExecute = false; +// p.RedirectStandardOutput = true; +// p.RedirectStandardError = true; + System.Diagnostics.Process.Start(p); + System.Diagnostics.Process pr = new System.Diagnostics.Process(); + pr.StartInfo = p; + pr.Start(); + pr.WaitForExit(); + + String[] arg = new string[]{file, user+"@"+host+":"+path+Path.GetFileName(file)}; + //Tamir.SharpSsh.Scp.To(file, host, path+Path.GetFileName(file), user, pass); + } + + public static void print(string name, byte[] data) + { + Console.WriteLine(); + Console.Write(name+": "); + Console.WriteLine( hex(data) ); + Console.WriteLine(); + } + + public static string hex(byte[] arr) + { + string hex = "0x"; + for(int i=0;i + /// Class for handling SCP file transfers over SSH connection. + /// + public class Scp : SshTransferProtocolBase + { + private bool m_recursive = false; + private bool m_verbos = false; + private bool m_cancelled = false; + + public Scp(string host, string user, string password) + : base(host, user, password) + { + } + + public Scp(string host, string user) + : base(host, user) + { + } + + protected override string ChannelType + { + get { return "exec"; } + } + + /// + ///This function is empty, so no channel is connected + ///on session connect + /// + protected override void ConnectChannel() + { + } + + /// + /// Gets or sets a value indicating the default recursive transfer behaviour + /// + public bool Recursive + { + get{return m_recursive;} + set{m_recursive=value;} + } + + /// + /// Gets or sets a value indicating whether trace information should be printed + /// + public bool Verbos + { + get{return m_verbos;} + set{m_verbos=value;} + } + + public override void Cancel() + { + m_cancelled = true; + } + + /// + /// Creates a directory on the remot server + /// + /// The new directory + public override void Mkdir(string dir) + { + SCP_CheckConnectivity(); + + Channel channel=null; + Stream server = null; + m_cancelled=false; + + SCP_ConnectTo(out channel, out server, dir, true); + SCP_EnterIntoDir(server, dir); + channel.disconnect(); + } + + public override void Put(string fromFilePath, string toFilePath) + { + this.To(fromFilePath, toFilePath); + } + + public override void Get(string fromFilePath, string toFilePath) + { + this.From(fromFilePath, toFilePath); + } + + + + /// + /// Copies a file from local machine to a remote SSH machine. + /// + /// The local file path. + /// The path of the remote file. + public void To(string localPath, string remotePath) + { + this.To(localPath, remotePath, Recursive); + } + + + /// + /// Copies a file from local machine to a remote SSH machine. + /// + /// The local file path. + /// The path of the remote file. + public void To(string localPath, string remotePath, bool _recursive) + { + SCP_CheckConnectivity(); + + Channel channel=null; + Stream server = null; + m_cancelled=false; + + try + { + //if we are sending a single file + if(File.Exists(localPath)) + { + SCP_ConnectTo(out channel, out server, remotePath, _recursive); + SCP_SendFile(server, localPath, remotePath); + channel.disconnect(); + } + //else, if we are sending a local directory + else if(Directory.Exists(localPath)) + { + if(!_recursive) + { + throw new SshTransferException(Path.GetFileName("'"+localPath)+"' is a directory, you should use recursive transfer."); + } + SCP_ConnectTo(out channel, out server, remotePath, true); + ToRecursive(server, localPath, remotePath); + channel.disconnect(); + } + else + { + throw new SshTransferException("File not found: "+localPath); + } + } + catch(Exception e) + { + if(Verbos) + Console.WriteLine("Error: "+e.Message); + //SendEndMessage(remoteFile, localFile, filesize,filesize, "Transfer ended with an error."); + try{channel.disconnect();} + catch{} + throw e; + } + } + + /// + /// Copies files and directories from local machine to a remote SSH machine using SCP. + /// + /// I/O Stream for the remote server + /// Source to copy + /// Destination path + private void ToRecursive(Stream server, string src, string dst) + { + if(Directory.Exists(src)) + { + SCP_EnterIntoDir(server, Path.GetFileName(dst)); + foreach(string file in Directory.GetFiles(src)) + { + SCP_SendFile(server, file, Path.GetFileName( file)); + } + if(m_cancelled) + { + return; + } + foreach(string dir in Directory.GetDirectories(src)) + { + ToRecursive(server, dir, Path.GetFileName(dir)); + } + SCP_EnterIntoParent(server); + } + else if(File.Exists(src)) + { + SCP_SendFile(server, src, Path.GetFileName(src)); + } + else + { + throw new SshTransferException("File not found: "+src); + } + } + + /// + /// Copies a file from a remote SSH machine to the local machine using SCP. + /// + /// The remmote file name + /// The local destination path + public void From(string remoteFile, string localPath) + { + this.From(remoteFile, localPath, Recursive); + } + + /// + /// Copies a file from a remote SSH machine to the local machine using SCP. + /// + /// The remmote file name + /// The local destination path + /// Value indicating whether a recursive transfer should take place + public void From(string remoteFile, string localPath, bool _recursive) + { + SCP_CheckConnectivity(); + + Channel channel=null; + Stream server = null; + m_cancelled=false; + int filesize=0; + String filename=null; + string cmd = null; + + try + { + String dir=null; + if(Directory.Exists(localPath)) + { + dir= Path.GetFullPath( localPath ); + } + + SCP_ConnectFrom(out channel, out server, remoteFile, _recursive); + + byte[] buf=new byte[1024]; + + // send '\0' + SCP_SendAck(server); + int c=SCP_CheckAck(server); + + //parse scp commands + while((c=='D')||(c=='C')||(c=='E')) + { + if(m_cancelled) + break; + + cmd = ""+(char)c; + if(c=='E') + { + c=SCP_CheckAck(server); + dir = Path.GetDirectoryName(dir); + if(Verbos) Console.WriteLine("E"); + //send '\0' + SCP_SendAck(server); + c=(char)SCP_CheckAck(server); + continue; + } + + // read '0644 ' or '0755 ' + server.Read(buf, 0, 5); + for(int i=0;i<5;i++) + cmd+=(char)buf[i]; + + //reading file size + filesize=0; + while(true) + { + server.Read(buf, 0, 1); + if(buf[0]==' ')break; + filesize=filesize*10+(buf[0]-'0'); + } + + //reading file name + for(int i=0;;i++) + { + server.Read(buf, i, 1); + if(buf[i]==(byte)0x0a) + { + filename=Util.getString(buf, 0, i); + break; + } + } + cmd += " "+filesize+" "+filename; + // send '\0' + SCP_SendAck(server); + + //Receive file + if(c=='C') + { + if(Verbos) Console.WriteLine("Sending file modes: "+cmd); + SCP_ReceiveFile(server, remoteFile, + dir==null?localPath:dir+"/"+filename, + filesize); + + if(m_cancelled) + break; + + // send '\0' + SCP_SendAck(server); + } + //Enter directory + else if(c=='D') + { + if(dir==null) + { + if(File.Exists(localPath)) throw new SshTransferException("'"+localPath+"' is not a directory"); + dir = localPath; + Directory.CreateDirectory(dir); + } + if(Verbos) Console.WriteLine("Entering directory: "+cmd); + dir += "/"+filename; + Directory.CreateDirectory(dir); + } + + c=SCP_CheckAck(server); + } + channel.disconnect(); + } + catch(Exception e) + { + if(Verbos) + Console.WriteLine("Error: "+e.Message); + try + { + channel.disconnect(); + } + catch{} + throw e; + } + } + + #region SCP private functions + + /// + /// Checks is a channel is already connected by this instance + /// + protected void SCP_CheckConnectivity() + { + if(!Connected) + throw new Exception("Channel is down."); + } + + /// + /// Connect a channel to the remote server using the 'SCP TO' command ('scp -t') + /// + /// Will contain the new connected channel + /// Will contaun the new connected server I/O stream + /// The remote path on the server + /// Idicate a recursive scp transfer + protected void SCP_ConnectTo(out Channel channel, out Stream server, string rfile, bool recursive) + { + string scpCommand = "scp -p -t "; + if(recursive) scpCommand += "-r "; + scpCommand += "\""+rfile+"\""; + + channel = (ChannelExec)m_session.openChannel(ChannelType); + ((ChannelExec)channel).setCommand(scpCommand); + + server = + new Tamir.Streams.CombinedStream + (channel.getInputStream(), channel.getOutputStream()); + channel.connect(); + + SCP_CheckAck(server); + } + + /// + /// Connect a channel to the remote server using the 'SCP From' command ('scp -f') + /// + /// Will contain the new connected channel + /// Will contaun the new connected server I/O stream + /// The remote path on the server + /// Idicate a recursive scp transfer + protected void SCP_ConnectFrom(out Channel channel, out Stream server, string rfile, bool recursive) + { + string scpCommand = "scp -f "; + if(recursive) scpCommand += "-r "; + scpCommand += "\""+rfile+"\""; + + channel = (ChannelExec)m_session.openChannel(ChannelType); + ((ChannelExec)channel).setCommand(scpCommand); + + server = + new Tamir.Streams.CombinedStream + (channel.getInputStream(), channel.getOutputStream()); + channel.connect(); + + //SCP_CheckAck(server); + } + + /// + /// Transfer a file to the remote server + /// + /// A connected server I/O stream + /// The source file to copy + /// The remote destination path + protected void SCP_SendFile(Stream server, string src, string dst) + { + int filesize = 0; + int copied = 0; + + filesize=(int)(new FileInfo(src)).Length; + + byte[] tmp=new byte[1]; + + // send "C0644 filesize filename", where filename should not include '/' + + string command="C0644 "+filesize+" "+Path.GetFileName(dst)+"\n"; + if(Verbos) Console.WriteLine("Sending file modes: "+command); + SendStartMessage(src, dst, filesize, "Starting transfer."); + byte[] buff = Util.getBytes(command); + server.Write(buff, 0, buff.Length); server.Flush(); + + if(SCP_CheckAck(server)!=0) + { + throw new SshTransferException("Error openning communication channel."); + } + + // send a content of lfile + SendProgressMessage(src, dst, copied, filesize, "Transferring..."); + FileStream fis=File.OpenRead(src); + byte[] buf=new byte[1024*10*2]; + + while(!m_cancelled) + { + int len=fis.Read(buf, 0, buf.Length); + if(len<=0) break; + server.Write(buf, 0, len); server.Flush(); + copied += len; + SendProgressMessage(src, dst, copied, filesize, "Transferring..."); + } + fis.Close(); + + if(m_cancelled) + return; + + // send '\0' + buf[0]=0; server.Write(buf, 0, 1); server.Flush(); + + SendProgressMessage(src, dst, copied, filesize, "Verifying transfer..."); + if(SCP_CheckAck(server)!=0) + { + SendEndMessage(src, dst,copied,filesize, "Transfer ended with an error."); + throw new SshTransferException("Unknow error during file transfer."); + } + SendEndMessage(src, dst, copied, filesize, "Transfer completed successfuly ("+copied+" bytes)."); + } + + /// + /// Transfer a file from the remote server + /// + /// A connected server I/O stream + /// The remote file to copy + /// The local destination path + protected void SCP_ReceiveFile(Stream server, string rfile, string lfile, int size) + { + int copied = 0; + SendStartMessage(rfile, lfile, size, "Connected, starting transfer."); + // read a content of lfile + FileStream fos=File.OpenWrite(lfile); + int foo; + int filesize=size; + byte[] buf = new byte[1024]; + while(!m_cancelled) + { + if(buf.Length + /// Instructs the remote server to enter into a directory + /// + /// A connected server I/O stream + /// The directory name/param> + protected void SCP_EnterIntoDir(Stream server, string dir) + { + try + { + byte[] tmp=new byte[1]; + + // send "C0644 filesize filename", where filename should not include '/' + + string command="D0755 0 "+Path.GetFileName(dir)+"\n"; + if(Verbos) Console.WriteLine("Enter directory: "+command); + + byte[] buff = Util.getBytes(command); + server.Write(buff, 0, buff.Length); server.Flush(); + + if(SCP_CheckAck(server)!=0) + { + throw new SshTransferException("Error openning communication channel."); + } + } + catch{} + } + + /// + /// Instructs the remote server to go up one level + /// + /// A connected server I/O stream + protected void SCP_EnterIntoParent(Stream server) + { + try + { + byte[] tmp=new byte[1]; + + // send "C0644 filesize filename", where filename should not include '/' + + string command="E\n"; + if(Verbos) Console.WriteLine(command); + + byte[] buff = Util.getBytes(command); + server.Write(buff, 0, buff.Length); server.Flush(); + + if(SCP_CheckAck(server)!=0) + { + throw new SshTransferException("Error openning communication channel."); + } + } + catch{} + } + + /// + /// Gets server acknowledgment + /// + /// A connected server I/O stream + private int SCP_CheckAck(Stream ins) + { + int b=ins.ReadByte(); + // b may be 0 for success, + // 1 for error, + // 2 for fatal error, + // -1 + if(b==0) return b; + if(b==-1) return b; + + if(b==1 || b==2) + { + StringBuilder sb=new StringBuilder(); + int c; + do + { + c=ins.ReadByte(); + sb.Append((char)c); + } + while(c!='\n'); + if(b==1) + { // error + //Console.WriteLine(sb.ToString()); + throw new SshTransferException(sb.ToString()); + } + if(b==2) + { // fatal error + //Console.WriteLine(sb.ToString()); + throw new SshTransferException(sb.ToString()); + } + } + return b; + } + + /// + /// Sends acknowledgment to remote server + /// + /// A connected server I/O stream + private void SCP_SendAck(Stream server) + { + server.WriteByte(0); + server.Flush(); + } + + #endregion SCP private functions + } +} diff --git a/SharpSSH/Scp.old.cs b/SharpSSH/Scp.old.cs new file mode 100644 index 00000000..06290ffa --- /dev/null +++ b/SharpSSH/Scp.old.cs @@ -0,0 +1,354 @@ +//using System; +//using Tamir.SharpSsh.jsch; +//using System.IO; +//using System.Windows.Forms; +//using System.Text; +//using System.Collections; +// +///* +// * Scp.cs +// * +// * THIS SOURCE CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// * PURPOSE. +// * +// * Copyright (C) 2005 Tamir Gal, tamirgal@myrealbox.com. +// */ +// +//namespace Tamir.SharpSsh +//{ +// /// +// /// Class for handling SCP file transfers over SSH connection. +// /// +// public class Scp +// { +// /// +// /// Triggered when this SCP object starts connecting to the remote server. +// /// +// public event FileTansferEvent OnConnecting; +// /// +// /// Triggered when this SCP object starts the file transfer process. +// /// +// public event FileTansferEvent OnStart; +// /// +// /// Triggered when this SCP object ends the file transfer process. +// /// +// public event FileTansferEvent OnEnd; +// /// +// /// Triggered on every interval with the transfer progress iformation. +// /// +// public event FileTansferEvent OnProgress; +// +// /// +// /// The default value of the progress update interval. +// /// +// private int m_interval = 250; +// +// /// +// /// Copies a file from local machine to a remote SSH machine. +// /// +// /// The local file path. +// /// The remote machine's hostname or IP address +// /// The path of the remote file. +// /// The username for the connection. +// /// The password for the connection. +// public void To(string localFile, string remoteHost,string remoteFile, string user, string pass) +// { +// Channel channel=null; +// int filesize=0; +// int copied=0; +// try +// { +// double progress=0; +// SendConnectingMessage("Connecting to "+remoteHost+"..."); +// +// JSch jsch=new JSch(); +// Session session=jsch.getSession(user, remoteHost, 22); +// session.setPassword( pass ); +// +// Hashtable config=new Hashtable(); +// config.Add("StrictHostKeyChecking", "no"); +// session.setConfig(config); +// +// session.connect(); +// +// // exec 'scp -t rfile' remotely +// String command="scp -p -t \""+remoteFile+"\""; +// channel=session.openChannel("exec"); +// ((ChannelExec)channel).setCommand(command); +// +// // get I/O streams for remote scp +// Stream outs=channel.getOutputStream(); +// Stream ins=channel.getInputStream(); +// +// channel.connect(); +// +// SendStartMessage("Connected, starting transfer."); +// +// byte[] tmp=new byte[1]; +// +// if(checkAck(ins)!=0) +// { +// throw new Exception("Error openning communication channel."); +// } +// +// // send "C0644 filesize filename", where filename should not include '/' +// +// filesize=(int)(new FileInfo(localFile)).Length; +// command="C0644 "+filesize+" "; +// if(localFile.LastIndexOf('/')>0) +// { +// command+=localFile.Substring(localFile.LastIndexOf('/')+1); +// } +// else +// { +// command+=localFile; +// } +// command+="\n"; +// byte[] buff = Util.getBytes(command); +// outs.Write(buff, 0, buff.Length); outs.Flush(); +// +// if(checkAck(ins)!=0) +// { +// throw new Exception("Error openning communication channel."); +// } +// +// // send a content of lfile +// SendProgressMessage(0, filesize, "Transferring..."); +// FileStream fis=File.OpenRead(localFile); +// byte[] buf=new byte[1024]; +// copied = 0; +// while(true) +// { +// int len=fis.Read(buf, 0, buf.Length); +// if(len<=0) break; +// outs.Write(buf, 0, len); outs.Flush(); +// copied += len; +// progress = (copied*100.0/filesize); +// SendProgressMessage(copied, filesize, "Transferring..."); +// } +// fis.Close(); +// +// // send '\0' +// buf[0]=0; outs.Write(buf, 0, 1); outs.Flush(); +// +// SendProgressMessage(copied, filesize, "Verifying transfer..."); +// if(checkAck(ins)!=0) +// { +// throw new Exception("Unknow error during file transfer."); +// } +// SendEndMessage(copied, filesize, "Transfer completed successfuly ("+copied+" bytes)."); +// try{channel.close();} +// catch{} +// } +// catch(Exception e) +// { +// SendEndMessage(copied,filesize, "Transfer ended with an error."); +// try{channel.close();} +// catch{} +// throw e; +// } +// } +// +// /// +// /// Copies a file from a remote SSH machine to the local machine. +// /// +// /// The remote machine's hosname or IP address. +// /// The remote file path. +// /// The username or the connection. +// /// The password for the connection. +// /// The local file path. +// public void From(string remoteHost,string remoteFile, string user, string pass, string localFile) +// { +// Channel channel=null; +// int filesize=0; +// int copied=0; +// try +// { +// String prefix=null; +// if(Directory.Exists(localFile)) +// { +// prefix=localFile+Path.DirectorySeparatorChar; +// } +// +// double progress=0; +// SendConnectingMessage("Connecting to "+remoteHost+"..."); +// +// JSch jsch=new JSch(); +// Session session=jsch.getSession(user, remoteHost, 22); +// session.setPassword( pass ); +// +// Hashtable config=new Hashtable(); +// config.Add("StrictHostKeyChecking", "no"); +// session.setConfig(config); +// +// session.connect(); +// +// // exec 'scp -f rfile' remotely +// String command="scp -f \""+remoteFile + "\""; +// channel=session.openChannel("exec"); +// ((ChannelExec)channel).setCommand(command); +// +// // get I/O streams for remote scp +// Stream outs=channel.getOutputStream(); +// Stream ins=channel.getInputStream(); +// +// channel.connect(); +// +// SendStartMessage("Connected, starting transfer."); +// +// byte[] buf=new byte[1024]; +// +// // send '\0' +// buf[0]=0; outs.Write(buf, 0, 1); outs.Flush(); +// int c=checkAck(ins); +// if(c!='C') +// { +// throw new Exception("Error openning communication channel."); +// } +// +// // read '0644 ' +// ins.Read(buf, 0, 5); +// +// filesize=0; +// while(true) +// { +// ins.Read(buf, 0, 1); +// if(buf[0]==' ')break; +// filesize=filesize*10+(buf[0]-'0'); +// } +// +// String file=null; +// for(int i=0;;i++) +// { +// ins.Read(buf, i, 1); +// if(buf[i]==(byte)0x0a) +// { +// file=Util.getString(buf, 0, i); +// break; +// } +// } +// +// // send '\0' +// buf[0]=0; outs.Write(buf, 0, 1); outs.Flush(); +// +// // read a content of lfile +// FileStream fos=File.OpenWrite(prefix==null ? +// localFile : +// prefix+file); +// int foo; +// int size=filesize; +// copied=0; +// while(true) +// { +// if(buf.LengthProgressUpdateInterval) +// { +// OnProgress(transferredBytes,totalBytes, msg); +// lastUpdate=DateTime.Now; +// } +// } +// } +// +// /// +// /// Gets or sets the progress update interval in milliseconds +// /// +// public int ProgressUpdateInterval +// { +// get{return m_interval;} +// set{m_interval=value;} +// } +// } +// +// public delegate void FileTansferEvent(int transferredBytes, int totalBytes, string message); +//} diff --git a/SharpSSH/SecureShell.cs b/SharpSSH/SecureShell.cs new file mode 100644 index 00000000..e9b260bf --- /dev/null +++ b/SharpSSH/SecureShell.cs @@ -0,0 +1,17 @@ +using System; + +namespace Tamir.SharpSsh +{ + /// + /// Summary description for SecureShell. + /// + public class SecureShell + { + public SecureShell() + { + // + // TODO: Add constructor logic here + // + } + } +} diff --git a/SharpSSH/Sftp.cs b/SharpSSH/Sftp.cs new file mode 100644 index 00000000..62fb31cc --- /dev/null +++ b/SharpSSH/Sftp.cs @@ -0,0 +1,219 @@ +using System; +using Tamir.SharpSsh.jsch; +using System.Collections; + +/* + * Sftp.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ + +namespace Tamir.SharpSsh +{ + public class Sftp : SshTransferProtocolBase + { + private MyProgressMonitor m_monitor; + private bool cancelled = false; + + public Sftp(string sftpHost, string user, string password) + : base(sftpHost, user, password) + { + Init(); + } + + public Sftp(string sftpHost, string user) + : base(sftpHost, user) + { + Init(); + } + + private void Init() + { + m_monitor = new MyProgressMonitor(this); + } + + protected override string ChannelType + { + get { return "sftp"; } + } + + private ChannelSftp SftpChannel + { + get { return (ChannelSftp)m_channel; } + } + + public override void Cancel() + { + cancelled = true; + } + + //Get + + public void Get(string fromFilePath) + { + Get(fromFilePath, "."); + } + + public void Get(string[] fromFilePaths) + { + for (int i = 0; i < fromFilePaths.Length; i++) + { + Get(fromFilePaths[i]); + } + } + + public void Get(string[] fromFilePaths, string toDirPath) + { + for (int i = 0; i < fromFilePaths.Length; i++) + { + Get(fromFilePaths[i], toDirPath); + } + } + + public override void Get(string fromFilePath, string toFilePath) + { + cancelled=false; + SftpChannel.get(fromFilePath, toFilePath, m_monitor, ChannelSftp.OVERWRITE); + } + + //Put + + public void Put(string fromFilePath) + { + Put(fromFilePath, "."); + } + + public void Put(string[] fromFilePaths) + { + for (int i = 0; i < fromFilePaths.Length; i++) + { + Put(fromFilePaths[i]); + } + } + + public void Put(string[] fromFilePaths, string toDirPath) + { + for (int i = 0; i < fromFilePaths.Length; i++) + { + Put(fromFilePaths[i], toDirPath); + } + } + + public override void Put(string fromFilePath, string toFilePath) + { + cancelled=false; + SftpChannel.put(fromFilePath, toFilePath, m_monitor, ChannelSftp.OVERWRITE); + } + + //MkDir + + public override void Mkdir(string directory) + { + SftpChannel.mkdir(directory); + } + + //Ls + + public ArrayList GetFileList(string path) + { + ArrayList list = new ArrayList(); + foreach(Tamir.SharpSsh.jsch.ChannelSftp.LsEntry entry in SftpChannel.ls(path)) + { + list.Add(entry.getFilename().ToString()); + } + return list; + } + + #region ProgressMonitor Implementation + + private class MyProgressMonitor : SftpProgressMonitor + { + private long transferred = 0; + private long total = 0; + private int elapsed = -1; + private Sftp m_sftp; + private string src; + private string dest; + + System.Timers.Timer timer; + + public MyProgressMonitor(Sftp sftp) + { + m_sftp = sftp; + } + + public override void init(int op, String src, String dest, long max) + { + this.src=src; + this.dest=dest; + this.elapsed = 0; + this.total = max; + timer = new System.Timers.Timer(1000); + timer.Start(); + timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); + + string note; + if (op.Equals(GET)) + { + note = "Downloading " + System.IO.Path.GetFileName( src ) + "..."; + } + else + { + note = "Uploading " + System.IO.Path.GetFileName( src ) + "..."; + } + m_sftp.SendStartMessage(src, dest, (int)total, note); + } + public override bool count(long c) + { + this.transferred += c; + string note = ("Transfering... [Elapsed time: " + elapsed + "]"); + m_sftp.SendProgressMessage(src, dest, (int)transferred, (int)total, note); + return !m_sftp.cancelled; + } + public override void end() + { + timer.Stop(); + timer.Dispose(); + string note = ("Done in " + elapsed + " seconds!"); + m_sftp.SendEndMessage(src, dest, (int)transferred, (int)total, note); + transferred = 0; + total = 0; + elapsed = -1; + src=null; + dest=null; + } + + private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + this.elapsed++; + } + } + + #endregion ProgressMonitor Implementation + } +} diff --git a/SharpSSH/SharpSSH.csproj b/SharpSSH/SharpSSH.csproj new file mode 100644 index 00000000..84636d8c --- /dev/null +++ b/SharpSSH/SharpSSH.csproj @@ -0,0 +1 @@ + Debug AnyCPU 8.0.50727 2.0 {BB50B7E2-4622-4D8B-B7FF-5E5D8F02D91F} Library Tamir.SharpSsh Tamir.SharpSSH true full false ..\bin\Debug\ prompt 4 false none false ..\bin\Release\ prompt 4 false InputForm.cs False lib\DiffieHellman.dll False lib\Org.Mentalis.Security.dll \ No newline at end of file diff --git a/SharpSSH/SharpSSH.csproj.user b/SharpSSH/SharpSSH.csproj.user new file mode 100644 index 00000000..6219a221 --- /dev/null +++ b/SharpSSH/SharpSSH.csproj.user @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/SharpSSH/SharpSSH.mdp b/SharpSSH/SharpSSH.mdp new file mode 100644 index 00000000..0cb8b6ed --- /dev/null +++ b/SharpSSH/SharpSSH.mdp @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SharpSSH/SshBase.cs b/SharpSSH/SshBase.cs new file mode 100644 index 00000000..02c2d9aa --- /dev/null +++ b/SharpSSH/SshBase.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections; +using Tamir.SharpSsh.jsch; + +/* + * SshBase.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.SharpSsh +{ + /// + /// A wrapper class for JSch's SSH channel + /// + public abstract class SshBase + { + protected string m_host; + protected string m_user; + protected string m_pass; + protected JSch m_jsch; + protected Session m_session; + protected Channel m_channel; + + /// + /// Default TCP port of SSH protocol + /// + private static int SSH_TCP_PORT = 22; + + /// + /// Constructs a new SSH instance + /// + /// The remote SSH host + /// The login username + /// The login password + public SshBase(string sftpHost, string user, string password) + { + this.m_host = sftpHost; + this.m_user = user; + this.Password = password; + m_jsch = new JSch(); + } + + /// + /// Constructs a new SSH instance + /// + /// The remote SSH host + /// The login username + public SshBase(string sftpHost, string user) + : this(sftpHost, user, null) + { + } + + /// + /// Adds identity file for publickey user authentication + /// + /// The path to the private key file + public virtual void AddIdentityFile(string privateKeyFile) + { + m_jsch.addIdentity(privateKeyFile); + } + + /// + /// Adds identity file for publickey user authentication + /// + /// The path to the private key file + /// A passphrase for decrypting the private key file + public virtual void AddIdentityFile(string privateKeyFile, string passphrase) + { + m_jsch.addIdentity(privateKeyFile, passphrase); + } + + protected abstract string ChannelType{get;} + + /// + /// Connect to remote SSH server + /// + public virtual void Connect() + { + this.Connect(SSH_TCP_PORT); + } + + /// + /// Connect to remote SSH server + /// + /// The destination TCP port for this connection + public virtual void Connect(int tcpPort) + { + this.ConnectSession(tcpPort); + this.ConnectChannel(); + } + + protected virtual void ConnectSession(int tcpPort) + { + m_session = m_jsch.getSession(m_user, m_host, tcpPort); + if (Password != null) + m_session.setUserInfo(new KeyboardInteractiveUserInfo(Password)); + Hashtable config = new Hashtable(); + config.Add("StrictHostKeyChecking", "no"); + m_session.setConfig(config); + m_session.connect(); + } + + protected virtual void ConnectChannel() + { + m_channel = m_session.openChannel(ChannelType); + this.OnChannelReceived(); + m_channel.connect(); + this.OnConnected(); + } + + protected virtual void OnConnected() + { + } + + protected virtual void OnChannelReceived() + { + } + + /// + /// Closes the SSH subsystem + /// + public virtual void Close() + { + if (m_channel != null) + { + m_channel.disconnect(); + m_channel = null; + } + if (m_session != null) + { + m_session.disconnect(); + m_session = null; + } + } + + /// + /// Return true if the SSH subsystem is connected + /// + public virtual bool Connected + { + get + { + if (m_session != null) + return m_session.isConnected(); + return false; + } + } + + /// + /// Gets the Cipher algorithm name used in this SSH connection. + /// + public string Cipher + { + get + { + CheckConnected(); + return m_session.getCipher(); + } + } + + /// + /// Gets the MAC algorithm name used in this SSH connection. + /// + public string Mac + { + get + { + CheckConnected(); + return m_session.getMac(); + } + } + + /// + /// Gets the server SSH version string. + /// + public string ServerVersion + { + get + { + CheckConnected(); + return m_session.getServerVersion(); + } + } + + /// + /// Gets the client SSH version string. + /// + public string ClientVersion + { + get + { + CheckConnected(); + return m_session.getClientVersion(); + } + } + + public string Host + { + get + { + CheckConnected(); + return m_session.getHost(); + } + } + + public HostKey HostKey + { + get + { + CheckConnected(); + return m_session.getHostKey(); + } + } + + public int Port + { + get + { + CheckConnected(); + return m_session.getPort(); + } + } + + /// + /// The password string of the SSH subsystem + /// + public string Password + { + get { return m_pass; } + set { m_pass = value; } + } + public string Username + { + get { return m_user; } + } + + public static Version Version + { + get + { + System.Reflection.Assembly asm + = System.Reflection.Assembly.GetAssembly(typeof(Tamir.SharpSsh.SshBase)); + return asm.GetName().Version; + } + } + + private void CheckConnected() + { + if(!Connected) + { + throw new Exception("SSH session is not connected."); + } + } + + /// + /// For password and KI auth modes + /// + protected class KeyboardInteractiveUserInfo : UserInfo, UIKeyboardInteractive + { + string _password; + + public KeyboardInteractiveUserInfo(string password) + { + _password = password; + } + + #region UIKeyboardInteractive Members + + public string[] promptKeyboardInteractive(string destination, string name, string instruction, string[] prompt, bool[] echo) + { + return new string[] { _password }; + } + + #endregion + + #region UserInfo Members + + public bool promptYesNo(string message) + { + return true; + } + + public bool promptPassword(string message) + { + return true; + } + + public string getPassword() + { + return _password; + } + + public bool promptPassphrase(string message) + { + return true; + } + + public string getPassphrase() + { + return null; + } + + public void showMessage(string message) + { + } + + #endregion + } + } +} diff --git a/SharpSSH/SshExe.cs b/SharpSSH/SshExe.cs new file mode 100644 index 00000000..7b96411a --- /dev/null +++ b/SharpSSH/SshExe.cs @@ -0,0 +1,121 @@ +using System; +using Tamir.SharpSsh.jsch; +using System.Text; + +/* + * SshExe.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.SharpSsh +{ + /// + /// Summary description for SshExe. + /// + public class SshExec : SshBase + { + public SshExec(string host, string user, string password) + : base(host, user, password) + { + } + + public SshExec(string host, string user) + : base(host, user) + { + } + + protected override string ChannelType + { + get { return "exec"; } + } + + /// + ///This function is empty, so no channel is connected + ///on session connect + /// + protected override void ConnectChannel() + { + } + + protected ChannelExec GetChannelExec(string command) + { + ChannelExec exeChannel = (ChannelExec)m_session.openChannel("exec"); + exeChannel.setCommand(command); + return exeChannel; + } + + public string RunCommand(string command) + { + m_channel = GetChannelExec(command); + System.IO.Stream s = m_channel.getInputStream(); + m_channel.connect(); + byte[] buff = new byte[1024]; + StringBuilder res = new StringBuilder(); + int c = 0; + while(true) + { + c = s.Read(buff, 0, buff.Length); + if(c==-1) break; + res.Append( Encoding.ASCII.GetString(buff, 0, c) ); + //Console.WriteLine(res); + } + m_channel.disconnect(); + return res.ToString(); + } + + public int RunCommand(string command, ref string StdOut, ref string StdErr) + { + StdOut = ""; + StdErr = ""; + m_channel = GetChannelExec(command); + System.IO.Stream stdout = m_channel.getInputStream(); + System.IO.Stream stderr = ((ChannelExec)m_channel).getErrStream(); + m_channel.connect(); + byte[] buff = new byte[1024]; + StringBuilder sbStdOut = new StringBuilder(); + StringBuilder sbStdErr = new StringBuilder(); + int o=0; int e=0; + while(true) + { + if(o!=-1) o = stdout.Read(buff, 0, buff.Length); + if(o!=-1) StdOut += sbStdOut.Append(Encoding.ASCII.GetString(buff, 0, o)); + if(e!=-1) e = stderr.Read(buff, 0, buff.Length); + if(e!=-1) StdErr += sbStdErr.Append(Encoding.ASCII.GetString(buff, 0, e)); + if((o==-1)&&(e==-1)) break; + } + m_channel.disconnect(); + + return m_channel.getExitStatus(); + } + + public ChannelExec ChannelExec + { + get{return (ChannelExec)this.m_channel;} + } + } +} diff --git a/SharpSSH/SshHelper.cs b/SharpSSH/SshHelper.cs new file mode 100644 index 00000000..f18a4bd5 --- /dev/null +++ b/SharpSSH/SshHelper.cs @@ -0,0 +1,220 @@ +using System.IO; +using System.Collections; +using Tamir.SharpSsh.jsch; +using Tamir.Streams; +using System.Text; + +namespace Tamir +{ + public class SshHelper + { + + private StreamReader reader; + private PipedOutputStream writer_po; + private Session session; + private ChannelShell channel; + private string host; + + public SshHelper(string host, string username, string password) + { + this.host = host; + JSch jsch=new JSch(); + Session session=jsch.getSession(username, host, 22); + session.setPassword( password ); + + Hashtable config=new Hashtable(); + config.Add("StrictHostKeyChecking", "no"); + session.setConfig(config); + + session.connect(); + + channel=(ChannelShell)session.openChannel("shell"); + + writer_po = new PipedOutputStream(); + PipedInputStream writer_pi = new PipedInputStream( writer_po ); + + PipedInputStream reader_pi = new PipedInputStream(); + PipedOutputStream reader_po = new PipedOutputStream( reader_pi ); + reader = new StreamReader (reader_pi,Encoding.UTF8); + + + channel.setInputStream( writer_pi ); + channel.setOutputStream( reader_po ); + + channel.connect(); + channel.setPtySize(132, 132, 1024, 768); + + } + + public void Write(string data) + { + data += "\n"; + writer_po.write( Util.getBytes(data )); + } + + public string WriteAndRead(string data) + { + Write( data ); + return ReadResponse(); + } + + public void SendCtrlC() + { + byte ASCII_CTRL_C = 3; + byte[] ctrlc = { ASCII_CTRL_C }; + writer_po.write( ctrlc ); + } + + public void SendCtrlZ() + { + byte ASCII_CTRL_Z = 26; + byte[] ctrlz = { ASCII_CTRL_Z }; + writer_po.write( ctrlz ); + } + + public string ReadResponse() + { + // return ReadLine(); + return ReadTest(); + } + + public string ReadBuffer(int size) + { + string res = ""; + int buff; + try + { + buff = reader.Read(); + while( ((char)buff != '#') && (size != 0) ) + { + res += (char)buff; + size--; + if (res.EndsWith("More--")) + writer_po.write(Util.getBytes( " ") ); + buff = reader.Read(); + } + if(buff != '\n') + res += (char)buff; + } + catch//(Exception exc) + { + } + res = RemoveJunk( res ); + return res; + } + + public void Close() + { + channel.disconnect(); + writer_po.close(); + reader.Close(); + } + +// private string ReadLine() +// { +// string res = ""; +// int buff; +// try +// { +// buff = reader.ReadByte(); +// while((char)buff != '#') +// { +// res += (char)buff; +// if (res.EndsWith("More--")) +// writer_po.write( Util.getBytes(" ") ); +// buff = reader.ReadByte(); +// } +// if(buff != '\n') +// res += (char)buff; +// } +// catch//Exception exc) +// { +// } +// res = RemoveJunk( res ); +// return res; +// } + + private string ReadTest() + { + StringBuilder res = new StringBuilder(); + char[] buff = new char[1024]; + int count = 0; + + try + { + count = reader.Read(buff, 0, buff.Length); + //ArrayList lstBuff = new ArrayList(java.util.Arrays.asList(buff)); + while(!Util.ArrayContains(buff, '#', count)) + { + // while(buff[count-2]!='#' ){ + res.Append( buff, 0, count ); + if ( (res.ToString().EndsWith("More--"))||(res.ToString().EndsWith("More--"))) + writer_po.write( Util.getBytes( " ") ); + count = reader.Read(buff, 0, buff.Length); + count++; + count--; + //lstBuff = new ArrayList(java.util.Arrays.asList(buff)); + } + if(buff[count-1] != '\n') + res.Append( buff, 0, count ); + else + res.Append( buff, 0, count-1 ); + } + catch//(Exception exc) + { + } + return RemoveJunk( res ).ToString(); + } + + private static string RemoveJunk(string str) + { + string[] junk = new string[]{"", "", "", "", "", " \b", "--More--", "\r", "\n "}; + + for( int i=0; i + /// Summary description for SshShell. + /// + public class SshShell : SshBase + { + private Stream m_sshIO = null; + private Regex m_expectPattern; + private bool m_removeTerminalChars = false; + private bool m_redirectToConsole = false; + private static string escapeCharsPattern = "\\[[0-9;?]*[^0-9;]"; + + public SshShell(string host, string user, string password) + : base(host, user, password) + { + Init(); + } + + public SshShell(string host, string user) + : base(host, user) + { + Init(); + } + + protected void Init() + { + ExpectPattern = ""; + m_removeTerminalChars = false; + } + + protected override void OnChannelReceived() + { + base.OnChannelReceived (); + if(m_redirectToConsole) + { + SetStream(Console.OpenStandardInput(), Console.OpenStandardOutput()); + } + else + { + m_sshIO = GetStream(); + } + } + + + protected override string ChannelType + { + get { return "shell"; } + } + + public Stream IO + { + get + { +// if(m_sshIO == null) +// { +// m_sshIO = GetStream(); +// } + return m_sshIO; + } + } + + public void WriteLine(string data) + { + Write( data+"\r" ); + } + + public void Write(string data) + { + Write( Encoding.Default.GetBytes( data ) ); + } + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + public virtual void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + /// The zero-based byte offset in buffer at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + public virtual void Write(byte[] buffer, int offset, int count) + { + IO.Write(buffer, offset, count); + IO.Flush(); + } + + /// + /// Creates a new I/O stream of communication with this SSH shell connection + /// + public Stream GetStream() + { + return new CombinedStream(m_channel.getInputStream(), m_channel.getOutputStream());; + } + + public void SetStream(Stream inputStream, Stream outputStream) + { + m_channel.setInputStream(inputStream); + m_channel.setOutputStream(outputStream); + } + + public void SetStream(Stream s) + { + SetStream(s, s); + } + + public void RedirectToConsole() + { + m_redirectToConsole = true; + } + + public virtual bool ShellOpened + { + get + { + if(m_channel != null) + { + return !m_channel.isClosed(); + } + return false; + } + } + + public virtual bool ShellConnected + { + get + { + if(m_channel != null) + { + return m_channel.isConnected(); + } + return false; + } + } + + /// + /// Gets or sets a value indicating wether this Steam sould remove the terminal emulation's escape sequence characters from the response String. + /// + public bool RemoveTerminalEmulationCharacters + { + get{return m_removeTerminalChars;} + set{m_removeTerminalChars=value;} + } + + /// + /// A regular expression pattern string to match when reading the resonse using the ReadResponse() method. The default prompt value is "\n" which makes the ReadRespons() method return one line of response. + /// + public string ExpectPattern + { + get{return m_expectPattern.ToString();} + set{m_expectPattern = new Regex(value, RegexOptions.Singleline);} + } + + /// + /// Reads a response string from the SSH channel. This method will block until the pattern in the 'Prompt' property is matched in the response. + /// + /// A response string from the SSH server. + public string Expect() + { + return Expect(m_expectPattern); + } + + /// + /// Reads a response string from the SSH channel. This method will block until the pattern in the 'Prompt' property is matched in the response. + /// + /// A response string from the SSH server. + public string Expect(string pattern) + { + return Expect( new Regex( pattern, RegexOptions.Singleline )); + } + + /// + /// Reads a response string from the SSH channel. This method will block until the pattern in the 'Prompt' property is matched in the response. + /// + /// A response string from the SSH server. + public string Expect(Regex pattern) + { + int readCount; + StringBuilder resp = new StringBuilder(); + byte[] buff = new byte[1024]; + Match match; + + do + { + readCount = IO.Read(buff, 0, buff.Length); + if(readCount == -1) break; + string tmp = System.Text.Encoding.Default.GetString(buff, 0, readCount); + resp.Append( tmp, 0, readCount); + string s = resp.ToString(); + match = pattern.Match( s ); + }while(!match.Success); + + string result = resp.ToString(); + if(RemoveTerminalEmulationCharacters) + result = HandleTerminalChars(result); + return result; + } + + /// + /// Removes escape sequence characters from the input string. + /// + public static string HandleTerminalChars(string str) + { + str = str.Replace("(B)0", ""); + str = Regex.Replace(str, escapeCharsPattern, ""); + str = str.Replace(((char)15).ToString(), ""); + str = Regex.Replace(str, ((char)27)+"=*", ""); + //str = Regex.Replace(str, "\\s*\r\n", "\r\n"); + return str; + } + } +} diff --git a/SharpSSH/SshStream.cs b/SharpSSH/SshStream.cs new file mode 100644 index 00000000..281582cd --- /dev/null +++ b/SharpSSH/SshStream.cs @@ -0,0 +1,325 @@ +using System; +using System.IO; +using System.Collections; +using Tamir.SharpSsh.jsch; +using Tamir.Streams; +using System.Text; +using System.Text.RegularExpressions; + +/* + * SshStream.cs + * + * THIS SOURCE CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + * PURPOSE. + * + * Copyright (C) 2005 Tamir Gal, tamirgal@myrealbox.com. + */ + +namespace Tamir.SharpSsh +{ + /// + /// A Stream based SSH class + /// + public class SshStream : Stream + { + private Stream m_in; + private Stream m_out; + private ChannelShell m_channel; + private string m_host; + private Regex m_prompt; + private string m_escapeCharPattern; + private bool m_removeTerminalChars = false; + private Session m_session; + + /// + /// Constructs a new SSH stream. + /// + /// The hostname or IP address of the remote SSH machine + /// The name of the user connecting to the remote machine + /// The password of the user connecting to the remote machine + public SshStream(string host, string username, string password) + { + this.m_host = host; + JSch jsch=new JSch(); + m_session=jsch.getSession(username, host, 22); + m_session.setPassword( password ); + + Hashtable config=new Hashtable(); + config.Add("StrictHostKeyChecking", "no"); + m_session.setConfig(config); + + m_session.connect(); + m_channel=(ChannelShell)m_session.openChannel("shell"); + + m_in = m_channel.getInputStream(); + m_out = m_channel.getOutputStream(); + + m_channel.connect(); + m_channel.setPtySize(80, 132, 1024, 768); + + Prompt = "\n"; + m_escapeCharPattern = "\\[[0-9;?]*[^0-9;]"; + } + + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count- 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + public override int Read(byte[] buffer, int offset, int count) + { + return m_in.Read(buffer, offset, count); + } + + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count- 1) replaced by the bytes read from the current source. + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + public virtual int Read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + /// + /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. + /// + /// The unsigned byte cast to an Int32, or -1 if at the end of the stream. + public override int ReadByte() + { + return m_in.ReadByte(); + } + + /// + /// Writes a byte to the current position in the stream and advances the position within the stream by one byte. + /// + /// The byte to write to the stream. + public override void WriteByte(byte value) + { + m_out.WriteByte(value); + } + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + /// The zero-based byte offset in buffer at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + public override void Write(byte[] buffer, int offset, int count) + { + m_out.Write(buffer, offset, count); + } + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + public virtual void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// Writes a String into the SSH channel. This method appends an 'end of line' character to the input string. + /// + /// The String to write to the SSH channel. + public void Write(String data) + { + data += "\r"; + Write( Encoding.Default.GetBytes( data ) ); + Flush(); + } + + /// + /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + /// + public override void Close() + { + try + { + base.Close (); + m_in.Close(); + m_out.Close(); + m_channel.close(); + m_channel.disconnect(); + m_session.disconnect(); + } + catch{} + } + + /// + /// Gets a value indicating whether the current stream supports reading. + /// + public override bool CanRead + { + get + { + return m_in.CanRead; + } + } + + /// + /// Gets a value indicating whether the current stream supports writing. + /// + public override bool CanWrite + { + get + { + return m_out.CanWrite; + } + } + + /// + /// Gets a value indicating whether the current stream supports seeking. This stream cannot seek, and will always return false. + /// + public override bool CanSeek + { + get + { + return false; + } + } + + /// + /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device. + /// + public override void Flush() + { + m_out.Flush(); + } + + /// + /// Gets the length in bytes of the stream. + /// + public override long Length + { + get + { + return 0; + } + } + + /// + /// Gets or sets the position within the current stream. This Stream cannot seek. This property has no effect on the Stream and will always return 0. + /// + public override long Position + { + get + { + return 0; + } + set + { + } + } + + /// + /// This method has no effect on the Stream. + /// + public override void SetLength(long value) + { + } + + /// + /// This method has no effect on the Stream. + /// + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + + /// + /// A regular expression pattern string to match when reading the resonse using the ReadResponse() method. The default prompt value is "\n" which makes the ReadRespons() method return one line of response. + /// + public string Prompt + { + get{return m_prompt.ToString();} + set{m_prompt = new Regex(value, RegexOptions.Singleline);} + } + + /// + /// Gets or sets a value indicating wether this Steam sould remove the terminal emulation's escape sequence characters from the response String. + /// + public bool RemoveTerminalEmulationCharacters + { + get{return m_removeTerminalChars;} + set{m_removeTerminalChars=value;} + } + + /// + /// Gets the Cipher algorithm name used in this SSH connection. + /// + public string Cipher + { + get{return m_session.getCipher();} + } + + /// + /// Gets the MAC algorithm name used in this SSH connection. + /// + public string Mac + { + get{return m_session.getMac();} + } + + /// + /// Gets the server SSH version string. + /// + public string ServerVersion + { + get{return m_session.getServerVersion();} + } + + /// + /// Gets the client SSH version string. + /// + public string ClientVersion + { + get{return m_session.getClientVersion();} + } + + /// + /// Reads a response string from the SSH channel. This method will block until the pattern in the 'Prompt' property is matched in the response. + /// + /// A response string from the SSH server. + public string ReadResponse() + { + int readCount; + StringBuilder resp = new StringBuilder(); + byte[] buff = new byte[1024]; + Match match; + + do + { + readCount = this.Read(buff); + resp.Append( System.Text.Encoding.Default.GetString( buff), 0, readCount); + string s = resp.ToString(); + match = m_prompt.Match( s ); + }while(!match.Success); + + return HandleTerminalChars( resp.ToString() ); + } + + /// + /// Removes escape sequence characters from the input string. + /// + /// + /// + private string HandleTerminalChars(string str) + { + if(RemoveTerminalEmulationCharacters) + { + str = str.Replace("(B)0", ""); + str = Regex.Replace(str, m_escapeCharPattern, ""); + str = str.Replace(((char)15).ToString(), ""); + str = Regex.Replace(str, ((char)27).ToString()+"=*", ""); + //str = Regex.Replace(str, "\\s*\r\n", "\r\n"); + } + return str; + } + } +} diff --git a/SharpSSH/SshTransferException.cs b/SharpSSH/SshTransferException.cs new file mode 100644 index 00000000..4ee64993 --- /dev/null +++ b/SharpSSH/SshTransferException.cs @@ -0,0 +1,44 @@ +using System; + +/* + * SshTransferException.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.SharpSsh +{ + /// + /// Summary description for SshTransferException. + /// + public class SshTransferException : Exception + { + public SshTransferException(string msg):base(msg) + { + } + } +} diff --git a/SharpSSH/SshTransferProtocolBase.cs b/SharpSSH/SshTransferProtocolBase.cs new file mode 100644 index 00000000..df1a09b3 --- /dev/null +++ b/SharpSSH/SshTransferProtocolBase.cs @@ -0,0 +1,114 @@ +using System; + +/* + * SshTransferProtocolBase.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.SharpSsh +{ + /// + /// Summary description for SshTransferProtocolBase. + /// + public abstract class SshTransferProtocolBase : SshBase, ITransferProtocol + { + public SshTransferProtocolBase(string host, string user, string password) + : base(host, user, password) + { + } + + public SshTransferProtocolBase(string host, string user) + : base(host, user) + { + } + #region ITransferProtocol Members + + public abstract void Get(string fromFilePath, string toFilePath); + public abstract void Put(string fromFilePath, string toFilePath); + public abstract void Mkdir(string directory); + public abstract void Cancel(); + + /// + /// Triggered when transfer is starting + /// + public event FileTransferEvent OnTransferStart; + /// + /// Triggered when transfer ends + /// + public event FileTransferEvent OnTransferEnd; + /// + /// Triggered on every interval with the transfer progress iformation. + /// + public event FileTransferEvent OnTransferProgress; + + /// + /// Sends a notification that a file transfer has started + /// + /// The source file to transferred + /// Transfer destination + /// Total bytes to transfer + /// A transfer message + protected void SendStartMessage(string src, string dst, int totalBytes, string msg) + { + if (OnTransferStart != null) + OnTransferStart(src, dst, 0, totalBytes, msg); + } + + /// + /// Sends a notification that a file transfer has ended + /// + /// The source file to transferred + /// Transfer destination + /// Transferred Bytes + /// Total bytes to transfer + /// A transfer message + protected void SendEndMessage(string src, string dst, int transferredBytes, int totalBytes, string msg) + { + if (OnTransferEnd != null) + OnTransferEnd(src, dst, transferredBytes, totalBytes, msg); + } + + /// + /// Sends a transfer progress notification + /// + /// The source file to transferred + /// Transfer destination + /// Transferred Bytes + /// Total bytes to transfer + /// A transfer message + protected void SendProgressMessage(string src, string dst, int transferredBytes, int totalBytes, string msg) + { + if (OnTransferProgress != null) + { + OnTransferProgress(src, dst, transferredBytes, totalBytes, msg); + } + } + + #endregion + } +} diff --git a/SharpSSH/Streams/CombinedStream.cs b/SharpSSH/Streams/CombinedStream.cs new file mode 100644 index 00000000..16c2039d --- /dev/null +++ b/SharpSSH/Streams/CombinedStream.cs @@ -0,0 +1,206 @@ +using System; +using System.IO; + +/* + * CombinedStream.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.Streams +{ + /// + /// Summary description for CombinedStream. + /// + public class CombinedStream : Stream + { + private Stream m_in; + private Stream m_out; + + public CombinedStream(Stream inputStream, Stream outputStream) + { + this.m_in=inputStream; + this.m_out=outputStream; + } + + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count- 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + public override int Read(byte[] buffer, int offset, int count) + { + return m_in.Read(buffer, offset, count); + } + + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count- 1) replaced by the bytes read from the current source. + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + public virtual int Read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + /// + /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. + /// + /// The unsigned byte cast to an Int32, or -1 if at the end of the stream. + public override int ReadByte() + { + return m_in.ReadByte(); + } + + /// + /// Writes a byte to the current position in the stream and advances the position within the stream by one byte. + /// + /// The byte to write to the stream. + public override void WriteByte(byte value) + { + m_out.WriteByte(value); + } + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + /// The zero-based byte offset in buffer at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + public override void Write(byte[] buffer, int offset, int count) + { + m_out.Write(buffer, offset, count); + } + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + public virtual void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + + /// + /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. + /// + public override void Close() + { + try + { + base.Close (); + m_in.Close(); + m_out.Close(); + } + catch{} + } + + /// + /// Gets a value indicating whether the current stream supports reading. + /// + public override bool CanRead + { + get + { + return m_in.CanRead; + } + } + + /// + /// Gets a value indicating whether the current stream supports writing. + /// + public override bool CanWrite + { + get + { + return m_out.CanWrite; + } + } + + /// + /// Gets a value indicating whether the current stream supports seeking. This stream cannot seek, and will always return false. + /// + public override bool CanSeek + { + get + { + return false; + } + } + + /// + /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device. + /// + public override void Flush() + { + m_out.Flush(); + } + + /// + /// Gets the length in bytes of the stream. + /// + public override long Length + { + get + { + return 0; + } + } + + /// + /// Gets or sets the position within the current stream. This Stream cannot seek. This property has no effect on the Stream and will always return 0. + /// + public override long Position + { + get + { + return 0; + } + set + { + } + } + + /// + /// This method has no effect on the Stream. + /// + public override void SetLength(long value) + { + } + + /// + /// This method has no effect on the Stream. + /// + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + } +} diff --git a/SharpSSH/Streams/InputStream.cs b/SharpSSH/Streams/InputStream.cs new file mode 100644 index 00000000..07b7d221 --- /dev/null +++ b/SharpSSH/Streams/InputStream.cs @@ -0,0 +1,69 @@ +//using System; +//using System.IO; +// +//namespace Tamir.Streams +//{ +// /// +// /// Summary description for InputStream. +// /// +// public abstract class InputStream : Stream +// { +// public override void WriteByte(byte value) +// { +// } +// +// public override void Write(byte[] buffer, int offset, int count) +// { +// } +// +// public override bool CanRead +// { +// get +// { +// return true; +// } +// } +// public override bool CanWrite +// { +// get +// { +// return false; +// } +// } +// public override bool CanSeek +// { +// get +// { +// return false; +// } +// } +// public override void Flush() +// { +// +// } +// public override long Length +// { +// get +// { +// return 0; +// } +// } +// public override long Position +// { +// get +// { +// return 0; +// } +// set +// { +// } +// } +// public override void SetLength(long value) +// { +// } +// public override long Seek(long offset, SeekOrigin origin) +// { +// return 0; +// } +// } +//} diff --git a/SharpSSH/Streams/OutputStream.cs b/SharpSSH/Streams/OutputStream.cs new file mode 100644 index 00000000..7cec3d8a --- /dev/null +++ b/SharpSSH/Streams/OutputStream.cs @@ -0,0 +1,70 @@ +//using System; +//using System.IO; +// +//namespace Tamir.Streams +//{ +// /// +// /// Summary description for OutputStream. +// /// +// public abstract class OutputStream : Stream +// { +// public override int Read(byte[] buffer, int offset, int count) +// { +// return 0; +// } +// +// public override int ReadByte() +// { +// return 0; +// } +// +// public override bool CanRead +// { +// get +// { +// return false; +// } +// } +// public override bool CanWrite +// { +// get +// { +// return true; +// } +// } +// public override bool CanSeek +// { +// get +// { +// return false; +// } +// } +// public override void Flush() +// { +// } +// public override long Length +// { +// get +// { +// return 0; +// } +// } +// public override long Position +// { +// get +// { +// return 0; +// } +// set +// { +// } +// } +// public override void SetLength(long value) +// { +// } +// public override long Seek(long offset, SeekOrigin origin) +// { +// return 0; +// } +// } +//} diff --git a/SharpSSH/Streams/PipedInputStream.cs b/SharpSSH/Streams/PipedInputStream.cs new file mode 100644 index 00000000..57677388 --- /dev/null +++ b/SharpSSH/Streams/PipedInputStream.cs @@ -0,0 +1,517 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Tamir.Streams +{ +/* + * @(#)PipedInputStream.java 1.35 03/12/19 + * + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +/** + * A piped input stream should be connected + * to a piped output stream; the piped input + * stream then provides whatever data bytes + * are written to the piped output stream. + * Typically, data is read from a PipedInputStream + * object by one thread and data is written + * to the corresponding PipedOutputStream + * by some other thread. Attempting to use + * both objects from a single thread is not + * recommended, as it may deadlock the thread. + * The piped input stream contains a buffer, + * decoupling read operations from write operations, + * within limits. + * + * @author James Gosling + * @version 1.35, 12/19/03 + * @see java.io.PipedOutputStream + * @since JDK1.0 + */ + public class PipedInputStream : Tamir.SharpSsh.java.io.InputStream + { + internal bool closedByWriter = false; + internal volatile bool closedByReader = false; + internal bool connected = false; + + /* REMIND: identification of the read and write sides needs to be + more sophisticated. Either using thread groups (but what about + pipes within a thread?) or using finalization (but it may be a + long time until the next GC). */ + internal Thread readSide; + internal Thread writeSide; + + /** + * The size of the pipe's circular input buffer. + * @since JDK1.1 + */ + internal const int PIPE_SIZE = 1024; + + /** + * The circular buffer into which incoming data is placed. + * @since JDK1.1 + */ + internal byte[] buffer = new byte[PIPE_SIZE]; + + /** + * The index of the position in the circular buffer at which the + * next byte of data will be stored when received from the connected + * piped output stream. in<0 implies the buffer is empty, + * in==out implies the buffer is full + * @since JDK1.1 + */ + internal int m_in = -1; + + /** + * The index of the position in the circular buffer at which the next + * byte of data will be read by this piped input stream. + * @since JDK1.1 + */ + internal int m_out = 0; + + /** + * Creates a PipedInputStream so + * that it is connected to the piped output + * stream src. Data bytes written + * to src will then be available + * as input from this stream. + * + * @param src the stream to connect to. + * @exception IOException if an I/O error occurs. + */ + public PipedInputStream(PipedOutputStream src) + { + connect(src); + } + + /** + * Creates a PipedInputStream so + * that it is not yet connected. It must be + * connected to a PipedOutputStream + * before being used. + * + * @see java.io.PipedInputStream#connect(java.io.PipedOutputStream) + * @see java.io.PipedOutputStream#connect(java.io.PipedInputStream) + */ + public PipedInputStream() + { + int i = 0; + } + + /** + * Causes this piped input stream to be connected + * to the piped output stream src. + * If this object is already connected to some + * other piped output stream, an IOException + * is thrown. + *

+ * If src is an + * unconnected piped output stream and snk + * is an unconnected piped input stream, they + * may be connected by either the call: + *

+ *

snk.connect(src) 
+ *

+ * or the call: + *

+ *

src.connect(snk) 
+ *

+ * The two + * calls have the same effect. + * + * @param src The piped output stream to connect to. + * @exception IOException if an I/O error occurs. + */ + public virtual void connect(PipedOutputStream src) + { + src.connect(this); + } + + /** + * Receives a byte of data. This method will block if no input is + * available. + * @param b the byte being received + * @exception IOException If the pipe is broken. + * @since JDK1.1 + */ + [MethodImpl(MethodImplOptions.Synchronized)] + internal void receive(int b) + { + checkStateForReceive(); + writeSide = Thread.CurrentThread; + if (m_in == m_out) + awaitSpace(); + if (m_in < 0) + { + m_in = 0; + m_out = 0; + } + buffer[m_in++] = (byte)(b & 0xFF); + if (m_in >= buffer.Length) + { + m_in = 0; + } + } + + /** + * Receives data into an array of bytes. This method will + * block until some input is available. + * @param b the buffer into which the data is received + * @param off the start offset of the data + * @param len the maximum number of bytes received + * @exception IOException If an I/O error has occurred. + */ + [MethodImpl(MethodImplOptions.Synchronized)] + internal void receive(byte[] b, int off, int len) + { + checkStateForReceive(); + writeSide = Thread.CurrentThread; + int bytesToTransfer = len; + while (bytesToTransfer > 0) + { + if (m_in == m_out) + awaitSpace(); + int nextTransferAmount = 0; + if (m_out < m_in) + { + nextTransferAmount = buffer.Length - m_in; + } + else if (m_in < m_out) + { + if (m_in == -1) + { + m_in = m_out = 0; + nextTransferAmount = buffer.Length - m_in; + } + else + { + nextTransferAmount = m_out - m_in; + } + } + if (nextTransferAmount > bytesToTransfer) + nextTransferAmount = bytesToTransfer; + assert(nextTransferAmount > 0); + Array.Copy(b, off, buffer, m_in, nextTransferAmount); + bytesToTransfer -= nextTransferAmount; + off += nextTransferAmount; + m_in += nextTransferAmount; + if (m_in >= buffer.Length) + { + m_in = 0; + } + } + } + + private void checkStateForReceive() + { + if (!connected) + { + throw new IOException("Pipe not connected"); + } + else if (closedByWriter || closedByReader) + { + throw new IOException("Pipe closed"); + } + else if (readSide != null && !readSide.IsAlive) + { + throw new IOException("Read end dead"); + } + } + + private void awaitSpace() + { + while (m_in == m_out) + { + if ((readSide != null) && !readSide.IsAlive) + { + throw new IOException("Pipe broken"); + } + /* full: kick any waiting readers */ + //java: notifyAll(); + Monitor.PulseAll(this); + try + { + //java: wait(1000); + Monitor.Wait(this, 1000); + } + catch (ThreadInterruptedException ex) + { + throw ex; + } + } + } + + /** + * Notifies all waiting threads that the last byte of data has been + * received. + */ + [MethodImpl(MethodImplOptions.Synchronized)] + internal void receivedLast() + { + closedByWriter = true; + //notifyAll(); + Monitor.PulseAll(this); + } + + /** + * Reads the next byte of data from this piped input stream. The + * value byte is returned as an int in the range + * 0 to 255. If no byte is available + * because the end of the stream has been reached, the value + * -1 is returned. This method blocks until input data + * is available, the end of the stream is detected, or an exception + * is thrown. + * If a thread was providing data bytes + * to the connected piped output stream, but + * the thread is no longer alive, then an + * IOException is thrown. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @exception IOException if the pipe is broken. + */ + [MethodImpl(MethodImplOptions.Synchronized)] + public virtual int read() + { + if (!connected) + { + throw new IOException("Pipe not connected"); + } + else if (closedByReader) + { + throw new IOException("Pipe closed"); + } + else if (writeSide != null && !writeSide.IsAlive + && !closedByWriter && (m_in < 0)) + { + throw new IOException("Write end dead"); + } + + readSide = Thread.CurrentThread; + int trials = 2; + while (m_in < 0) + { + if (closedByWriter) + { + /* closed by writer, return EOF */ + return -1; + } + if ((writeSide != null) && (!writeSide.IsAlive) && (--trials < 0)) + { + throw new IOException("Pipe broken"); + } + /* might be a writer waiting */ + Monitor.PulseAll(this); + try + { + Monitor.Wait(this, 1000); + } + catch (ThreadInterruptedException ex) + { + throw ex; + } + } + int ret = buffer[m_out++] & 0xFF; + if (m_out >= buffer.Length) + { + m_out = 0; + } + if (m_in == m_out) + { + /* now empty */ + m_in = -1; + } + return ret; + } + + /** + * Reads up to len bytes of data from this piped input + * stream into an array of bytes. Less than len bytes + * will be read if the end of the data stream is reached. This method + * blocks until at least one byte of input is available. + * If a thread was providing data bytes + * to the connected piped output stream, but + * the thread is no longer alive, then an + * IOException is thrown. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + */ + [MethodImpl(MethodImplOptions.Synchronized)] + public override int read(byte[] b, int off, int len) + { + if (b == null) + { + throw new NullReferenceException(); + } + else if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0)) + { + throw new IndexOutOfRangeException(); + } + else if (len == 0) + { + return 0; + } + + /* possibly wait on the first character */ + int c = read(); + if (c < 0) + { + return -1; + } + b[off] = (byte) c; + int rlen = 1; + while ((m_in >= 0) && (--len > 0)) + { + b[off + rlen] = buffer[m_out++]; + rlen++; + if (m_out >= buffer.Length) + { + m_out = 0; + } + if (m_in == m_out) + { + /* now empty */ + m_in = -1; + } + } + return rlen; + } + + /** + * Returns the number of bytes that can be read from this input + * stream without blocking. This method overrides the available + * method of the parent class. + * + * @return the number of bytes that can be read from this input stream + * without blocking. + * @exception IOException if an I/O error occurs. + * @since JDK1.0.2 + */ + [MethodImpl(MethodImplOptions.Synchronized)] + public virtual int available() + { + if(m_in < 0) + return 0; + else if(m_in == m_out) + return buffer.Length; + else if (m_in > m_out) + return m_in - m_out; + else + return m_in + buffer.Length - m_out; + } + + /** + * Closes this piped input stream and releases any system resources + * associated with the stream. + * + * @exception IOException if an I/O error occurs. + */ + public override void close() + { + closedByReader = true; + lock (this) + { + m_in = -1; + } + } + + private void assert(bool exp) + { + if (!exp) + throw new Exception("Assertion failed!"); + } + + /////////////////////////////////////// + + + public override int Read(byte[] buffer, int offset, int count) + { + return this.read(buffer, offset, count); + } + + public override int ReadByte() + { + return this.read(); + } + + public override void WriteByte(byte value) + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + } + public override void Close() + { + base.Close (); + this.close(); + } + public override bool CanRead + { + get + { + return true; + } + } + public override bool CanWrite + { + get + { + return false; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override void Flush() + { + + } + public override long Length + { + get + { + if(m_in > m_out) + return (m_in - m_out); + else + { + return (buffer.Length -m_out+m_in); + } + } + } + public override long Position + { + get + { + return m_out; + } + set + { + throw new IOException("Setting the position of this stream is not supported"); + } + } + public override void SetLength(long value) + { + throw new IOException("Setting the length of this stream is not supported"); + } + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + } +} diff --git a/SharpSSH/Streams/PipedOutputStream.cs b/SharpSSH/Streams/PipedOutputStream.cs new file mode 100644 index 00000000..632c7fb5 --- /dev/null +++ b/SharpSSH/Streams/PipedOutputStream.cs @@ -0,0 +1,276 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; + +namespace Tamir.Streams +{ + /* + * @(#)PipedOutputStream.java 1.26 03/12/19 + * + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + + /** + * A piped output stream can be connected to a piped input stream + * to create a communications pipe. The piped output stream is the + * sending end of the pipe. Typically, data is written to a + * PipedOutputStream object by one thread and data is + * read from the connected PipedInputStream by some + * other thread. Attempting to use both objects from a single thread + * is not recommended as it may deadlock the thread. + * + * @author James Gosling + * @version 1.26, 12/19/03 + * @see java.io.PipedInputStream + * @since JDK1.0 + */ + public class PipedOutputStream : Tamir.SharpSsh.java.io.OutputStream + { + + /* REMIND: identification of the read and write sides needs to be + more sophisticated. Either using thread groups (but what about + pipes within a thread?) or using finalization (but it may be a + long time until the next GC). */ + private PipedInputStream sink; + + /** + * Creates a piped output stream connected to the specified piped + * input stream. Data bytes written to this stream will then be + * available as input from snk. + * + * @param snk The piped input stream to connect to. + * @exception IOException if an I/O error occurs. + */ + public PipedOutputStream(PipedInputStream snk) + { + connect(snk); + } + + /** + * Creates a piped output stream that is not yet connected to a + * piped input stream. It must be connected to a piped input stream, + * either by the receiver or the sender, before being used. + * + * @see java.io.PipedInputStream#connect(java.io.PipedOutputStream) + * @see java.io.PipedOutputStream#connect(java.io.PipedInputStream) + */ + public PipedOutputStream() + { + } + + /** + * Connects this piped output stream to a receiver. If this object + * is already connected to some other piped input stream, an + * IOException is thrown. + *

+ * If snk is an unconnected piped input stream and + * src is an unconnected piped output stream, they may + * be connected by either the call: + *

+		 * src.connect(snk)
+ * or the call: + *
+		 * snk.connect(src)
+ * The two calls have the same effect. + * + * @param snk the piped input stream to connect to. + * @exception IOException if an I/O error occurs. + */ + [MethodImpl(MethodImplOptions.Synchronized)] + public virtual void connect(PipedInputStream snk) + { + if (snk == null) + { + throw new NullReferenceException(); + } + else if (sink != null || snk.connected) + { + throw new IOException("Already connected"); + } + sink = snk; + snk.m_in = -1; + snk.m_out = 0; + snk.connected = true; + int t=0; + } + + /** + * Writes the specified byte to the piped output stream. + * If a thread was reading data bytes from the connected piped input + * stream, but the thread is no longer alive, then an + * IOException is thrown. + *

+ * Implements the write method of OutputStream. + * + * @param b the byte to be written. + * @exception IOException if an I/O error occurs. + */ + public virtual void write(int b) + { + if (sink == null) + { + throw new IOException("Pipe not connected"); + } + sink.receive(b); + } + + /** + * Writes len bytes from the specified byte array + * starting at offset off to this piped output stream. + * If a thread was reading data bytes from the connected piped input + * stream, but the thread is no longer alive, then an + * IOException is thrown. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception IOException if an I/O error occurs. + */ + public override void write(byte[] b, int off, int len) + { + if (sink == null) + { + throw new IOException("Pipe not connected"); + } + else if (b == null) + { + throw new NullReferenceException(); + } + else if ((off < 0) || (off > b.Length) || (len < 0) || + ((off + len) > b.Length) || ((off + len) < 0)) + { + throw new IndexOutOfRangeException(); + } + else if (len == 0) + { + return; + } + sink.receive(b, off, len); + } + + public virtual void write(byte[] b) + { + write(b, 0, b.Length); + } + + /** + * Flushes this output stream and forces any buffered output bytes + * to be written out. + * This will notify any readers that bytes are waiting in the pipe. + * + * @exception IOException if an I/O error occurs. + */ + [MethodImpl(MethodImplOptions.Synchronized)] + public override void flush() + { + if (sink != null) + { + lock (sink) + { + //sink.notifyAll(); + System.Threading.Monitor.PulseAll(sink); + } + } + } + + /** + * Closes this piped output stream and releases any system resources + * associated with this stream. This stream may no longer be used for + * writing bytes. + * + * @exception IOException if an I/O error occurs. + */ + public override void close() + { + if (sink != null) + { + sink.receivedLast(); + } + } + + /////////////////////////////////////// + + + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + + public override int ReadByte() + { + return 0; + } + + public override void WriteByte(byte value) + { + this.write(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + this.write(buffer, offset, count); + } + public virtual void Write(byte[] buffer) + { + this.Write(buffer, 0, buffer.Length); + } + public override void Close() + { + base.Close (); + this.close(); + } + public override bool CanRead + { + get + { + return false; + } + } + public override bool CanWrite + { + get + { + return true; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override void Flush() + { + this.flush(); + } + public override long Length + { + get + { + return sink.Length; + } + } + public override long Position + { + get + { + return sink.m_in; + } + set + { + throw new IOException("Setting the position of this stream is not supported"); + } + } + public override void SetLength(long value) + { + throw new IOException("Setting the length of this stream is not supported"); + } + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + } + +} diff --git a/SharpSSH/Streams/PipedStream.cs b/SharpSSH/Streams/PipedStream.cs new file mode 100644 index 00000000..f6129854 --- /dev/null +++ b/SharpSSH/Streams/PipedStream.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; + +namespace Tamir.Streams +{ + ///

+ /// Summary description for PipedStream. + /// + public class PipedStream : Stream + { + PipedInputStream pins; + PipedOutputStream pouts; + + public PipedStream(PipedInputStream pins, PipedOutputStream pouts) + { + this.pins = pins; + this.pouts = pouts; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return pins.read(buffer, offset, count); + } + + public override int ReadByte() + { + return pins.read(); + } + + public override void WriteByte(byte value) + { + pouts.write(value); + } + + + public override void Write(byte[] buffer, int offset, int count) + { + pouts.write(buffer, offset, count); + } + public override void Close() + { + base.Close (); + pins.close(); + pouts.close(); + } + public override bool CanRead + { + get + { + return true; + } + } + public override bool CanWrite + { + get + { + return true; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override void Flush() + { + + } + public override long Length + { + get + { + return 0; + } + } + public override long Position + { + get + { + return 0; + } + set + { + } + } + public override void SetLength(long value) + { + + } + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + } +} diff --git a/SharpSSH/Streams/ProtectedConsoleStream.cs b/SharpSSH/Streams/ProtectedConsoleStream.cs new file mode 100644 index 00000000..c397434f --- /dev/null +++ b/SharpSSH/Streams/ProtectedConsoleStream.cs @@ -0,0 +1,174 @@ +using System; +using System.IO; + +/* + * ProtectedConsoleStream.cs + * + * Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * + * 3. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * *OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + **/ +namespace Tamir.Streams +{ + /// + /// This class provide access to the console stream obtained by calling the + /// Console.OpenStandardInput() and Console.OpenStandardOutput(), and prevents reading + /// into buffers to large for the Console Stream + /// + public class ProtectedConsoleStream : System.IO.Stream + { + Stream s; + public ProtectedConsoleStream(Stream s) + { + if((s.GetType() != Type.GetType("System.IO.__ConsoleStream"))&& + (s.GetType() != Type.GetType("System.IO.FileStream")))//for mono + { + throw new ArgumentException("Not ConsoleStream"); + } + this.s=s; + } + +// public static Stream Protect(Stream s) +// { +// if(s.GetType() == Console. +// } + + public override int Read(byte[] buffer, int offset, int count) + { + if(count > 256) + count = 256; + return s.Read(buffer, offset, count); + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return s.BeginRead (buffer, offset, count, callback, state); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return s.BeginWrite (buffer, offset, count, callback, state); + } + + public override bool CanRead + { + get + { + return s.CanRead; + } + } + + public override bool CanSeek + { + get + { + return s.CanSeek; + } + } + public override bool CanWrite + { + get + { + return s.CanWrite; + } + } + public override void Close() + { + s.Close (); + } + public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType) + { + return s.CreateObjRef (requestedType); + } + public override int EndRead(IAsyncResult asyncResult) + { + return s.EndRead (asyncResult); + } + public override void EndWrite(IAsyncResult asyncResult) + { + s.EndWrite (asyncResult); + } + public override bool Equals(object obj) + { + return s.Equals (obj); + } + public override void Flush() + { + s.Flush(); + } + public override int GetHashCode() + { + return s.GetHashCode (); + } + public override object InitializeLifetimeService() + { + return s.InitializeLifetimeService (); + } + public override long Length + { + get + { + return s.Length; + } + } + public override long Position + { + get + { + return s.Position; + } + set + { + s.Position = value; + } + } + public override int ReadByte() + { + return s.ReadByte (); + } + public override long Seek(long offset, SeekOrigin origin) + { + return s.Seek(offset, origin); + } + public override void SetLength(long value) + { + s.SetLength(value); + } + public override string ToString() + { + return s.ToString (); + } + public override void Write(byte[] buffer, int offset, int count) + { + s.Write(buffer, offset, count); + } + public override void WriteByte(byte value) + { + s.WriteByte (value); + } + + } +} diff --git a/SharpSSH/java/Exception.cs b/SharpSSH/java/Exception.cs new file mode 100644 index 00000000..a184580b --- /dev/null +++ b/SharpSSH/java/Exception.cs @@ -0,0 +1,22 @@ +using Ex = System.Exception; + +namespace Tamir.SharpSsh.java +{ + /// + /// Summary description for Exception. + /// + public class Exception : Ex + { + public Exception() : base() + { + } + public Exception(string msg) : base(msg) + { + } + + public virtual string toString() + { + return ToString(); + } + } +} diff --git a/SharpSSH/java/Platform.cs b/SharpSSH/java/Platform.cs new file mode 100644 index 00000000..2753f61a --- /dev/null +++ b/SharpSSH/java/Platform.cs @@ -0,0 +1,18 @@ +using System; + +namespace Tamir.SharpSsh.java +{ + /// + /// Summary description for Platform. + /// + public class Platform + { + public static bool Windows + { + get + { + return Environment.OSVersion.Platform.ToString().StartsWith("Win"); + } + } + } +} diff --git a/SharpSSH/java/RuntimeException.cs b/SharpSSH/java/RuntimeException.cs new file mode 100644 index 00000000..f96f7217 --- /dev/null +++ b/SharpSSH/java/RuntimeException.cs @@ -0,0 +1,17 @@ +using System; + +namespace Tamir.SharpSsh.java +{ + /// + /// Summary description for RuntimeException. + /// + public class RuntimeException : Exception + { + public RuntimeException() + { + // + // TODO: Add constructor logic here + // + } + } +} diff --git a/SharpSSH/java/String.cs b/SharpSSH/java/String.cs new file mode 100644 index 00000000..61225c4c --- /dev/null +++ b/SharpSSH/java/String.cs @@ -0,0 +1,177 @@ +using System; +using Text = System.Text; +using Str = System.String; + +namespace Tamir.SharpSsh.java +{ + /// + /// Summary description for String. + /// + public class String + { + string s; + public String(string s) + { + this.s=s; + } + + public String(object o):this(o.ToString()) + { + } + + public String(byte[] arr):this(getString(arr)) + { + } + + public String(byte[] arr, int offset, int len):this(getString(arr, offset, len)) + { + } + + public static implicit operator String (string s1) + { + if(s1==null) return null; + return new String(s1); + } + + public static implicit operator Str (String s1) + { + if(s1==null) return null; + return s1.ToString(); + } + + public static Tamir.SharpSsh.java.String operator+(Tamir.SharpSsh.java.String s1, Tamir.SharpSsh.java.String s2) + { + return new Tamir.SharpSsh.java.String(s1.ToString()+s2.ToString()); + } + + public byte[] getBytes() + { + return String.getBytes(this); + } + + public override string ToString() + { + return s; + } + + public String toLowerCase() + { + return this.ToString().ToLower(); + } + + public bool startsWith(string prefix) + { + return this.ToString().StartsWith(prefix); + } + + public int indexOf(string sub) + { + return this.ToString().IndexOf(sub); + } + + public int indexOf(char sub) + { + return this.ToString().IndexOf(sub); + } + + public int indexOf(char sub, int i) + { + return this.ToString().IndexOf(sub, i); + } + + public char charAt(int i) + { + return s[i]; + } + + public String substring(int start, int end) + { + int len = end - start; + return this.ToString().Substring(start, len); + } + + public String subString(int start, int len) + { + return substring(start, len); + } + + public String substring(int len) + { + return this.ToString().Substring(len); + } + + public String subString(int len) + { + return substring(len); + } + + public int Length() + { + return this.ToString().Length; + } + + public int length() + { + return Length(); + } + + public bool endsWith(string str) + { + return s.EndsWith(str); + } + + public int lastIndexOf(string str) + { + return s.LastIndexOf(str); + } + + public int lastIndexOf(char c) + { + return s.LastIndexOf(c); + } + + public bool equals(object o) + { + return this.ToString().Equals(o.ToString()); + } + + public override bool Equals(object obj) + { + return this.equals (obj); + } + + public override int GetHashCode() + { + return s.GetHashCode (); + } + + public static string getString(byte[] arr) + { + return getString(arr, 0, arr.Length); + } + + public static string getString(byte[] arr, int offset, int len) + { + return Text.Encoding.Default.GetString(arr, offset, len); + } + + public static string getStringUTF8(byte[] arr) + { + return getStringUTF8(arr, 0, arr.Length); + } + + public static string getStringUTF8(byte[] arr, int offset, int len) + { + return Text.Encoding.UTF8.GetString(arr, offset, len); + } + + public static byte[] getBytes(string str) + { + return getBytesUTF8( str ); + } + public static byte[] getBytesUTF8(string str) + { + return Text.Encoding.UTF8.GetBytes( str ); + } + } +} diff --git a/SharpSSH/java/System.cs b/SharpSSH/java/System.cs new file mode 100644 index 00000000..c71c2f5a --- /dev/null +++ b/SharpSSH/java/System.cs @@ -0,0 +1,43 @@ +using System; + +namespace Tamir.SharpSsh.java +{ + /// + /// Summary description for System. + /// + public class System + { + public static Out Out = new Out(); + public static Err err = new Err(); + public static void arraycopy(Array a1, long sourceIndex, Array a2, long destIndex, long len) + { + Array.Copy(a1, sourceIndex, a2, destIndex, len); + } + } + + public class Out + { + public void print(string v) + { + Console.Write(v); + } + + public void println(string v) + { + Console.WriteLine(v); + } + } + + public class Err + { + public void print(string v) + { + Console.Error.Write(v); + } + + public void println(string v) + { + Console.Error.WriteLine(v); + } + } +} diff --git a/SharpSSH/java/io/File.cs b/SharpSSH/java/io/File.cs new file mode 100644 index 00000000..ea7489d5 --- /dev/null +++ b/SharpSSH/java/io/File.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; + +namespace Tamir.SharpSsh.java.io +{ + /// + /// Summary description for File. + /// + public class File + { + string file; + internal FileInfo info; + + public File(string file) + { + this.file = file; + info = new FileInfo(file); + } + + public string getCanonicalPath() + { + return Path.GetFullPath(file); + } + + public bool isDirectory() + { + return Directory.Exists(file); + } + + public long Length() + { + return info.Length; + } + + public long length() + { + return Length(); + } + + public bool isAbsolute() + { + return Path.IsPathRooted(file); + } + + public java.String[] list() + { + string [] dirs = Directory.GetDirectories(file); + string [] files = Directory.GetFiles(file); + java.String[] _list = new java.String[dirs.Length+files.Length]; + System.arraycopy(dirs, 0, _list, 0, dirs.Length); + System.arraycopy(files, 0, _list, dirs.Length, files.Length); + return _list; + } + + public static string separator + { + get + { + return Path.DirectorySeparatorChar.ToString(); + } + } + + public static char separatorChar + { + get + { + return Path.DirectorySeparatorChar; + } + } + } +} diff --git a/SharpSSH/java/io/FileInputStream.cs b/SharpSSH/java/io/FileInputStream.cs new file mode 100644 index 00000000..6a4eab22 --- /dev/null +++ b/SharpSSH/java/io/FileInputStream.cs @@ -0,0 +1,45 @@ +using System; +using IO = System.IO; + +namespace Tamir.SharpSsh.java.io +{ + /// + /// Summary description for FileInputStream. + /// + public class FileInputStream : InputStream + { + IO.FileStream fs; + public FileInputStream(string file) + { + fs = IO.File.OpenRead(file); + } + + public FileInputStream(File file):this(file.info.Name) + { + } + + public override void Close() + { + fs.Close(); + } + + + public override int Read(byte[] buffer, int offset, int count) + { + return fs.Read(buffer, offset, count); + } + + public override bool CanSeek + { + get + { + return fs.CanSeek; + } + } + + public override long Seek(long offset, IO.SeekOrigin origin) + { + return fs.Seek(offset, origin); + } + } +} diff --git a/SharpSSH/java/io/FileOutputStream.cs b/SharpSSH/java/io/FileOutputStream.cs new file mode 100644 index 00000000..a9c17f6a --- /dev/null +++ b/SharpSSH/java/io/FileOutputStream.cs @@ -0,0 +1,60 @@ +using System; +using IO = System.IO; + +namespace Tamir.SharpSsh.java.io +{ + /// + /// Summary description for FileInputStream. + /// + public class FileOutputStream : OutputStream + { + IO.FileStream fs; + public FileOutputStream(string file):this(file, false) + { + } + + public FileOutputStream(File file):this(file.info.Name, false) + { + } + + public FileOutputStream(string file, bool append) + { + if(append) + fs = new IO.FileStream(file, IO.FileMode.Append); // append + else + fs = new IO.FileStream(file, IO.FileMode.Create); + } + + public FileOutputStream(File file, bool append):this(file.info.Name) + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + fs.Write(buffer, offset, count); + } + + public override void Flush() + { + fs.Flush(); + } + + public override void Close() + { + fs.Close(); + } + + public override bool CanSeek + { + get + { + return fs.CanSeek; + } + } + + public override long Seek(long offset, IO.SeekOrigin origin) + { + return fs.Seek(offset, origin); + } + } +} diff --git a/SharpSSH/java/io/InputStream.cs b/SharpSSH/java/io/InputStream.cs new file mode 100644 index 00000000..75e18238 --- /dev/null +++ b/SharpSSH/java/io/InputStream.cs @@ -0,0 +1,110 @@ +using System; +using IO = System.IO; + +namespace Tamir.SharpSsh.java.io +{ + /// + /// Summary description for InputStream. + /// + public abstract class InputStream : IO.Stream + { + public virtual int read(byte[] buffer, int offset, int count) + { + return this.Read(buffer, offset, count); + } + + public virtual int read(byte[] buffer) + { + return this.Read(buffer, 0, buffer.Length); + } + + public virtual int read() + { + return this.ReadByte(); + } + + public virtual void close() + { + Close(); + } + + public override void WriteByte(byte value) + { + } + + public override void Write(byte[] buffer, int offset, int count) + { + } + + public override bool CanRead + { + get + { + return true; + } + } + public override bool CanWrite + { + get + { + return false; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override void Flush() + { + + } + public override long Length + { + get + { + return 0; + } + } + public override long Position + { + get + { + return 0; + } + set + { + } + } + public override void SetLength(long value) + { + } + public override long Seek(long offset, IO.SeekOrigin origin) + { + return 0; + } + + public long skip(long len) + { + //Seek doesn't work + //return Seek(offset, IO.SeekOrigin.Current); + int i=0; + int count = 0; + byte[] buf = new byte[len]; + while(len>0) + { + i=Read(buf, count, (int)len);//tamir: possible lost of pressision + if(i<=0) + { + throw new Exception("inputstream is closed"); + //return (s-foo)==0 ? i : s-foo; + } + count+=i; + len-=i; + } + return count; + } + } +} diff --git a/SharpSSH/java/io/InputStreamWrapper.cs b/SharpSSH/java/io/InputStreamWrapper.cs new file mode 100644 index 00000000..4952505e --- /dev/null +++ b/SharpSSH/java/io/InputStreamWrapper.cs @@ -0,0 +1,21 @@ +using Tamir.SharpSsh.java.io; + +namespace Tamir.Streams +{ + /// + /// Summary description for InputStreamWrapper. + /// + public class InputStreamWrapper : InputStream + { + System.IO.Stream s; + public InputStreamWrapper(System.IO.Stream s) + { + this.s = s; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return s.Read(buffer, offset, count); + } + } +} diff --git a/SharpSSH/java/io/JStream.cs b/SharpSSH/java/io/JStream.cs new file mode 100644 index 00000000..74124313 --- /dev/null +++ b/SharpSSH/java/io/JStream.cs @@ -0,0 +1,156 @@ +using System; +using IO = System.IO; + +namespace Tamir.SharpSsh.java.io +{ + /// + /// Summary description for Stream. + /// + public class JStream : IO.Stream + { + internal IO.Stream s; + public JStream(IO.Stream s) + { + this.s = s; + } + + public override int Read(byte[] buffer, int offset, int count) + { + return s.Read(buffer, offset, count); + } + + public override int ReadByte() + { + return s.ReadByte(); + } + + public int read(byte[] buffer, int offset, int count) + { + return Read(buffer, offset, count); + } + + public int read(byte[] buffer) + { + return Read(buffer, 0, buffer.Length); + } + + public int read() + { + return ReadByte(); + } + + public void close() + { + this.Close(); + } + + public override void Close() + { + s.Close (); + } + + public override void WriteByte(byte value) + { + s.WriteByte(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + s.Write(buffer, offset, count); + } + + public void write(byte[] buffer, int offset, int count) + { + Write(buffer, offset, count); + } + + public void write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + public override bool CanRead + { + get {return s.CanRead;} + } + public override bool CanWrite + { + get + { + return s.CanWrite; + } + } + public override bool CanSeek + { + get + { + return s.CanSeek; + } + } + public override void Flush() + { + s.Flush(); + } + public override long Length + { + get + { + return s.Length; + } + } + public override long Position + { + get + { + return s.Position; + } + set + { + s.Position = value; + } + } + public override void SetLength(long value) + { + s.SetLength(value); + } + public override long Seek(long offset, IO.SeekOrigin origin) + { + return s.Seek(offset, origin); + } + + public long skip(long len) + { + //Seek doesn't work + //return Seek(offset, IO.SeekOrigin.Current); + int i=0; + int count = 0; + byte[] buf = new byte[len]; + while(len>0) + { + i=Read(buf, count, (int)len);//tamir: possible lost of pressision + if(i<=0) + { + throw new Exception("inputstream is closed"); + //return (s-foo)==0 ? i : s-foo; + } + count+=i; + len-=i; + } + return count; + } + + public int available() + { + if(s is Tamir.Streams.PipedInputStream) + { + return ((Tamir.Streams.PipedInputStream)s).available(); + } + throw new Exception("JStream.available() -- Method not implemented"); + } + + public void flush() + { + s.Flush(); + } + } +} diff --git a/SharpSSH/java/io/OutputStream.cs b/SharpSSH/java/io/OutputStream.cs new file mode 100644 index 00000000..a8e8ed6f --- /dev/null +++ b/SharpSSH/java/io/OutputStream.cs @@ -0,0 +1,85 @@ +using System; +using System.IO; + +namespace Tamir.SharpSsh.java.io +{ + /// + /// Summary description for InputStream. + /// + public abstract class OutputStream : Stream + { + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + + public override int ReadByte() + { + return 0; + } + + public virtual void write(byte[] buffer, int offset, int count) + { + Write(buffer, offset, count); + } + + public virtual void close() + { + Close(); + } + + public virtual void flush() + { + Flush(); + } + + public override bool CanRead + { + get + { + return false; + } + } + public override bool CanWrite + { + get + { + return true; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override void Flush() + { + } + public override long Length + { + get + { + return 0; + } + } + public override long Position + { + get + { + return 0; + } + set + { + } + } + public override void SetLength(long value) + { + } + public override long Seek(long offset, SeekOrigin origin) + { + return 0; + } + } +} diff --git a/SharpSSH/java/lang/Class.cs b/SharpSSH/java/lang/Class.cs new file mode 100644 index 00000000..2de93eea --- /dev/null +++ b/SharpSSH/java/lang/Class.cs @@ -0,0 +1,28 @@ +using System; + +namespace Tamir.SharpSsh.java.lang +{ + /// + /// Summary description for Class. + /// + public class Class + { + Type t; + private Class(Type t) + { + this.t=t; + } + private Class(string typeName) : this(Type.GetType(typeName)) + { + } + public static Class forName(string name) + { + return new Class(name); + } + + public object newInstance() + { + return Activator.CreateInstance(t); + } + } +} diff --git a/SharpSSH/java/lang/Integer.cs b/SharpSSH/java/lang/Integer.cs new file mode 100644 index 00000000..d9411817 --- /dev/null +++ b/SharpSSH/java/lang/Integer.cs @@ -0,0 +1,24 @@ +using System; + +namespace Tamir.SharpSsh.java.lang +{ + /// + /// Summary description for Integer. + /// + public class Integer + { + private int i; + public Integer(int i) + { + this.i = i; + } + public int intValue() + { + return i; + } + public static int parseInt(string s) + { + return int.Parse(s); + } + } +} diff --git a/SharpSSH/java/lang/Runnable.cs b/SharpSSH/java/lang/Runnable.cs new file mode 100644 index 00000000..3646097c --- /dev/null +++ b/SharpSSH/java/lang/Runnable.cs @@ -0,0 +1,12 @@ +using System; + +namespace Tamir.SharpSsh.java.lang +{ + /// + /// Summary description for Runnable. + /// + public interface Runnable + { + void run(); + } +} diff --git a/SharpSSH/java/lang/StringBuffer.cs b/SharpSSH/java/lang/StringBuffer.cs new file mode 100644 index 00000000..fbf6c5cd --- /dev/null +++ b/SharpSSH/java/lang/StringBuffer.cs @@ -0,0 +1,64 @@ +using System; +using System.Text; + +namespace Tamir.SharpSsh.java.lang +{ + /// + /// Summary description for StringBuffer. + /// + public class StringBuffer + { + StringBuilder sb; + public StringBuffer() + { + sb = new StringBuilder(); + } + + public StringBuffer(string s) + { + sb = new StringBuilder(s); + } + + public StringBuffer(StringBuilder sb):this(sb.ToString()) + { + } + + public StringBuffer(Tamir.SharpSsh.java.String s):this(s.ToString()) + { + } + + public StringBuffer append(string s) + { + sb.Append(s); + return this; + } + + public StringBuffer append(char s) + { + sb.Append(s); + return this; + } + + public StringBuffer append(Tamir.SharpSsh.java.String s) + { + return append(s.ToString()); + } + + public StringBuffer delete(int start, int end) + { + sb.Remove(start, end-start); + return this; + } + + public override string ToString() + { + return sb.ToString(); + } + + public string toString() + { + return ToString(); + } + + } +} diff --git a/SharpSSH/java/lang/Thread.cs b/SharpSSH/java/lang/Thread.cs new file mode 100644 index 00000000..34489562 --- /dev/null +++ b/SharpSSH/java/lang/Thread.cs @@ -0,0 +1,75 @@ +using System; +using System.Threading; +using Threading = System.Threading; + +namespace Tamir.SharpSsh.java.lang +{ + /// + /// Summary description for Thread. + /// + public class Thread + { + Threading.Thread t; + + public Thread(Threading.Thread t) + { + this.t=t; + } + public Thread(ThreadStart ts):this(new Threading.Thread(ts)) + { + } + + public Thread(Runnable r):this(new ThreadStart(r.run)) + { + } + + public void setName(string name) + { + t.Name=name; + } + + public void start() + { + t.Start(); + } + + public bool isAlive() + { + return t.IsAlive; + } + + public void yield() + { + } + + public void interrupt() + { + try + { + t.Interrupt(); + }catch + { + } + } + + public void notifyAll() + { + Monitor.PulseAll(this); + } + + public static void Sleep(int t) + { + Threading.Thread.Sleep(t); + } + + public static void sleep(int t) + { + Sleep(t); + } + + public static Thread currentThread() + { + return new Thread( Threading.Thread.CurrentThread ); + } + } +} diff --git a/SharpSSH/java/net/InetAddress.cs b/SharpSSH/java/net/InetAddress.cs new file mode 100644 index 00000000..cb28dfff --- /dev/null +++ b/SharpSSH/java/net/InetAddress.cs @@ -0,0 +1,61 @@ +using System; +using System.Net; + +namespace Tamir.SharpSsh.java.net +{ + /// + /// Summary description for InetAddress. + /// + public class InetAddress + { + internal IPAddress addr; + public InetAddress(string addr) + { + this.addr = IPAddress.Parse(addr); + } + public InetAddress(IPAddress addr) + { + this.addr = addr; + } + + public bool isAnyLocalAddress() + { + return IPAddress.IsLoopback(addr); + } + + public bool equals(InetAddress addr) + { + return addr.ToString().Equals( addr.ToString()); + } + + public bool equals(string addr) + { + return addr.ToString().Equals( addr.ToString()); + } + + public override string ToString() + { + return addr.ToString (); + } + + public override bool Equals(object obj) + { + return equals (obj.ToString()); + } + + public string getHostAddress() + { + return ToString(); + } + + public override int GetHashCode() + { + return base.GetHashCode (); + } + + public static InetAddress getByName(string name) + { + return new InetAddress( Dns.GetHostByName(name).AddressList[0] ); + } + } +} diff --git a/SharpSSH/java/net/ServerSocket.cs b/SharpSSH/java/net/ServerSocket.cs new file mode 100644 index 00000000..52daa8a0 --- /dev/null +++ b/SharpSSH/java/net/ServerSocket.cs @@ -0,0 +1,27 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Tamir.SharpSsh.java.net +{ + /// + /// Summary description for ServerSocket. + /// + public class ServerSocket : TcpListener + { + public ServerSocket(int port, int arg, InetAddress addr) : base(addr.addr, port) + { + this.Start(); + } + + public Tamir.SharpSsh.java.net.Socket accept() + { + return new Tamir.SharpSsh.java.net.Socket( this.AcceptSocket() ); + } + + public void close() + { + this.Stop(); + } + } +} diff --git a/SharpSSH/java/net/Socket.cs b/SharpSSH/java/net/Socket.cs new file mode 100644 index 00000000..5b28ea6e --- /dev/null +++ b/SharpSSH/java/net/Socket.cs @@ -0,0 +1,95 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using Net = System.Net; +using Sock = System.Net.Sockets.Socket; + +namespace Tamir.SharpSsh.java.net +{ + /// + /// Summary description for Socket. + /// + public class Socket + { + internal Sock sock; + + protected void SetSocketOption(SocketOptionLevel level, SocketOptionName name, int val) + { + try + { + sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, val); + } + catch + { + } + } + +// public Socket(AddressFamily af, SocketType st, ProtocolType pt) +// { +// this.sock = new Sock(af, st, pt); +// this.sock.Connect(); +// } + + public Socket(string host, int port) + { + IPEndPoint ep = new IPEndPoint(Dns.GetHostByName(host).AddressList[0], port); + this.sock = new Sock(ep.AddressFamily, + SocketType.Stream, ProtocolType.Tcp); + this.sock.Connect(ep); + } + + public Socket(Sock sock) + { + this.sock = sock; + } + + public Stream getInputStream() + { + return new Net.Sockets.NetworkStream(sock); + } + + public Stream getOutputStream() + { + return new Net.Sockets.NetworkStream(sock); + } + + public bool isConnected() + { + return sock.Connected; + } + + public void setTcpNoDelay(bool b) + { + if(b) + { + SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1); + } + else + { + SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 0); + } + } + + public void setSoTimeout(int t) + { + SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, t); + SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, t); + } + + public void close() + { + sock.Close(); + } + + public InetAddress getInetAddress() + { + return new InetAddress( ((IPEndPoint) sock.RemoteEndPoint).Address ); + } + + public int getPort() + { + return ((IPEndPoint) sock.RemoteEndPoint).Port; + } + } +} diff --git a/SharpSSH/java/util/Arrays.cs b/SharpSSH/java/util/Arrays.cs new file mode 100644 index 00000000..4a9fbe78 --- /dev/null +++ b/SharpSSH/java/util/Arrays.cs @@ -0,0 +1,19 @@ +using System; + +namespace Tamir.SharpSsh.java.util +{ + /// + /// Summary description for Arrays. + /// + public class Arrays + { + internal static bool equals(byte[] foo, byte[] bar) + { + int i=foo.Length; + if(i!=bar.Length) return false; + for(int j=0; j + /// Summary description for Enumeration. + /// + public class Enumeration + { + private IEnumerator e; + private bool hasMore; + public Enumeration(IEnumerator e) + { + this.e=e; + hasMore = e.MoveNext(); + } + + public bool hasMoreElements() + { + return hasMore; + } + + public object nextElement() + { + object o = e.Current; + hasMore = e.MoveNext(); + return o; + } + } +} diff --git a/SharpSSH/java/util/Hashtable.cs b/SharpSSH/java/util/Hashtable.cs new file mode 100644 index 00000000..e8a77d14 --- /dev/null +++ b/SharpSSH/java/util/Hashtable.cs @@ -0,0 +1,43 @@ +using System; +using Collections = System.Collections; + +namespace Tamir.SharpSsh.java.util +{ + /// + /// Summary description for Hashtable. + /// + public class Hashtable + { + internal Collections.Hashtable h; + + public Hashtable() + { + h= new Collections.Hashtable(); + } + public Hashtable(Collections.Hashtable h) + { + this.h=h; + } + + public void put(object key, object item) + { + h.Add(key, item); + } + + public object get(object key) + { + return h[key]; + } + + public Enumeration keys() + { + return new Enumeration( h.Keys.GetEnumerator() ); + } + + public object this[object key] + { + get{return get(key);} + set{h[key]=value;} + } + } +} diff --git a/SharpSSH/java/util/JavaString.cs b/SharpSSH/java/util/JavaString.cs new file mode 100644 index 00000000..b9fac6b5 --- /dev/null +++ b/SharpSSH/java/util/JavaString.cs @@ -0,0 +1,27 @@ +using System; + +namespace Tamir.SharpSsh.java.util +{ + /// + /// Summary description for JavaString. + /// + public class JavaString : Tamir.SharpSsh.java.String + { + public JavaString(string s) : base(s) + { + } + + public JavaString(object o):base(o) + { + } + + public JavaString(byte[] arr):base(arr) + { + } + + public JavaString(byte[] arr, int offset, int len):base(arr, offset, len) + { + } + + } +} diff --git a/SharpSSH/java/util/Vector.cs b/SharpSSH/java/util/Vector.cs new file mode 100644 index 00000000..1a6b270d --- /dev/null +++ b/SharpSSH/java/util/Vector.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections; + +namespace Tamir.SharpSsh.java.util +{ + /// + /// Summary description for Vector. + /// + public class Vector : ArrayList + { + public int size() + { + return this.Count; + } + + public void addElement(object o) + { + this.Add(o); + } + + public void add(object o) + { + addElement(o); + } + + public void removeElement(object o) + { + this.Remove(o); + } + + public bool remove(object o) + { + this.Remove(o); + return true; + } + + public object elementAt(int i) + { + return this[i]; + } + + public object get(int i) + { + return elementAt(i);; + } + + public void clear() + { + this.Clear(); + } + + public string toString() + { + return ToString(); + } + } +} diff --git a/SharpSSH/jsch/Buffer.cs b/SharpSSH/jsch/Buffer.cs new file mode 100644 index 00000000..985b0c22 --- /dev/null +++ b/SharpSSH/jsch/Buffer.cs @@ -0,0 +1,262 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class Buffer + { + static byte[] tmp=new byte[4]; + internal byte[] buffer; + internal int index; + internal int s; + public Buffer(int size) + { + buffer=new byte[size]; + index=0; + s=0; + } + public Buffer(byte[] buffer) + { + this.buffer=buffer; + index=0; + s=0; + } + public Buffer():this(1024*10*2){ } + public void putByte(byte foo) + { + buffer[index++]=foo; + } + public void putByte(byte[] foo) + { + putByte(foo, 0, foo.Length); + } + public void putByte(byte[] foo, int begin, int length) + { + Array.Copy(foo, begin, buffer, index, length); + index+=length; + } + public void putString(byte[] foo) + { + putString(foo, 0, foo.Length); + } + public void putString(byte[] foo, int begin, int length) + { + putInt(length); + putByte(foo, begin, length); + } + public void putInt(int v) + { + uint val = (uint)v; + tmp[0]=(byte)(val >> 24); + tmp[1]=(byte)(val >> 16); + tmp[2]=(byte)(val >> 8); + tmp[3]=(byte)(val); + Array.Copy(tmp, 0, buffer, index, 4); + index+=4; + } + public void putLong(long v) + { + ulong val = (ulong)v; + tmp[0]=(byte)(val >> 56); + tmp[1]=(byte)(val >> 48); + tmp[2]=(byte)(val >>40); + tmp[3]=(byte)(val >> 32); + Array.Copy(tmp, 0, buffer, index, 4); + tmp[0]=(byte)(val >> 24); + tmp[1]=(byte)(val >> 16); + tmp[2]=(byte)(val >> 8); + tmp[3]=(byte)(val); + Array.Copy(tmp, 0, buffer, index+4, 4); + index+=8; + } + internal void skip(int n) + { + index+=n; + } + internal void putPad(int n) + { + while(n>0) + { + buffer[index++]=(byte)0; + n--; + } + } + public void putMPInt(byte[] foo) + { + int i=foo.Length; + if((foo[0]&0x80)!=0) + { + i++; + putInt(i); + putByte((byte)0); + } + else + { + putInt(i); + } + putByte(foo); + } + public int getLength() + { + return index-s; + } + public int getOffSet() + { + return s; + } + public void setOffSet(int s) + { + this.s=s; + } + public long getLong() + { + long foo = getInt()&0xffffffffL; + foo = ((foo<<32)) | (getInt()&0xffffffffL); + return foo; + } + public int getInt() + { + uint foo = (uint) getShort(); + foo = ((foo<<16)&0xffff0000) | ((uint)getShort()&0xffff); + return (int)foo; + } + internal int getShort() + { + int foo = getByte(); + foo = ((foo<<8)&0xff00)|(getByte()&0xff); + return foo; + } + public int getByte() + { + return (buffer[s++]&0xff); + } + public void getByte(byte[] foo) + { + getByte(foo, 0, foo.Length); + } + void getByte(byte[] foo, int start, int len) + { + Array.Copy(buffer, s, foo, start, len); + s+=len; + } + public int getByte(int len) + { + int foo=s; + s+=len; + return foo; + } + public byte[] getMPInt() + { + int i=getInt(); + byte[] foo=new byte[i]; + getByte(foo, 0, i); + return foo; + } + public byte[] getMPIntBits() + { + int bits=getInt(); + int bytes=(bits+7)/8; + byte[] foo=new byte[bytes]; + getByte(foo, 0, bytes); + if((foo[0]&0x80)!=0) + { + byte[] bar=new byte[foo.Length+1]; + bar[0]=0; // ?? + Array.Copy(foo, 0, bar, 1, foo.Length); + foo=bar; + } + return foo; + } + public byte[] getString() + { + int i=getInt(); + byte[] foo=new byte[i]; + getByte(foo, 0, i); + return foo; + } + internal byte[] getString(int[]start, int[]len) + { + int i=getInt(); + start[0]=getByte(i); + len[0]=i; + return buffer; + } + public void reset() + { + index=0; + s=0; + } + public void shift() + { + if(s==0)return; + Array.Copy(buffer, s, buffer, 0, index-s); + index=index-s; + s=0; + } + internal void rewind() + { + s=0; + } + + /* + static String[] chars={ + "0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f" + }; + static void dump_buffer(){ + int foo; + for(int i=0; i>>4)&0xf]); + System.out.print(chars[foo&0xf]); + if(i%16==15){ + System.out.println(""); + continue; + } + if(i>0 && i%2==1){ + System.out.print(" "); + } + } + System.out.println(""); + } + static void dump(byte[] b){ + dump(b, 0, b.length); + } + static void dump(byte[] b, int s, int l){ + for(int i=s; i0) + { + try{Thread.sleep(50);} + catch(Exception ee){} + retry--; + } + if(!session.isConnected()) + { + throw new JSchException("session is down"); + } + if(retry==0) + { + throw new JSchException("channel is not opened."); + } + connected=true; + start(); + } + catch(Exception e) + { + connected=false; + if(e is JSchException) throw (JSchException)e; + } + } + + public virtual void setXForwarding(bool foo) + { + } + + public virtual void start(){} + + public bool isEOF() {return _eof_remote;} + + internal virtual void getData(Buffer buf) + { + setRecipient(buf.getInt()); + setRemoteWindowSize(buf.getInt()); + setRemotePacketSize(buf.getInt()); + } + + public virtual void setInputStream(Stream In) + { + io.setInputStream(In, false); + } + public virtual void setInputStream(Stream In, bool dontclose) + { + io.setInputStream(In, dontclose); + } + public virtual void setOutputStream(Stream Out) + { + io.setOutputStream(Out, false); + } + public virtual void setOutputStream(Stream Out, bool dontclose) + { + io.setOutputStream(Out, dontclose); + } + public virtual void setExtOutputStream(Stream Out) + { + io.setExtOutputStream(Out, false); + } + public virtual void setExtOutputStream(Stream Out, bool dontclose) + { + io.setExtOutputStream(Out, dontclose); + } + public virtual java.io.InputStream getInputStream() + { + PipedInputStream In= + new MyPipedInputStream( + 32*1024 // this value should be customizable. + ); + io.setOutputStream(new PassiveOutputStream(In), false); + return In; + } + public virtual java.io.InputStream getExtInputStream() + { + PipedInputStream In= + new MyPipedInputStream( + 32*1024 // this value should be customizable. + ); + io.setExtOutputStream(new PassiveOutputStream(In), false); + return In; + } + public virtual Stream getOutputStream() + { + PipedOutputStream Out=new PipedOutputStream(); + io.setInputStream(new PassiveInputStream(Out + , 32*1024 + ), false); + // io.setInputStream(new PassiveInputStream(Out), false); + return Out; + } + internal class MyPipedInputStream : PipedInputStream + { + internal MyPipedInputStream():base() { ; } + internal MyPipedInputStream(int size) :base() + { + buffer=new byte[size]; + } + internal MyPipedInputStream(PipedOutputStream Out):base(Out) { } + internal MyPipedInputStream(PipedOutputStream Out, int size):base(Out) + { + buffer=new byte[size]; + } + } + internal virtual void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; } + internal virtual void setLocalWindowSize(int foo){ this.lwsize=foo; } + internal virtual void setLocalPacketSize(int foo){ this.lmpsize=foo; } + [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.Synchronized)] + internal virtual void setRemoteWindowSize(int foo){ this.rwsize=foo; } + [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.Synchronized)] + internal virtual void addRemoteWindowSize(int foo){ this.rwsize+=foo; } + internal virtual void setRemotePacketSize(int foo){ this.rmpsize=foo; } + + public virtual void run() + { + } + + internal virtual void write(byte[] foo) + { + write(foo, 0, foo.Length); + } + internal virtual void write(byte[] foo, int s, int l) + { + try + { + // if(io.outs!=null) + io.put(foo, s, l); + } + catch(NullReferenceException e){} + } + internal virtual void write_ext(byte[] foo, int s, int l) + { + try + { + // if(io.out_ext!=null) + io.put_ext(foo, s, l); + } + catch(NullReferenceException e){} + } + + internal virtual void eof_remote() + { + _eof_remote=true; + try + { + if(io.outs!=null) + { + io.outs.Close(); + io.outs=null; + } + } + catch(NullReferenceException e){} + catch(IOException e){} + } + + internal virtual void eof() + { + //System.Out.println("EOF!!!! "+this); + //Thread.dumpStack(); + if(_close)return; + if(eof_local)return; + eof_local=true; + //close=eof; + try + { + Buffer buf=new Buffer(100); + Packet packet=new Packet(buf); + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF); + buf.putInt(getRecipient()); + session.write(packet); + } + catch(Exception e) + { + //System.Out.println("Channel.eof"); + //e.printStackTrace(); + } + /* + if(!isConnected()){ disconnect(); } + */ + } + + /* + http://www1.ietf.org/internet-drafts/draft-ietf-secsh-connect-24.txt + + 5.3 Closing a Channel + When a party will no longer send more data to a channel, it SHOULD + send SSH_MSG_CHANNEL_EOF. + + byte SSH_MSG_CHANNEL_EOF + uint32 recipient_channel + + No explicit response is sent to this message. However, the + application may send EOF to whatever is at the other end of the + channel. Note that the channel remains open after this message, and + more data may still be sent In the other direction. This message + does not consume window space and can be sent even if no window space + is available. + + When either party wishes to terminate the channel, it sends + SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST + send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this + message for the channel. The channel is considered closed for a + party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and + the party may then reuse the channel number. A party MAY send + SSH_MSG_CHANNEL_CLOSE without having sent or received + SSH_MSG_CHANNEL_EOF. + + byte SSH_MSG_CHANNEL_CLOSE + uint32 recipient_channel + + This message does not consume window space and can be sent even if no + window space is available. + + It is recommended that any data sent before this message is delivered + to the actual destination, if possible. + */ + + internal virtual void close() + { + //System.Out.println("close!!!!"); + if(_close)return; + _close=true; + try + { + Buffer buf=new Buffer(100); + Packet packet=new Packet(buf); + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE); + buf.putInt(getRecipient()); + session.write(packet); + } + catch(Exception e) + { + //e.printStackTrace(); + } + } + public virtual bool isClosed() + { + return _close; + } + internal static void disconnect(Session session) + { + Channel[] channels=null; + int count=0; + lock(pool) + { + channels=new Channel[pool.size()]; + for(int i=0; i0) +// { +// try{System.Threading.Thread.Sleep(50);} +// catch{} +// retry--; +// } +// if(!session.IsConnected()) +// { +// throw new JSchException("session is down"); +// } +// if(retry==0) +// { +// throw new JSchException("channel is not opened."); +// } +// start(); +// } +// catch(Exception e) +// { +// if(e is JSchException) throw (JSchException)e; +// } +// } +// +// public virtual void setXForwarding(bool foo) +// { +// } +// +// public virtual void start() {} +// +// public bool isEOF() {return eof_remote;} +// +// internal virtual void getData(Buffer buf) +// { +// setRecipient(buf.getInt()); +// setRemoteWindowSize(buf.getInt()); +// setRemotePacketSize(buf.getInt()); +// } +// +// public RequestWindowChange getRequestWindowChange() +// { +// return new RequestWindowChange(); +// } +// +// public virtual void setInputStream(Stream ins) +// { +// io.setInputStream(ins); +// } +// public virtual void setOutputStream(Stream outs) +// { +// io.setOutputStream(outs); +// } +// public virtual void setExtOutputStream(Stream outs) +// { +// io.setExtOutputStream(outs); +// } +// public virtual Stream getInputStream() +// { +// PipedInputStream ins= +// new MyPipedInputStream( +// 32*1024 // this value should be customizable. +// ); +// io.setOutputStream(new PassiveOutputStream(ins)); +// return ins; +// } +// public virtual Stream getExtInputStream() +// { +// PipedInputStream ins= +// new MyPipedInputStream( +// 32*1024 // this value should be customizable. +// ); +// io.setExtOutputStream(new PassiveOutputStream(ins)); +// return ins; +// } +// public virtual Stream getOutputStream() +// { +// PipedOutputStream outs=new PipedOutputStream(); +// io.setInputStream(new PassiveInputStream(outs)); +// return outs; +// } +// +// internal void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; } +// internal void setLocalWindowSize(int foo){ this.lwsize=foo; } +// internal void setLocalPacketSize(int foo){ this.lmpsize=foo; } +// internal void setRemoteWindowSize(int foo){ this.rwsize=foo; } +// internal void addRemoteWindowSize(int foo){ this.rwsize+=foo; } +// internal void setRemotePacketSize(int foo){ this.rmpsize=foo; } +// +// public virtual void run() +// { +// } +// +// internal virtual void write(byte[] foo) +// { +// write(foo, 0, foo.Length); +// } +// internal virtual void write(byte[] foo, int s, int l) +// { +// //if(eof_remote)return; +// if(io.outs!=null) +// io.put(foo, s, l); +// } +// internal void write_ext(byte[] foo, int s, int l) +// { +// //if(eof_remote)return; +// if(io.out_ext!=null) +// io.put_ext(foo, s, l); +// } +// +// internal void eof() +// { +// //System.out.println("EOF!!!! "+this); +// //Thread.dumpStack(); +// if(eof_local)return; +// eof_local=true; +// //close=eof; +// try +// { +// Buffer buf=new Buffer(100); +// Packet packet=new Packet(buf); +// packet.reset(); +// buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF); +// buf.putInt(getRecipient()); +// session.write(packet); +// } +// catch +// { +// //System.out.println("Channel.eof"); +// //e.printStackTrace(); +// } +// if(!isConnected()) +// { +// disconnect(); +// } +// } +// +// internal void close() +// { +// //System.out.println("close!!!!"); +// if(_close)return; +// _close=true; +// try +// { +// Buffer buf=new Buffer(100); +// Packet packet=new Packet(buf); +// packet.reset(); +// buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE); +// buf.putInt(getRecipient()); +// session.write(packet); +// session.disconnect(); +// } +// catch +// { +// //e.printStackTrace(); +// } +// } +// internal static void eof(Session session) +// { +// Channel[] channels=null; +// int count=0; +// lock(pool) +// { +// channels=new Channel[pool.Count]; +// for(int i=0; i0 && + !_eof_remote) + { + //Thread.sleep(500); + Thread.Sleep(50); + retry--; + } + } + catch + { + } + + if(!session.isConnected()) + { + throw new JSchException("session is down"); + } + if(retry==0 || this._eof_remote) + { + throw new JSchException("channel is not opened."); + } + /* + if(this.eof_remote){ // failed to open + disconnect(); + return; + } + */ + + connected=true; + + thread=new Thread(this); + thread.start(); + } + catch(Exception e) + { + io.close(); + io=null; + Channel.del(this); + if (e is JSchException) + { + throw (JSchException) e; + } + } + } + + public override void run() + { + // thread=Thread.currentThread(); + //System.out.println("rmpsize: "+rmpsize+", lmpsize: "+lmpsize); + Buffer buf=new Buffer(rmpsize); + // Buffer buf=new Buffer(lmpsize); + Packet packet=new Packet(buf); + int i=0; + try + { + while(isConnected() && + thread!=null && + io!=null && + io.ins!=null) + { + i=io.ins.Read(buf.buffer, + 14, + buf.buffer.Length-14 + -32 -20 // padding and mac + ); + if(i<=0) + { + eof(); + break; + } + if(_close)break; + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); + buf.putInt(recipient); + buf.putInt(i); + buf.skip(i); + session.write(packet, this, i); + } + } + catch + { + } + disconnect(); + //System.out.println("connect end"); + + /* + try{ + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF); + buf.putInt(recipient); + session.write(packet); + } + catch(Exception e){ + } + */ + // close(); + } + + public override void setInputStream(Stream ins) + { + io.setInputStream(ins); + } + public override void setOutputStream(Stream outs) + { + io.setOutputStream(outs); + } + + public void setHost(String host){this.host=host;} + public void setPort(int port){this.port=port;} + public void setOrgIPAddress(String foo){this.originator_IP_address=foo;} + public void setOrgPort(int foo){this.originator_port=foo;} + } + +} diff --git a/SharpSSH/jsch/ChannelExec.cs b/SharpSSH/jsch/ChannelExec.cs new file mode 100644 index 00000000..b6064e81 --- /dev/null +++ b/SharpSSH/jsch/ChannelExec.cs @@ -0,0 +1,98 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.IO; +using Tamir.SharpSsh.java.lang; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use ins source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions ins binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer ins + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class ChannelExec : ChannelSession + { + bool xforwading=false; + bool pty=false; + String command=""; + /* + ChannelExec(){ + super(); + type="session".getBytes(); + io=new IO(); + } + */ + public override void setXForwarding(bool foo){ xforwading=foo; } + public void setPty(bool foo){ pty=foo; } + public override void start() + { + try + { + Request request; + + if(xforwading) + { + request=new RequestX11(); + request.request(session, this); + } + + if(pty) + { + request=new RequestPtyReq(); + request.request(session, this); + } + + request=new RequestExec(command); + request.request(session, this); + } + catch(Exception e) + { + throw new JSchException("ChannelExec"); + } + thread=new Thread(this); + thread.setName("Exec thread "+session.getHost()); + thread.start(); + } + public void setCommand(String foo){ command=foo;} + public override void init() + { + io.setInputStream(session.In); + io.setOutputStream(session.Out); + } + //public void finalize() throws java.lang.Throwable{ super.finalize(); } + public void setErrStream(Stream Out) + { + setExtOutputStream(Out); + } + public Stream getErrStream() + { + return getExtInputStream(); + } + } + +} diff --git a/SharpSSH/jsch/ChannelForwardedTCPIP.cs b/SharpSSH/jsch/ChannelForwardedTCPIP.cs new file mode 100644 index 00000000..aefc28fa --- /dev/null +++ b/SharpSSH/jsch/ChannelForwardedTCPIP.cs @@ -0,0 +1,310 @@ +using System; +using System.IO; +using Tamir.SharpSsh.java.util; +using Tamir.SharpSsh.java.net; +using Tamir.SharpSsh.java.lang; +using Str = Tamir.SharpSsh.java.String; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class ChannelForwardedTCPIP : Channel + { + + internal static java.util.Vector pool=new java.util.Vector(); + + // static private final int LOCAL_WINDOW_SIZE_MAX=0x20000; + static private int LOCAL_WINDOW_SIZE_MAX=0x100000; + static private int LOCAL_MAXIMUM_PACKET_SIZE=0x4000; + + internal SocketFactory factory=null; + internal String target; + internal int lport; + internal int rport; + + internal ChannelForwardedTCPIP() : base() + { + setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX); + setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX); + setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE); + } + + public override void init () + { + try + { + io=new IO(); + if(lport==-1) + { + Class c=Class.forName(target); + ForwardedTCPIPDaemon daemon=(ForwardedTCPIPDaemon)c.newInstance(); + daemon.setChannel(this); + Object[] foo=getPort(session, rport); + daemon.setArg((Object[])foo[3]); + new Thread(daemon).start(); + connected=true; + return; + } + else + { + Socket socket=(factory==null) ? + new Socket(target, lport) : + factory.createSocket(target, lport); + socket.setTcpNoDelay(true); + io.setInputStream(socket.getInputStream()); + io.setOutputStream(socket.getOutputStream()); + connected=true; + } + } + catch(Exception e) + { + Console.WriteLine("target={0},port={1}",target,lport); + Console.WriteLine(e); + } + } + + public override void run() + { + thread=Thread.currentThread(); + Buffer buf=new Buffer(rmpsize); + Packet packet=new Packet(buf); + int i=0; + try + { + while(thread!=null && io!=null && io.ins!=null) + { + i=io.ins.Read(buf.buffer, + 14, + buf.buffer.Length-14 + -32 -20 // padding and mac + ); + if(i<=0) + { + eof(); + break; + } + packet.reset(); + if(_close)break; + buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); + buf.putInt(recipient); + buf.putInt(i); + buf.skip(i); + session.write(packet, this, i); + } + } + catch(Exception e) + { + //System.out.println(e); + } + + //thread=null; + //eof(); + disconnect(); + } + internal override void getData(Buffer buf) + { + setRecipient(buf.getInt()); + setRemoteWindowSize(buf.getInt()); + setRemotePacketSize(buf.getInt()); + byte[] addr=buf.getString(); + int port=buf.getInt(); + byte[] orgaddr=buf.getString(); + int orgport=buf.getInt(); + + /* + System.out.println("addr: "+new String(addr)); + System.out.println("port: "+port); + System.out.println("orgaddr: "+new String(orgaddr)); + System.out.println("orgport: "+orgport); + */ + + lock(pool) + { + for(int i=0; i=5) + { + this.factory=((SocketFactory)foo[4]); + } + break; + } + if(target==null) + { + Console.WriteLine("??"); + } + } + } + + internal static Object[] getPort(Session session, int rport) + { + lock(pool) + { + for(int i=0; i"); + /* + if(thread!=null){ return; } + thread=Thread.currentThread(); + */ + + // Buffer buf=new Buffer(); + Buffer buf=new Buffer(rmpsize); + Packet packet=new Packet(buf); + int i=-1; + try + { + while(isConnected() && + thread!=null && + io!=null && + io.ins!=null) + { + i=io.ins.Read(buf.buffer, + 14, + buf.buffer.Length-14 + -32 -20 // padding and mac + ); + if(i==0)continue; + if(i==-1) + { + eof(); + break; + } + if(_close)break; + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); + buf.putInt(recipient); + buf.putInt(i); + buf.skip(i); + session.write(packet, this, i); + } + } + catch(Exception e) + { + Console.WriteLine("# ChannelSession.run"); + Console.WriteLine(e); + } + if(thread!=null) + { + //lock(thread){ System.Threading.Monitor.PulseAll(this);/*thread.notifyAll();*/ } + } + thread=null; + //System.out.println(this+":run <"); + } + } +} diff --git a/SharpSSH/jsch/ChannelSftp.cs b/SharpSSH/jsch/ChannelSftp.cs new file mode 100644 index 00000000..869e5e48 --- /dev/null +++ b/SharpSSH/jsch/ChannelSftp.cs @@ -0,0 +1,2651 @@ +//using System; +using System.Runtime.CompilerServices; +using Tamir.Streams; +using Tamir.SharpSsh.java.io; +using Tamir.SharpSsh.java.lang; +using Tamir.SharpSsh.java.util; +using Tamir.SharpSsh.java; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ + /* + Copyright (c) 2002,2003,2004,2005,2006 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /// + /// Based on JSch-0.1.30 + /// + public class ChannelSftp : ChannelSession + { + private static byte SSH_FXP_INIT= 1; + private static byte SSH_FXP_VERSION= 2; + private static byte SSH_FXP_OPEN= 3; + private static byte SSH_FXP_CLOSE= 4; + private static byte SSH_FXP_READ= 5; + private static byte SSH_FXP_WRITE= 6; + private static byte SSH_FXP_LSTAT= 7; + private static byte SSH_FXP_FSTAT= 8; + private static byte SSH_FXP_SETSTAT= 9; + private static byte SSH_FXP_FSETSTAT= 10; + private static byte SSH_FXP_OPENDIR= 11; + private static byte SSH_FXP_READDIR= 12; + private static byte SSH_FXP_REMOVE= 13; + private static byte SSH_FXP_MKDIR= 14; + private static byte SSH_FXP_RMDIR= 15; + private static byte SSH_FXP_REALPATH= 16; + private static byte SSH_FXP_STAT= 17; + private static byte SSH_FXP_RENAME= 18; + private static byte SSH_FXP_READLINK= 19; + private static byte SSH_FXP_SYMLINK= 20; + private static byte SSH_FXP_STATUS= 101; + private static byte SSH_FXP_HANDLE= 102; + private static byte SSH_FXP_DATA= 103; + private static byte SSH_FXP_NAME= 104; + private static byte SSH_FXP_ATTRS= 105; + private static byte SSH_FXP_EXTENDED= (byte)200; + private static byte SSH_FXP_EXTENDED_REPLY= (byte)201; + + // pflags + private static int SSH_FXF_READ= 0x00000001; + private static int SSH_FXF_WRITE= 0x00000002; + private static int SSH_FXF_APPEND= 0x00000004; + private static int SSH_FXF_CREAT= 0x00000008; + private static int SSH_FXF_TRUNC= 0x00000010; + private static int SSH_FXF_EXCL= 0x00000020; + + private static int SSH_FILEXFER_ATTR_SIZE= 0x00000001; + private static int SSH_FILEXFER_ATTR_UIDGID= 0x00000002; + private static int SSH_FILEXFER_ATTR_PERMISSIONS= 0x00000004; + private static int SSH_FILEXFER_ATTR_ACMODTIME= 0x00000008; + private static uint SSH_FILEXFER_ATTR_EXTENDED= 0x80000000; + + public static int SSH_FX_OK= 0; + public static int SSH_FX_EOF= 1; + public static int SSH_FX_NO_SUCH_FILE= 2; + public static int SSH_FX_PERMISSION_DENIED= 3; + public static int SSH_FX_FAILURE= 4; + public static int SSH_FX_BAD_MESSAGE= 5; + public static int SSH_FX_NO_CONNECTION= 6; + public static int SSH_FX_CONNECTION_LOST= 7; + public static int SSH_FX_OP_UNSUPPORTED= 8; + /* + SSH_FX_OK + Indicates successful completion of the operation. + SSH_FX_EOF + indicates end-of-file condition; for SSH_FX_READ it means that no + more data is available in the file, and for SSH_FX_READDIR it + indicates that no more files are contained in the directory. + SSH_FX_NO_SUCH_FILE + is returned when a reference is made to a file which should exist + but doesn't. + SSH_FX_PERMISSION_DENIED + is returned when the authenticated user does not have sufficient + permissions to perform the operation. + SSH_FX_FAILURE + is a generic catch-all error message; it should be returned if an + error occurs for which there is no more specific error code + defined. + SSH_FX_BAD_MESSAGE + may be returned if a badly formatted packet or protocol + incompatibility is detected. + SSH_FX_NO_CONNECTION + is a pseudo-error which indicates that the client has no + connection to the server (it can only be generated locally by the + client, and MUST NOT be returned by servers). + SSH_FX_CONNECTION_LOST + is a pseudo-error which indicates that the connection to the + server has been lost (it can only be generated locally by the + client, and MUST NOT be returned by servers). + SSH_FX_OP_UNSUPPORTED + indicates that an attempt was made to perform an operation which + is not supported for the server (it may be generated locally by + the client if e.g. the version number exchange indicates that a + required feature is not supported by the server, or it may be + returned by the server if the server does not implement an + operation). + */ + private static int MAX_MSG_LENGTH = 256* 1024; + + public static int OVERWRITE=0; + public static int RESUME=1; + public static int APPEND=2; + + // private bool interactive=true; + private bool interactive=false; + internal int seq=1; + private int[] ackid=new int[1]; + private Buffer buf; + private Packet packet;//=new Packet(buf); + + private String _version="3"; + private int server_version=3; + /* + 10. Changes from previous protocol versions + The SSH File Transfer Protocol has changed over time, before it's + standardization. The following is a description of the incompatible + changes between different versions. + 10.1 Changes between versions 3 and 2 + o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. + o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were added. + o The SSH_FXP_STATUS message was changed to include fields `error + message' and `language tag'. + 10.2 Changes between versions 2 and 1 + o The SSH_FXP_RENAME message was added. + 10.3 Changes between versions 1 and 0 + o Implementation changes, no actual protocol changes. + */ + + private static String file_separator=java.io.File.separator; + private static char file_separatorc=java.io.File.separatorChar; + + private String cwd; + private String home; + private String lcwd; + + internal ChannelSftp(){packet=new Packet(buf);} + + public override void init() + { + /* + io.setInputStream(session.in); + io.setOutputStream(session.out); + */ + } + + public override void start() + { //throws JSchException{ + try + { + + PipedOutputStream pos=new PipedOutputStream(); + io.setOutputStream(pos); + PipedInputStream pis=new MyPipedInputStream(pos, 32*1024); + io.setInputStream(pis); + + Request request=new RequestSftp(); + request.request(session, this); + + /* + System.err.println("lmpsize: "+lmpsize); + System.err.println("lwsize: "+lwsize); + System.err.println("rmpsize: "+rmpsize); + System.err.println("rwsize: "+rwsize); + */ + + buf=new Buffer(rmpsize); + packet=new Packet(buf); + int i=0; + int length; + int type; + byte[] str; + + // send SSH_FXP_INIT + sendINIT(); + + // receive SSH_FXP_VERSION + Header _header=new Header(); + _header=header(buf, _header); + length=_header.length; + if(length > MAX_MSG_LENGTH) + { + throw new SftpException(SSH_FX_FAILURE, "Received message is too long: " + length); + } + type=_header.type; // 2 -> SSH_FXP_VERSION + server_version=_header.rid; + skip(length); + //System.err.println("SFTP protocol server-version="+server_version); + //System.Console.WriteLine("server_version="+server_version+", type="+type+", length="+length+", i="+i); + + // send SSH_FXP_REALPATH + sendREALPATH(new String(".").getBytes()); + + // receive SSH_FXP_NAME + _header=header(buf, _header); + length=_header.length; + type=_header.type; // 104 -> SSH_FXP_NAME + buf.rewind(); + fill(buf.buffer, 0, length); + i=buf.getInt(); // count + //System.Console.WriteLine("type="+type+", length="+length+", i="+i); + str=buf.getString(); // filename + //System.Console.WriteLine("str.length="+str.Length); + home=cwd=new String(str); + str=buf.getString(); // logname + // SftpATTRS.getATTR(buf); // attrs + + lcwd=new File(".").getCanonicalPath(); + } + catch(Exception e) + { + //System.out.println(e); + //System.Console.WriteLine(e); + if(e is JSchException) throw (JSchException)e; + throw new JSchException(e.toString()); + } + } + + public void quit(){ disconnect();} + public void exit(){ disconnect();} + public void lcd(String path) + { //throws SftpException{ + path=localAbsolutePath(path); + if((new File(path)).isDirectory()) + { + try + { + path=(new File(path)).getCanonicalPath(); + } + catch(Exception e){} + lcwd=path; + return; + } + throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory"); + } + + /* + cd /tmp + c->s REALPATH + s->c NAME + c->s STAT + s->c ATTR + */ + public void cd(String path) + { + //throws SftpException{ + try + { + path=remoteAbsolutePath(path); + + Vector v=glob_remote(path); + if(v.size()!=1) + { + throw new SftpException(SSH_FX_FAILURE, v.toString()); + } + path=(String)(v.elementAt(0)); + sendREALPATH(path.getBytes()); + + Header _header=new Header(); + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + buf.rewind(); + fill(buf.buffer, 0, length); + + if(type!=101 && type!=104) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + int i; + if(type==101) + { + i=buf.getInt(); + throwStatusError(buf, i); + } + i=buf.getInt(); + byte[] str=buf.getString(); + if(str!=null && str[0]!='/') + { + str=(cwd+"/"+new String(str)).getBytes(); + } + str=buf.getString(); // logname + i=buf.getInt(); // attrs + + String newpwd=new String(str); + SftpATTRS attr=_stat(newpwd); + if((attr.getFlags()&SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS)==0) + { + throw new SftpException(SSH_FX_FAILURE, + "Can't change directory: "+path); + } + if(!attr.isDir()) + { + throw new SftpException(SSH_FX_FAILURE, + "Can't change directory: "+path); + } + cwd=newpwd; + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + + /* + put foo + c->s OPEN + s->c HANDLE + c->s WRITE + s->c STATUS + c->s CLOSE + s->c STATUS + */ + public void put(String src, String dst) + { //throws SftpException{ + put(src, dst, null, OVERWRITE); + } + public void put(String src, String dst, int mode) + { //throws SftpException{ + put(src, dst, null, mode); + } + public void put(String src, String dst, + SftpProgressMonitor monitor) + { //throws SftpException{ + put(src, dst, monitor, OVERWRITE); + } + public void put(String src, String dst, + SftpProgressMonitor monitor, int mode) + { + //throws SftpException{ + src=localAbsolutePath(src); + dst=remoteAbsolutePath(dst); + + //System.err.println("src: "+src+", "+dst); + try + { + Vector v=glob_remote(dst); + int vsize=v.size(); + if(vsize!=1) + { + if(vsize==0) + { + if(isPattern(dst)) + throw new SftpException(SSH_FX_FAILURE, dst); + else + dst=Util.unquote(dst); + } + throw new SftpException(SSH_FX_FAILURE, v.toString()); + } + else + { + dst=(String)(v.elementAt(0)); + } + + //System.err.println("dst: "+dst); + + bool _isRemoteDir=isRemoteDir(dst); + + v=glob_local(src); + //System.err.println("glob_local: "+v+" dst="+dst); + vsize=v.size(); + + StringBuffer dstsb=null; + if(_isRemoteDir) + { + if(!dst.endsWith("/")) + { + dst+="/"; + } + dstsb=new StringBuffer(dst); + } + else if(vsize>1) + { + throw new SftpException(SSH_FX_FAILURE, "Copying multiple files, but destination is missing or a file."); + } + + for(int j=0; j0) + { + long skipped=src.skip(skip); + if(skipped0){ + // _len-=sendWRITE(handle, _offset[0], d, s, _len); + + // if((count-1)==startid || + // io.ins.available()>=1024){ + // while(io.ins.available()>0){ + // if(checkStatus(ackid)){ + // _ackid=ackid[0]; + // if(startid>_ackid || _ackid>count-1){ + // throw new SftpException(SSH_FX_FAILURE, ""); + // } + // ackcount++; + // } + // else{ + // break; + // } + // } + // } + + // } + // _offset[0]+=len; + // if(monitor!=null && !monitor.count(len)){ + // throw new IOException("canceled"); + // } + // } + // catch(IOException e){ throw e; } + // catch(Exception e){ throw new IOException(e.toString()); } + // } + // byte[] _data=new byte[1]; + // public void write(int foo) { //throws java.io.IOException{ + // _data[0]=(byte)foo; + // write(_data, 0, 1); + // } + // public void close() { //throws java.io.IOException{ + + // try{ + // int _ackcount=count-startid; + // while(_ackcount>ackcount){ + // if(!checkStatus(null)){ + // break; + // } + // ackcount++; + // } + // } + // catch(SftpException e){ + // throw new IOException(e.toString()); + // } + + // if(monitor!=null)monitor.end(); + // try{ _sendCLOSE(handle); } + // catch(IOException e){ throw e; } + // catch(Exception e){ + // throw new IOException(e.toString()); + // } + // } + //}; + return outs; + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + + /**/ + public void get(String src, String dst) + { //throws SftpException{ + get(src, dst, null, OVERWRITE); + } + public void get(String src, String dst, + SftpProgressMonitor monitor) + { //throws SftpException{ + get(src, dst, monitor, OVERWRITE); + } + public void get(String src, String dst, + SftpProgressMonitor monitor, int mode) + { + //throws SftpException{ + src=remoteAbsolutePath(src); + dst=localAbsolutePath(dst); + try + { + Vector v=glob_remote(src); + int vsize=v.size(); + if(vsize==0) + { + throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such file"); + } + + File dstFile=new File(dst); + bool isDstDir=dstFile.isDirectory(); + StringBuffer dstsb=null; + if(isDstDir) + { + if(!dst.endsWith(file_separator)) + { + dst+=file_separator; + } + dstsb=new StringBuffer(dst); + } + else if(vsize>1) + { + throw new SftpException(SSH_FX_FAILURE, "Copying multiple files, but destination is missing or a file."); + } + + for(int j=0; jsize_of_src) + { + throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+_dst); + } + if(size_of_dst==size_of_src) + { + return; + } + } + + if(monitor!=null) + { + monitor.init(SftpProgressMonitor.GET, _src, _dst, attr.getSize()); + if(mode==RESUME) + { + monitor.count(new File(_dst).length()); + } + } + FileOutputStream fos=null; + if(mode==OVERWRITE) + { + fos=new FileOutputStream(_dst); + } + else + { + fos=new FileOutputStream(_dst, true); // append + } + + //System.err.println("_get: "+_src+", "+_dst); + _get(_src, fos, monitor, mode, new File(_dst).length()); + fos.close(); + } + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + public void get(String src, OutputStream dst) + { //throws SftpException{ + get(src, dst, null, OVERWRITE, 0); + } + public void get(String src, OutputStream dst, + SftpProgressMonitor monitor) + { //throws SftpException{ + get(src, dst, monitor, OVERWRITE, 0); + } + public void get(String src, OutputStream dst, + SftpProgressMonitor monitor, int mode, long skip) + { + //throws SftpException{ + try + { + src=remoteAbsolutePath(src); + Vector v=glob_remote(src); + if(v.size()!=1) + { + throw new SftpException(SSH_FX_FAILURE, v.toString()); + } + src=(String)(v.elementAt(0)); + + if(monitor!=null) + { + SftpATTRS attr=_stat(src); + monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize()); + if(mode==RESUME) + { + monitor.count(skip); + } + } + _get(src, dst, monitor, mode, skip); + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + + ///tamir: updated to jcsh-0.1.30 + private void _get(String src, OutputStream dst, + SftpProgressMonitor monitor, int mode, long skip) + { //throws SftpException{ + //System.out.println("_get: "+src+", "+dst); + try + { + sendOPENR(src.getBytes()); + + + Header _header=new Header(); + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + + buf.rewind(); + + fill(buf.buffer, 0, length); + + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE) + { + //System.Console.WriteLine("Type is "+type); + throw new SftpException(SSH_FX_FAILURE, "Type is "+type); + } + + if(type==SSH_FXP_STATUS) + { + int i=buf.getInt(); + throwStatusError(buf, i); + } + + byte[] handle=buf.getString(); // filename + + long offset=0; + if(mode==RESUME) + { + offset+=skip; + } + + int request_len=0; + loop: + while(true) + { + + request_len=buf.buffer.Length-13; + if(server_version==0){ request_len=1024; } + sendREAD(handle, offset, request_len); + + _header=header(buf, _header); + length=_header.length; + type=_header.type; + + int i; + if(type==SSH_FXP_STATUS) + { + buf.rewind(); + fill(buf.buffer, 0, length); + i=buf.getInt(); + if(i==SSH_FX_EOF) + { + goto BREAK; + } + throwStatusError(buf, i); + } + + if(type!=SSH_FXP_DATA) + { + goto BREAK; + } + + buf.rewind(); + fill(buf.buffer, 0, 4); length-=4; + i=buf.getInt(); // length of data + int foo=i; + while(foo>0) + { + int bar=foo; + if(bar>buf.buffer.Length) + { + bar=buf.buffer.Length; + } + i=io.ins.read(buf.buffer, 0, bar); + if(i<0) + { + goto BREAK; + } + int data_len=i; + dst.write(buf.buffer, 0, data_len); + + offset+=data_len; + foo-=data_len; + + if(monitor!=null) + { + if(!monitor.count(data_len)) + { + while(foo>0) + { + i=io.ins.read(buf.buffer, + 0, + (buf.buffer.Lengthd.Length){ + // throw new IndexOutOfBoundsException(); + // } + // if(len==0){ return 0; } + + // if(rest_length>0){ + // int foo=rest_length; + // if(foo>len) foo=len; + // int i=io.ins.read(d, s, foo); + // if(i<0){ + // throw new IOException("error"); + // } + // rest_length-=i; + // return i; + // } + + // if(buf.buffer.Length-131024){ + // len=1024; + // } + + // try{sendREAD(handle, offset, len);} + // catch(Exception e){ throw new IOException("error"); } + + // buf.rewind(); + // int i=io.ins.read(buf.buffer, 0, 13); // 4 + 1 + 4 + 4 + // if(i!=13){ + // throw new IOException("error"); + // } + + // rest_length=buf.getInt(); + // int type=buf.getByte(); + // rest_length--; + // buf.getInt(); + // rest_length-=4; + // if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){ + // throw new IOException("error"); + // } + // if(type==SSH_FXP_STATUS){ + // i=buf.getInt(); + // rest_length-=4; + // io.ins.read(buf.buffer, 13, rest_length); + // rest_length=0; + // if(i==SSH_FX_EOF){ + // close(); + // return -1; + // } + // //throwStatusError(buf, i); + // throw new IOException("error"); + // } + + // i=buf.getInt(); + // rest_length-=4; + // offset+=rest_length; + // int foo=i; + // if(foo>0){ + // int bar=rest_length; + // if(bar>len){ + // bar=len; + // } + // i=io.ins.read(d, s, bar); + // if(i<0){ + // return -1; + // } + // rest_length-=i; + + // if(monitor!=null){ + // if(!monitor.count(i)){ + // return -1; + // } + // } + // return i; + // } + // return 0; // ?? + // } + // public void close() { //throws IOException{ + // if(closed)return; + // closed=true; + // /* + // while(rest_length>0){ + // int foo=rest_length; + // if(foo>buf.buffer.Length){ + // foo=buf.buffer.Length; + // } + // io.ins.read(buf.buffer, 0, foo); + // rest_length-=foo; + // } + // */ + // if(monitor!=null)monitor.end(); + // try{_sendCLOSE(handle);} + // catch(Exception e){throw new IOException("error");} + // } + //}; + return ins; + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + + public java.util.Vector ls(String path) + { //throws SftpException{ + try + { + path=remoteAbsolutePath(path); + + String dir=path; + byte[] pattern=null; + SftpATTRS attr=null; + if(isPattern(dir) || + ((attr=stat(dir))!=null && !attr.isDir())) + { + int foo=path.lastIndexOf('/'); + dir=path.substring(0, ((foo==0)?1:foo)); + pattern=path.substring(foo+1).getBytes(); + } + + sendOPENDIR(dir.getBytes()); + + Header _header=new Header(); + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + buf.rewind(); + fill(buf.buffer, 0, length); + + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + if(type==SSH_FXP_STATUS) + { + int i=buf.getInt(); + throwStatusError(buf, i); + } + + byte[] handle=buf.getString(); // filename + + java.util.Vector v=new java.util.Vector(); + while(true) + { + sendREADDIR(handle); + + _header=header(buf, _header); + length=_header.length; + type=_header.type; + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + if(type==SSH_FXP_STATUS) + { + buf.rewind(); + fill(buf.buffer, 0, length); + int i=buf.getInt(); + if(i==SSH_FX_EOF) + break; + throwStatusError(buf, i); + } + + buf.rewind(); + fill(buf.buffer, 0, 4); length-=4; + int count=buf.getInt(); + + byte[] str; + int flags; + + buf.reset(); + while(count>0) + { + if(length>0) + { + buf.shift(); + int j=(buf.buffer.Length>(buf.index+length)) ? length : (buf.buffer.Length-buf.index); + int i=fill(buf.buffer, buf.index, j); + buf.index+=i; + length-=i; + } + byte[] filename=buf.getString(); + str=buf.getString(); + String longname=new String(str); + + SftpATTRS attrs=SftpATTRS.getATTR(buf); + if(pattern==null || Util.glob(pattern, filename)) + { + v.addElement(new LsEntry(new String(filename), longname, attrs)); + } + + count--; + } + } + _sendCLOSE(handle, _header); + return v; + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + + public String readlink(String path) + { + // throws SftpException{ + try + { + path=remoteAbsolutePath(path); + Vector v=glob_remote(path); + if(v.size()!=1) + { + throw new SftpException(SSH_FX_FAILURE, v.toString()); + } + path=(String)(v.elementAt(0)); + + sendREADLINK(path.getBytes()); + + Header _header=new Header(); + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + buf.rewind(); + fill(buf.buffer, 0, length); + + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + int i; + if(type==SSH_FXP_NAME) + { + int count=buf.getInt(); // count + byte[] filename=null; + byte[] longname=null; + for(i=0; i=2) + { + throw new SftpException(SSH_FX_FAILURE, v.toString()); + } + if(vsize==1) + { + newpath=(String)(v.elementAt(0)); + } + else + { // vsize==0 + if(isPattern(newpath)) + throw new SftpException(SSH_FX_FAILURE, newpath); + newpath=Util.unquote(newpath); + } + + sendRENAME(oldpath.getBytes(), newpath.getBytes()); + + Header _header=new Header(); + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + buf.rewind(); + fill(buf.buffer, 0, length); + + if(type!=SSH_FXP_STATUS) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + + int i=buf.getInt(); + if(i==SSH_FX_OK) return; + throwStatusError(buf, i); + } + catch(Exception e) + { + if(e is SftpException) throw (SftpException)e; + throw new SftpException(SSH_FX_FAILURE, ""); + } + } + public void rm(String path) + { + //throws SftpException{ + try + { + path=remoteAbsolutePath(path); + Vector v=glob_remote(path); + int vsize=v.size(); + Header _header=new Header(); + + for(int j=0; j0) + { + i=io.ins.read(buf, s, l); + if(i<=0) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + s+=i; + l-=i; + } + } + internal bool checkStatus(int[] ackid, Header _header ) + { //throws IOException, SftpException{ + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + if(ackid!=null) + ackid[0]=_header.rid; + buf.rewind(); + fill(buf.buffer, 0, length); + + if(type!=SSH_FXP_STATUS) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + int i=buf.getInt(); + if(i!=SSH_FX_OK) + { + throwStatusError(buf, i); + } + return true; + } + + internal bool _sendCLOSE(byte[] handle, Header header) + //throws Exception + { + sendCLOSE(handle); + return checkStatus(null, header); + } + + private void sendINIT() + { //throws Exception{ + packet.reset(); + putHEAD(SSH_FXP_INIT, 5); + buf.putInt(3); // version 3 + session.write(packet, this, 5+4); + } + + private void sendREALPATH(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_REALPATH, path); + } + private void sendSTAT(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_STAT, path); + } + private void sendLSTAT(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_LSTAT, path); + } + private void sendFSTAT(byte[] handle) + { //throws Exception{ + sendPacketPath(SSH_FXP_FSTAT, handle); + } + private void sendSETSTAT(byte[] path, SftpATTRS attr) + { //throws Exception{ + packet.reset(); + putHEAD(SSH_FXP_SETSTAT, 9+path.Length+attr.Length()); + buf.putInt(seq++); + buf.putString(path); // path + attr.dump(buf); + session.write(packet, this, 9+path.Length+attr.Length()+4); + } + private void sendREMOVE(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_REMOVE, path); + } + private void sendMKDIR(byte[] path, SftpATTRS attr) + { //throws Exception{ + packet.reset(); + putHEAD(SSH_FXP_MKDIR, 9+path.Length+(attr!=null?attr.Length():4)); + buf.putInt(seq++); + buf.putString(path); // path + if(attr!=null) attr.dump(buf); + else buf.putInt(0); + session.write(packet, this, 9+path.Length+(attr!=null?attr.Length():4)+4); + } + private void sendRMDIR(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_RMDIR, path); + } + private void sendSYMLINK(byte[] p1, byte[] p2) + { //throws Exception{ + sendPacketPath(SSH_FXP_SYMLINK, p1, p2); + } + private void sendREADLINK(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_READLINK, path); + } + private void sendOPENDIR(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_OPENDIR, path); + } + private void sendREADDIR(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_READDIR, path); + } + private void sendRENAME(byte[] p1, byte[] p2) + { //throws Exception{ + sendPacketPath(SSH_FXP_RENAME, p1, p2); + } + private void sendCLOSE(byte[] path) + { //throws Exception{ + sendPacketPath(SSH_FXP_CLOSE, path); + } + private void sendOPENR(byte[] path) + { //throws Exception{ + sendOPEN(path, SSH_FXF_READ); + } + private void sendOPENW(byte[] path) + { //throws Exception{ + sendOPEN(path, SSH_FXF_WRITE|SSH_FXF_CREAT|SSH_FXF_TRUNC); + } + private void sendOPENA(byte[] path) + { //throws Exception{ + sendOPEN(path, SSH_FXF_WRITE|/*SSH_FXF_APPEND|*/SSH_FXF_CREAT); + } + private void sendOPEN(byte[] path, int mode) + { //throws Exception{ + packet.reset(); + putHEAD(SSH_FXP_OPEN, 17+path.Length); + buf.putInt(seq++); + buf.putString(path); + buf.putInt(mode); + buf.putInt(0); // attrs + session.write(packet, this, 17+path.Length+4); + } + private void sendPacketPath(byte fxp, byte[] path) + { //throws Exception{ + packet.reset(); + putHEAD(fxp, 9+path.Length); + buf.putInt(seq++); + buf.putString(path); // path + session.write(packet, this, 9+path.Length+4); + } + private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) + { //throws Exception{ + packet.reset(); + putHEAD(fxp, 13+p1.Length+p2.Length); + buf.putInt(seq++); + buf.putString(p1); + buf.putString(p2); + session.write(packet, this, 13+p1.Length+p2.Length+4); + } + + internal int sendWRITE(byte[] handle, long offset, + byte[] data, int start, int length) + { //throws Exception{ + int _length=length; + packet.reset(); + if(buf.buffer.Length=0){if(path[i]=='/')break;i--;} + if(i<0){ v.addElement(Util.unquote(_path)); return v;} + byte[] dir; + if(i==0){dir=new byte[]{(byte)'/'};} + else + { + dir=new byte[i]; + java.System.arraycopy(path, 0, dir, 0, i); + } + //System.err.println("dir: "+new String(dir)); + byte[] pattern=new byte[path.Length-i-1]; + java.System.arraycopy(path, i+1, pattern, 0, pattern.Length); + //System.err.println("file: "+new String(pattern)); + + sendOPENDIR(dir); + + Header _header=new Header(); + _header=header(buf, _header); + int length=_header.length; + int type=_header.type; + buf.rewind(); + fill(buf.buffer, 0, length); + + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + if(type==SSH_FXP_STATUS) + { + i=buf.getInt(); + throwStatusError(buf, i); + } + + byte[] handle=buf.getString(); // filename + + while(true) + { + sendREADDIR(handle); + _header=header(buf, _header); + length=_header.length; + type=_header.type; + + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME) + { + throw new SftpException(SSH_FX_FAILURE, ""); + } + if(type==SSH_FXP_STATUS) + { + buf.rewind(); + fill(buf.buffer, 0, length); + break; + } + + buf.rewind(); + fill(buf.buffer, 0, 4); length-=4; + int count=buf.getInt(); + + byte[] str; + int flags; + + buf.reset(); + while(count>0) + { + if(length>0) + { + buf.shift(); + int j=(buf.buffer.Length>(buf.index+length)) ? length : (buf.buffer.Length-buf.index); + i=io.ins.read(buf.buffer, buf.index, j); + if(i<=0)break; + buf.index+=i; + length-=i; + } + + byte[] filename=buf.getString(); + //System.err.println("filename: "+new String(filename)); + str=buf.getString(); + SftpATTRS attrs=SftpATTRS.getATTR(buf); + + if(Util.glob(pattern, filename)) + { + v.addElement(new String(dir)+"/"+new String(filename)); + } + count--; + } + } + if(_sendCLOSE(handle, _header)) + return v; + return null; + } + + private Vector glob_local(String _path) + { //throws Exception{ + //System.out.println("glob_local: "+_path); + Vector v=new Vector(); + byte[] path=_path.getBytes(); + int i=path.Length-1; + while(i>=0){if(path[i]=='*' || path[i]=='?')break;i--;} + if(i<0){ v.addElement(_path); return v;} + while(i>=0){if(path[i]==file_separatorc)break;i--;} + if(i<0){ v.addElement(_path); return v;} + byte[] dir; + if(i==0){dir=new byte[]{(byte)file_separatorc};} + else + { + dir=new byte[i]; + Tamir.SharpSsh.java.System.arraycopy(path, 0, dir, 0, i); + } + byte[] pattern=new byte[path.Length-i-1]; + Tamir.SharpSsh.java.System.arraycopy(path, i+1, pattern, 0, pattern.Length); + //System.out.println("dir: "+new String(dir)+" pattern: "+new String(pattern)); + try + { + String[] children=(new File(new String(dir))).list(); + for(int j=0; j=3) + { + byte[] str=buf.getString(); + //byte[] tag=buf.getString(); + throw new SftpException(i, new String(str)); + } + else + { + throw new SftpException(i, "Failure"); + } + } + + private static bool isLocalAbsolutePath(String path) + { + return (new File(path)).isAbsolute(); + } + + /* + public void finalize() { //throws Throwable{ + base.finalize(); + } + */ + + public override void disconnect() + { + //waitForRunningThreadFinish(10000); + clearRunningThreads(); + base.disconnect(); + } + private java.util.Vector threadList=null; + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] + protected void addRunningThread(Thread thread) + { + if(threadList==null)threadList=new java.util.Vector(); + threadList.add(thread); + } + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] + protected void clearRunningThreads() + { + if(threadList==null)return; + for(int t=0;t=0) + { + if(path[i]=='*' || path[i]=='?') + { + if(i>0 && path[i-1]=='\\') + { + i--; + } + else + { + break; + } + } + i--; + } + //System.err.println("isPattern: ["+(new String(path))+"] "+(!(i<0))); + return !(i<0); + } + + private int fill(byte[] buf, int s, int len) + { + int i=0; + int foo=s; + while(len>0) + { + i=io.ins.read(buf, s, len); + if(i<=0) + { + throw new System.IO.IOException("inputstream is closed"); + //return (s-foo)==0 ? i : s-foo; + } + s+=i; + len-=i; + } + return s-foo; + } + + //tamir: some functions from jsch-0.1.30 + private void skip(long foo) + { + while(foo>0) + { + long bar=io.ins.skip(foo); + if(bar<=0) + break; + foo-=bar; + } + } + + internal class Header + { + public int length; + public int type; + public int rid; + } + internal Header header(Buffer buf, Header header) + { + buf.rewind(); + int i=fill(buf.buffer, 0, 9); + header.length=buf.getInt()-5; + header.type=buf.getByte()&0xff; + header.rid=buf.getInt(); + return header; + } + + private String remoteAbsolutePath(String path) + { + if(path.charAt(0)=='/') return path; + if(cwd.endsWith("/")) return cwd+path; + return cwd+"/"+path; + } + + private String localAbsolutePath(String path) + { + if(isLocalAbsolutePath(path)) return path; + if(lcwd.endsWith(file_separator)) return lcwd+path; + return lcwd+file_separator+path; + } + + public class LsEntry + { + private String filename; + private String longname; + private SftpATTRS attrs; + internal LsEntry(String filename, String longname, SftpATTRS attrs) + { + setFilename(filename); + setLongname(longname); + setAttrs(attrs); + } + public String getFilename(){return filename;} + void setFilename(String filename){this.filename = filename;} + public String getLongname(){return longname;} + void setLongname(String longname){this.longname = longname;} + public SftpATTRS getAttrs(){return attrs;} + void setAttrs(SftpATTRS attrs) {this.attrs = attrs;} + public override string ToString(){return toString();} + public String toString(){ return longname; } + } + + public class InputStreamGet : InputStream + { + ChannelSftp sftp; + SftpProgressMonitor monitor; + long offset=0; + bool closed=false; + int rest_length=0; + byte[] _data=new byte[1]; + byte[] rest_byte=new byte[1024]; + byte[] handle; + Header header=new Header(); + + public InputStreamGet( + ChannelSftp sftp, + byte[] handle, + SftpProgressMonitor monitor) + { + this.sftp=sftp; + this.handle=handle; + this.monitor=monitor; + } + + public override int ReadByte() + { + if(closed)return -1; + int i=read(_data, 0, 1); + if (i==-1) { return -1; } + else + { + return _data[0]&0xff; + } + } + public int Read(byte[] d) + { + if(closed)return -1; + return Read(d, 0, d.Length); + } + public override int Read(byte[] d, int s, int len) + { + if(closed)return -1; + int i; + int foo; + if(d==null){throw new System.NullReferenceException();} + if(s<0 || len <0 || s+len>d.Length) + { + throw new System.IndexOutOfRangeException(); + } + if(len==0){ return 0; } + + if(rest_length>0) + { + foo=rest_length; + if(foo>len) foo=len; + java.System.arraycopy(rest_byte, 0, d, s, foo); + if(foo!=rest_length) + { + java.System.arraycopy(rest_byte, foo, + rest_byte, 0, rest_length-foo); + } + if(monitor!=null) + { + if(!monitor.count(foo)) + { + close(); + return -1; + } + } + + rest_length-=foo; + return foo; + } + + if(sftp.buf.buffer.Length-131024) + { + len=1024; + } + + try{sftp.sendREAD(handle, offset, len);} + catch(Exception e){ throw new System.IO.IOException("error"); } + + header= sftp.header(sftp.buf, header); + rest_length=header.length; + int type=header.type; + int id=header.rid; + + if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA) + { + throw new System.IO.IOException("error"); + } + if(type==SSH_FXP_STATUS) + { + sftp.buf.rewind(); + sftp.fill(sftp.buf.buffer, 0, rest_length); + i=sftp.buf.getInt(); + rest_length=0; + if(i==SSH_FX_EOF) + { + close(); + return -1; + } + //throwStatusError(buf, i); + throw new System.IO.IOException("error"); + } + sftp.buf.rewind(); + sftp.fill(sftp.buf.buffer, 0, 4); + i=sftp.buf.getInt(); rest_length-=4; + + offset+=rest_length; + foo=i; + if(foo>0) + { + int bar=rest_length; + if(bar>len) + { + bar=len; + } + i=sftp.io.ins.read(d, s, bar); + if(i<0) + { + return -1; + } + rest_length-=i; + + if(rest_length>0) + { + if(rest_byte.Length0) + { + j=sftp.io.ins.read(rest_byte, _s, _len); + if(j<=0)break; + _s+=j; + _len-=j; + } + } + + if(monitor!=null) + { + if(!monitor.count(i)) + { + close(); + return -1; + } + } + return i; + } + return 0; // ?? + } + public override void Close() + { + if(closed)return; + closed=true; + /* + while(rest_length>0){ + int foo=rest_length; + if(foo>buf.buffer.length){ + foo=buf.buffer.length; + } + io.in.read(buf.buffer, 0, foo); + rest_length-=foo; + } + */ + if(monitor!=null)monitor.end(); + try{sftp._sendCLOSE(handle, header);} + catch(Exception e){throw new System.IO.IOException("error");} + } + } + } +} diff --git a/SharpSSH/jsch/ChannelSftpStreamGet.cs b/SharpSSH/jsch/ChannelSftpStreamGet.cs new file mode 100644 index 00000000..1a9b1473 --- /dev/null +++ b/SharpSSH/jsch/ChannelSftpStreamGet.cs @@ -0,0 +1,157 @@ +//using System; +//using System.IO; +// +//namespace Tamir.SharpSsh.jsch +//{ +// public class InputStreamGet : java.io.InputStream +// { +// bool closed=false; +// int rest_length=0; +// byte[] _data=new byte[1]; +// ChannelSftp sftp; +// byte[] handle; +// long[] _offset; +// int[]_server_version; +// SftpProgressMonitor monitor; +// +// public InputStreamGet( +// ChannelSftp sftp, +// byte[] handle, +// long[] _offset, +// int[] _server_version, +// SftpProgressMonitor monitor) +// { +// this.sftp=sftp; +// this.handle=handle; +// this._offset=_offset; +// this._server_version=_server_version; +// this.monitor=monitor; +// } +// +// public override int ReadByte() +// { +// int i=read(_data, 0, 1); +// if (i==-1) { return -1; } +// else +// { +// return _data[0]&0xff; +// } +// } +// public override int read(byte[] d) +// { +// return Read(d, 0, d.Length); +// } +// public override int Read(byte[] d, int s, int len) +// { +// if(d==null){throw new NullReferenceException();} +// if(s<0 || len <0 || s+len>d.Length) +// { +// throw new ArgumentOutOfRangeException(); +// } +// if(len==0){ return 0; } +// +// if(rest_length>0) +// { +// int foo=rest_length; +// if(foo>len) foo=len; +// int i=sftp.io.ins.read(d, s, foo); +// if(i<0) +// { +// throw new IOException("error"); +// } +// rest_length-=i; +// return i; +// } +// +// if(sftp.buf.buffer.length-131024) +// { +// len=1024; +// } +// +// try{sftp.sendREAD(handle, offset, len);} +// catch(Exception e){ throw new IOException("error"); } +// +// sftp.buf.rewind(); +// int i=io.ins.read(buf.buffer, 0, 13); // 4 + 1 + 4 + 4 +// if(i!=13) +// { +// throw new IOException("error"); +// } +// +// rest_length=sftp.buf.getInt(); +// int type=sftp.buf.getByte(); +// rest_length--; +// sftp.buf.getInt(); +// rest_length-=4; +// if(type!=sftp.SSH_FXP_STATUS && type!=SSH_FXP_DATA) +// { +// throw new IOException("error"); +// } +// if(type==sftp.SSH_FXP_STATUS) +// { +// i=buf.getInt(); +// rest_length-=4; +// sftp.io.ins.read(sftp.buf.buffer, 13, rest_length); +// rest_length=0; +// if(i==SSH_FX_EOF) +// { +// close(); +// return -1; +// } +// //throwStatusError(buf, i); +// throw new IOException("error"); +// } +// +// i=buf.getInt(); +// rest_length-=4; +// offset+=rest_length; +// int foo=i; +// if(foo>0) +// { +// int bar=rest_length; +// if(bar>len) +// { +// bar=len; +// } +// i=io.ins.read(d, s, bar); +// if(i<0) +// { +// return -1; +// } +// rest_length-=i; +// +// if(monitor!=null) +// { +// if(!monitor.count(i)) +// { +// return -1; +// } +// } +// return i; +// } +// return 0; // ?? +// } +// public override void Close() +// { +// if(closed)return; +// closed=true; +// /* +// while(rest_length>0){ +// int foo=rest_length; +// if(foo>buf.buffer.length){ +// foo=buf.buffer.length; +// } +// io.in.read(buf.buffer, 0, foo); +// rest_length-=foo; +// } +// */ +// if(monitor!=null)monitor.end(); +// try{sftp._sendCLOSE(handle);} +// catch(Exception e){throw new IOException("error");} +// } +// } +//} diff --git a/SharpSSH/jsch/ChannelSftpStreamPut.cs b/SharpSSH/jsch/ChannelSftpStreamPut.cs new file mode 100644 index 00000000..ac097e3c --- /dev/null +++ b/SharpSSH/jsch/ChannelSftpStreamPut.cs @@ -0,0 +1,116 @@ +using System; +using System.IO; + +namespace Tamir.SharpSsh.jsch +{ + internal class OutputStreamPut : java.io.OutputStream + { + ChannelSftp sftp; + byte[] handle; + long[] _offset; + SftpProgressMonitor monitor; + private bool init=true; + private int[] ackid=new int[1]; + private int startid=0; + private int _ackid=0; + private int ackcount=0; + private ChannelSftp.Header header=new ChannelSftp.Header(); + + internal OutputStreamPut + (ChannelSftp sftp, + byte[] handle, + long[] _offset, + SftpProgressMonitor monitor):base() + { + this.sftp=sftp; + this.handle=handle; + this._offset=_offset; + this.monitor=monitor; + } + + public override void Write(byte[] d, int s, int len) + { + if(init) + { + startid=sftp.seq; + _ackid=sftp.seq; + init=false; + } + + try + { + int _len=len; + while(_len>0) + { + int sent=sftp.sendWRITE(handle, _offset[0], d, s, _len); + _offset[0]+=sent; + s+=sent; + _len-=sent; + if((sftp.seq-1)==startid || + sftp.io.ins.available()>=1024) + { + while(sftp.io.ins.available()>0) + { + if(sftp.checkStatus(ackid, header)) + { + _ackid=ackid[0]; + if(startid>_ackid || _ackid>sftp.seq-1) + { + throw new SftpException(ChannelSftp.SSH_FX_FAILURE, ""); + } + ackcount++; + } + else + { + break; + } + } + } + } + if(monitor!=null && !monitor.count(len)) + { + close(); + throw new IOException("canceled"); + } + } + catch(IOException e){ throw e; } + catch(Exception e){ throw new IOException(e.ToString()); } + } + byte[] _data=new byte[1]; + public void write(int foo) + { + _data[0]=(byte)foo; + Write(_data, 0, 1); + } + public override void Close() + { + if(!init) + { + try + { + int _ackcount=sftp.seq-startid; + while(_ackcount>ackcount) + { + if(!sftp.checkStatus(null, header)) + { + break; + } + ackcount++; + } + } + catch(SftpException e) + { + throw new IOException(e.toString()); + } + } + + if(monitor!=null)monitor.end(); + try{ sftp._sendCLOSE(handle, header); } + catch(IOException e){ throw e; } + catch(Exception e) + { + throw new IOException(e.ToString()); + } + } + } +} diff --git a/SharpSSH/jsch/ChannelShell.cs b/SharpSSH/jsch/ChannelShell.cs new file mode 100644 index 00000000..4220458b --- /dev/null +++ b/SharpSSH/jsch/ChannelShell.cs @@ -0,0 +1,89 @@ +using System; +using Tamir.SharpSsh.java.lang; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class ChannelShell : ChannelSession + { + internal bool xforwading=false; + internal bool pty=true; + public override void setXForwarding(bool foo){ xforwading=foo; } + public void setPty(bool foo){ pty=foo; } + public override void start() + { + try + { + Request request; + if(xforwading) + { + request=new RequestX11(); + request.request(session, this); + } + if(pty) + { + request=new RequestPtyReq(); + request.request(session, this); + } + request=new RequestShell(); + request.request(session, this); + } + catch//(Exception e) + { + throw new JSchException("ChannelShell"); + } + thread=new Thread(this); + thread.setName("Shell for "+session.host); + thread.start(); + } + public override void init() + { + io.setInputStream(session.In); + io.setOutputStream(session.Out); + } + + public void setPtySize(int col, int row, int wp, int hp) + { + //if(thread==null) return; + try + { + RequestWindowChange request=new RequestWindowChange(); + request.setSize(col, row, wp, hp); + request.request(session, this); + } + catch(Exception e) + { + throw new JSchException("ChannelShell.setPtySize: "+e.ToString()); + } + } + } + +} diff --git a/SharpSSH/jsch/ChannelSubsystem.cs b/SharpSSH/jsch/ChannelSubsystem.cs new file mode 100644 index 00000000..527433a5 --- /dev/null +++ b/SharpSSH/jsch/ChannelSubsystem.cs @@ -0,0 +1,89 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2005 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using Tamir.SharpSsh.java.net; +using Tamir.SharpSsh.java.lang; + +namespace Tamir.SharpSsh.jsch +{ + public class ChannelSubsystem : ChannelSession + { + bool xforwading=false; + bool pty=false; + bool want_reply=true; + String subsystem=""; + public override void setXForwarding(bool foo){ xforwading=true; } + public void setPty(bool foo){ pty=foo; } + public void setWantReply(bool foo){ want_reply=foo; } + public void setSubsystem(String foo){ subsystem=foo; } + public override void start() + { + try + { + Request request; + if(xforwading) + { + request=new RequestX11(); + request.request(session, this); + } + if(pty) + { + request=new RequestPtyReq(); + request.request(session, this); + } + request=new RequestSubsystem(); + ((RequestSubsystem)request).request(session, this, subsystem, want_reply); + } + catch(Exception e) + { + if(e is JSchException){ throw (JSchException)e; } + throw new JSchException("ChannelSubsystem"); + } + Thread thread=new Thread(this); + thread.setName("Subsystem for "+session.host); + thread.start(); + } + //public void finalize() throws Throwable{ super.finalize(); } + public override void init() + { + io.setInputStream(session.In); + io.setOutputStream(session.Out); + } + public void setErrStream(System.IO.Stream outs) + { + setExtOutputStream(outs); + } + public java.io.InputStream getErrStream() + { + return getExtInputStream(); + } + } + +} diff --git a/SharpSSH/jsch/ChannelX11.cs b/SharpSSH/jsch/ChannelX11.cs new file mode 100644 index 00000000..cd33875d --- /dev/null +++ b/SharpSSH/jsch/ChannelX11.cs @@ -0,0 +1,257 @@ +using System; +using System.Net; +using System.Net.Sockets; +using Tamir.SharpSsh.java.lang; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + internal class ChannelX11 : Channel + { + + private const int LOCAL_WINDOW_SIZE_MAX=0x20000; + private const int LOCAL_MAXIMUM_PACKET_SIZE=0x4000; + + internal static String host="127.0.0.1"; + internal static int port=6000; + + internal bool _init=true; + + internal static byte[] cookie=null; + //static byte[] cookie_hex="0c281f065158632a427d3e074d79265d".getBytes(); + internal static byte[] cookie_hex=null; + + private static System.Collections.Hashtable faked_cookie_pool=new System.Collections.Hashtable(); + private static System.Collections.Hashtable faked_cookie_hex_pool=new System.Collections.Hashtable(); + + internal static byte[] table={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39, + 0x61,0x62,0x63,0x64,0x65,0x66}; + internal static int revtable(byte foo) + { + for(int i=0; i>4)&0xf]; + bar[2*i+1]=table[(foo[i])&0xf]; + } + faked_cookie_hex_pool.Add(session, bar); + foo=bar; + } + return foo; + } + } + + Socket socket = null; + internal ChannelX11():base() + { + + setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX); + setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX); + setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE); + + type=Util.getBytes("x11"); + try + { + IPEndPoint ep = new IPEndPoint(Dns.GetHostByName(host).AddressList[0], port); + socket=new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1); + socket.Connect(ep); + io=new IO(); + NetworkStream ns = new NetworkStream( socket ); + io.setInputStream(ns); + io.setOutputStream(ns); + } + catch(Exception e) + { + Console.WriteLine(e); + } + } + + public override void run() + { + thread=Thread.currentThread(); + Buffer buf=new Buffer(rmpsize); + Packet packet=new Packet(buf); + int i=0; + try + { + while(thread!=null) + { + i=io.ins.Read(buf.buffer, + 14, + buf.buffer.Length-14 + -16 -20 // padding and mac + ); + if(i<=0) + { + eof(); + break; + } + if(_close)break; + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); + buf.putInt(recipient); + buf.putInt(i); + buf.skip(i); + session.write(packet, this, i); + } + } + catch + { + //System.out.println(e); + } + thread=null; + } + + internal override void write(byte[] foo, int s, int l) + { + //if(eof_local)return; + + if(_init) + { + int plen=(foo[s+6]&0xff)*256+(foo[s+7]&0xff); + int dlen=(foo[s+8]&0xff)*256+(foo[s+9]&0xff); + if((foo[s]&0xff)==0x42) + { + } + else if((foo[s]&0xff)==0x6c) + { + plen=(int)(((uint)plen>>8)&0xff)|((plen<<8)&0xff00); + dlen=(int)(((uint)dlen>>8)&0xff)|((dlen<<8)&0xff00); + } + else + { + // ?? + } + byte[] bar=new byte[dlen]; + Array.Copy(foo, s+12+plen+((-plen)&3), bar, 0, dlen); + byte[] faked_cookie=(byte[])faked_cookie_pool[session]; + + if(equals(bar, faked_cookie)) + { + if(cookie!=null) + Array.Copy(cookie, 0, foo, s+12+plen+((-plen)&3), dlen); + } + else + { + Console.WriteLine("wrong cookie"); + } + _init=false; + } + io.put(foo, s, l); + } + + public override void disconnect() + { + close(); + thread=null; + try + { + if(io!=null) + { + try + { + if(io.ins!=null) + io.ins.Close(); + } + catch{} + try + { + if(io.outs!=null) + io.outs.Close(); + } + catch{} + } + try + { + if(socket!=null) + socket.Close(); + } + catch{} + } + catch(Exception e) + { + Console.WriteLine(e.StackTrace); + } + io=null; + Channel.del(this); + } + + private static bool equals(byte[] foo, byte[] bar) + { + if(foo.Length!=bar.Length)return false; + for(int i=0; i "); //dump(H, 0, H.length); + + i=0; + j=0; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + String alg=Util.getString(K_S, i, j); + i+=j; + + result=false; + + if(alg.Equals("ssh-rsa")) + { + byte[] tmp; + byte[] ee; + byte[] n; + + type=RSA; + + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + ee=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + n=tmp; + + // SignatureRSA sig=new SignatureRSA(); + // sig.init(); + + SignatureRSA sig=null; + try + { + Type t=Type.GetType(session.getConfig("signature.rsa")); + sig=(SignatureRSA)(Activator.CreateInstance(t)); + sig.init(); + } + catch(Exception eee) + { + Console.WriteLine(eee); + } + + sig.setPubKey(ee, n); + sig.update(H); + result=sig.verify(sig_of_H); + //MainClass.dump(ee, n, sig_of_H, H); + } + else if(alg.Equals("ssh-dss")) + { + byte[] q=null; + byte[] tmp; + byte[] p; + byte[] g; + + type=DSS; + + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + p=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + q=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + g=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + f=tmp; + // SignatureDSA sig=new SignatureDSA(); + // sig.init(); + SignatureDSA sig=null; + try + { + Type t=Type.GetType(session.getConfig("signature.dss")); + sig=(SignatureDSA)(Activator.CreateInstance(t)); + sig.init(); + } + catch(Exception ee) + { + Console.WriteLine(ee); + } + sig.setPubKey(f, p, q, g); + sig.update(H); + result=sig.verify(sig_of_H); + } + else + { + Console.WriteLine("unknow alg"); + } + state=STATE_END; + break; + } + return result; + } + + public override String getKeyType() + { + if(type==DSS) return "DSA"; + return "RSA"; + } + + public override int getState(){return state; } + } + +} diff --git a/SharpSSH/jsch/DHGEX.cs b/SharpSSH/jsch/DHGEX.cs new file mode 100644 index 00000000..922b459c --- /dev/null +++ b/SharpSSH/jsch/DHGEX.cs @@ -0,0 +1,340 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + + public class DHGEX : KeyExchange + { + + internal const int SSH_MSG_KEX_DH_GEX_GROUP= 31; + internal const int SSH_MSG_KEX_DH_GEX_INIT= 32; + internal const int SSH_MSG_KEX_DH_GEX_REPLY= 33; + + internal static int min=1024; + + // static int min=512; + internal static int preferred=1024; + internal static int max=1024; + + // static int preferred=1024; + // static int max=2000; + + internal const int RSA=0; + internal const int DSS=1; + private int type=0; + + private int state; + + // com.jcraft.jsch.DH dh; + internal DH dh; + + internal byte[] V_S; + internal byte[] V_C; + internal byte[] I_S; + internal byte[] I_C; + + private Buffer buf; + private Packet packet; + + private byte[] p; + private byte[] g; + private byte[] e; + //private byte[] f; + + public override void init(Session session, + byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) + { + this.session=session; + this.V_S=V_S; + this.V_C=V_C; + this.I_S=I_S; + this.I_C=I_C; + + // sha=new SHA1(); + // sha.init(); + + try + { + Type t=Type.GetType(session.getConfig("sha-1")); + sha=(HASH)(Activator.CreateInstance(t)); + sha.init(); + } + catch(Exception e) + { + Console.WriteLine(e); + } + + buf=new Buffer(); + packet=new Packet(buf); + + try + { + Type t=Type.GetType(session.getConfig("dh")); + dh=(DH)(Activator.CreateInstance(t)); + dh.init(); + } + catch(Exception e) + { + throw e; + } + + packet.reset(); + buf.putByte((byte)0x22); + buf.putInt(min); + buf.putInt(preferred); + buf.putInt(max); + session.write(packet); + + state=SSH_MSG_KEX_DH_GEX_GROUP; + } + + public override bool next(Buffer _buf) + { + int i,j; + bool result=false; + switch(state) + { + case SSH_MSG_KEX_DH_GEX_GROUP: + // byte SSH_MSG_KEX_DH_GEX_GROUP(31) + // mpint p, safe prime + // mpint g, generator for subgroup in GF (p) + _buf.getInt(); + _buf.getByte(); + j=_buf.getByte(); + if(j!=31) + { + Console.WriteLine("type: must be 31 "+j); + result = false; + } + + p=_buf.getMPInt(); + g=_buf.getMPInt(); + /* + for(int iii=0; iii "); dump(H, 0, H.length); + + i=0; + j=0; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + String alg=Util.getString(K_S, i, j); + i+=j; + + + if(alg.Equals("ssh-rsa")) + { + byte[] tmp; + byte[] ee; + byte[] n; + + type=RSA; + + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + ee=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + n=tmp; + + // SignatureRSA sig=new SignatureRSA(); + // sig.init(); + + SignatureRSA sig=null; + try + { + Type t=Type.GetType(session.getConfig("signature.rsa")); + sig=(SignatureRSA)(Activator.CreateInstance(t)); + sig.init(); + } + catch(Exception eee) + { + Console.WriteLine(eee); + } + + sig.setPubKey(ee, n); + sig.update(H); + result=sig.verify(sig_of_H); + } + else if(alg.Equals("ssh-dss")) + { + byte[] q=null; + byte[] tmp; + + type=DSS; + + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + p=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + q=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + g=tmp; + j=(int)((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)| + ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff); + tmp=new byte[j]; Array.Copy(K_S, i, tmp, 0, j); i+=j; + f=tmp; + + // SignatureDSA sig=new SignatureDSA(); + // sig.init(); + + SignatureDSA sig=null; + try + { + Type t=Type.GetType(session.getConfig("signature.dss")); + sig=(SignatureDSA)(Activator.CreateInstance(t)); + sig.init(); + } + catch(Exception ee) + { + Console.WriteLine(ee); + } + + sig.setPubKey(f, p, q, g); + sig.update(H); + result=sig.verify(sig_of_H); + } + else + { + Console.WriteLine("unknow alg"); + } + state=STATE_END; + break; + } + return result; + } + + public override String getKeyType() + { + if(type==DSS) return "DSA"; + return "RSA"; + } + + public override int getState(){return state; } + } + +} + diff --git a/SharpSSH/jsch/ForwardedTCPIPDaemon.cs b/SharpSSH/jsch/ForwardedTCPIPDaemon.cs new file mode 100644 index 00000000..5ec781ab --- /dev/null +++ b/SharpSSH/jsch/ForwardedTCPIPDaemon.cs @@ -0,0 +1,11 @@ +using System; +using Tamir.SharpSsh.java.lang; + +namespace Tamir.SharpSsh.jsch +{ + public interface ForwardedTCPIPDaemon : Runnable + { + void setChannel(ChannelForwardedTCPIP channel); + void setArg(Object[] arg); + } +} diff --git a/SharpSSH/jsch/HASH.cs b/SharpSSH/jsch/HASH.cs new file mode 100644 index 00000000..33ebcecf --- /dev/null +++ b/SharpSSH/jsch/HASH.cs @@ -0,0 +1,41 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public abstract class HASH + { + public abstract void init(); + public abstract int getBlockSize(); + public abstract void update(byte[] foo, int start, int len); + public abstract byte[] digest(); + } +} diff --git a/SharpSSH/jsch/HostKey.cs b/SharpSSH/jsch/HostKey.cs new file mode 100644 index 00000000..6c5042f6 --- /dev/null +++ b/SharpSSH/jsch/HostKey.cs @@ -0,0 +1,74 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + public class HostKey{ + private static byte[] sshdss= System.Text.Encoding.Default.GetBytes( "ssh-dss" ); + private static byte[] sshrsa= System.Text.Encoding.Default.GetBytes( "ssh-rsa" ); + + public const int SSHDSS=0; + public const int SSHRSA=1; + public const int UNKNOWN=2; + + internal String host; + internal int type; + internal byte[] key; + public HostKey(String host, byte[] key) + { + this.host=host; this.key=key; + if(key[8]=='d'){ this.type=SSHDSS; } + else if(key[8]=='r'){ this.type=SSHRSA; } + else { throw new JSchException("invalid key type");} + } + internal HostKey(String host, int type, byte[] key){ + this.host=host; this.type=type; this.key=key; + } + public String getHost(){ return host; } + public String getType(){ + if(type==SSHDSS){ return System.Text.Encoding.Default.GetString(sshdss); } + if(type==SSHRSA){ return System.Text.Encoding.Default.GetString(sshrsa);} + return "UNKNOWN"; + } + public String getKey(){ + return Convert.ToBase64String(key, 0, key.Length); + } + public String getFingerPrint(JSch jsch){ + HASH hash=null; + try{ + hash=(HASH)Activator.CreateInstance(Type.GetType(jsch.getConfig("md5"))); + } + catch(Exception e){ Console.Error.WriteLine("getFingerPrint: "+e); } + return Util.getFingerPrint(hash, key); + } + } + +} diff --git a/SharpSSH/jsch/HostKeyRepository.cs b/SharpSSH/jsch/HostKeyRepository.cs new file mode 100644 index 00000000..aff4fa30 --- /dev/null +++ b/SharpSSH/jsch/HostKeyRepository.cs @@ -0,0 +1,48 @@ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; + +namespace Tamir.SharpSsh.jsch +{ + public abstract class HostKeyRepository + { + internal const int OK=0; + internal const int NOT_INCLUDED=1; + internal const int CHANGED=2; + + public abstract int check(String host, byte[] key); + public abstract void add(String host, byte[] key, UserInfo ui); + public abstract void remove(String host, String type); + public abstract void remove(String host, String type, byte[] key); + public abstract String getKnownHostsRepositoryID(); + public abstract HostKey[] getHostKey(); + public abstract HostKey[] getHostKey(String host, String type); + } +} diff --git a/SharpSSH/jsch/IO.cs b/SharpSSH/jsch/IO.cs new file mode 100644 index 00000000..a54d7856 --- /dev/null +++ b/SharpSSH/jsch/IO.cs @@ -0,0 +1,183 @@ +using System; +using System.IO; +using Tamir.SharpSsh.java.io; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class IO + { + internal JStream ins; + internal JStream outs; + internal JStream outs_ext; + + private bool in_dontclose=false; + private bool out_dontclose=false; + private bool outs_ext_dontclose=false; + + public void setOutputStream(Stream outs) + { + if(outs!=null) + { + this.outs= new JStream(outs); + } + else + { + this.outs=null; + } + } + public void setOutputStream(Stream outs, bool dontclose) + { + this.out_dontclose=dontclose; + setOutputStream(outs); + } + public void setExtOutputStream(Stream outs) + { + if(outs!=null) + { + this.outs_ext=new JStream(outs); + } + else + { + this.outs_ext=null; + } + } + public void setExtOutputStream(Stream outs, bool dontclose) + { + this.outs_ext_dontclose=dontclose; + setExtOutputStream(outs); + } + public void setInputStream(Stream ins) + { + //ConsoleStream low buffer patch + if(ins!=null) + { + if(ins.GetType() == Type.GetType("System.IO.__ConsoleStream")) + { + ins = new Tamir.Streams.ProtectedConsoleStream(ins); + } + else if(ins.GetType() == Type.GetType("System.IO.FileStream")) + { + ins = new Tamir.Streams.ProtectedConsoleStream(ins); + } + this.ins=new JStream(ins); + } + else + { + this.ins=null; + } + } + public void setInputStream(Stream ins, bool dontclose) + { + this.in_dontclose=dontclose; + setInputStream(ins); + } + + public void put(Packet p) + { + outs.Write(p.buffer.buffer, 0, p.buffer.index); + outs.Flush(); + } + internal void put(byte[] array, int begin, int length) + { + outs.Write(array, begin, length); + outs.Flush(); + } + internal void put_ext(byte[] array, int begin, int length) + { + outs_ext.Write(array, begin, length); + outs_ext.Flush(); + } + + internal int getByte() + { + int res = ins.ReadByte()&0xff; + return res; + } + + internal void getByte(byte[] array) + { + getByte(array, 0, array.Length); + } + + internal void getByte(byte[] array, int begin, int length) + { + do + { + int completed = ins.Read(array, begin, length); + if(completed<=0) + { + throw new IOException("End of IO Stream Read"); + } + begin+=completed; + length-=completed; + } + while (length>0); + } + + public void close() + { + try + { + if(ins!=null && !in_dontclose) ins.Close(); + ins=null; + } + catch(Exception ee){} + try + { + if(outs!=null && !out_dontclose) outs.Close(); + outs=null; + } + catch(Exception ee){} + try + { + if(outs_ext!=null && !outs_ext_dontclose) outs_ext.Close(); + outs_ext=null; + } + catch(Exception ee){} + } + +// public void finalize() +// { +// try +// { +// if(ins!=null) ins.Close(); +// } +// catch{} +// try +// { +// if(outs!=null) outs.Close(); +// } +// catch{} +// } + } + +} diff --git a/SharpSSH/jsch/Identity.cs b/SharpSSH/jsch/Identity.cs new file mode 100644 index 00000000..a4e2c693 --- /dev/null +++ b/SharpSSH/jsch/Identity.cs @@ -0,0 +1,44 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + internal interface Identity + { + bool setPassphrase(String passphrase); + byte[] getPublicKeyBlob(); + byte[] getSignature(Session session, byte[] data); + bool decrypt(); + String getAlgName(); + String getName(); + bool isEncrypted(); + } +} diff --git a/SharpSSH/jsch/IdentityFile.cs b/SharpSSH/jsch/IdentityFile.cs new file mode 100644 index 00000000..51ecb948 --- /dev/null +++ b/SharpSSH/jsch/IdentityFile.cs @@ -0,0 +1,949 @@ +using System; +using System.IO; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + internal class IdentityFile : Identity + { + String identity; + byte[] key; + byte[] iv; + private JSch jsch; + private HASH hash; + private byte[] encoded_data; + + private Cipher cipher; + + // DSA + private byte[] P_array; + private byte[] Q_array; + private byte[] G_array; + private byte[] pub_array; + private byte[] prv_array; + + // RSA + private byte[] n_array; // modulus + private byte[] e_array; // public exponent + private byte[] d_array; // private exponent + + private byte[] p_array; + private byte[] q_array; + private byte[] dmp1_array; + private byte[] dmq1_array; + private byte[] iqmp_array; + + // private String algname="ssh-dss"; + private String algname="ssh-rsa"; + + private const int ERROR=0; + private const int RSA=1; + private const int DSS=2; + internal const int UNKNOWN=3; + + private const int OPENSSH=0; + private const int FSECURE=1; + private const int PUTTY=2; + + private int type=ERROR; + private int keytype=OPENSSH; + + private byte[] publickeyblob=null; + + private bool encrypted=true; + + internal IdentityFile(String identity, JSch jsch) + { + this.identity=identity; + this.jsch=jsch; + try + { + Type c=Type.GetType(jsch.getConfig("3des-cbc")); + cipher=(Cipher)Activator.CreateInstance(c); + key=new byte[cipher.getBlockSize()]; // 24 + iv=new byte[cipher.getIVSize()]; // 8 + c=Type.GetType(jsch.getConfig("md5")); + hash=(HASH)(Activator.CreateInstance(c)); + hash.init(); + FileInfo file=new FileInfo(identity); + FileStream fis = File.OpenRead(identity); + byte[] buf=new byte[(int)(file.Length)]; + int len=fis.Read(buf, 0, buf.Length); + fis.Close(); + + int i=0; + while(i4 && // FSecure + encoded_data[0]==(byte)0x3f && + encoded_data[1]==(byte)0x6f && + encoded_data[2]==(byte)0xf9 && + encoded_data[3]==(byte)0xeb) + { + + Buffer _buf=new Buffer(encoded_data); + _buf.getInt(); // 0x3f6ff9be + _buf.getInt(); + byte[]_type=_buf.getString(); + //System.out.println("type: "+new String(_type)); + byte[] _cipher=_buf.getString(); + String s_cipher=System.Text.Encoding.Default.GetString(_cipher); + //System.out.println("cipher: "+cipher); + if(s_cipher.Equals("3des-cbc")) + { + _buf.getInt(); + byte[] foo=new byte[encoded_data.Length-_buf.getOffSet()]; + _buf.getByte(foo); + encoded_data=foo; + encrypted=true; + throw new JSchException("unknown privatekey format: "+identity); + } + else if(s_cipher.Equals("none")) + { + _buf.getInt(); + //_buf.getInt(); + + encrypted=false; + + byte[] foo=new byte[encoded_data.Length-_buf.getOffSet()]; + _buf.getByte(foo); + encoded_data=foo; + } + + } + + try + { + file=new FileInfo(identity+".pub"); + fis=File.OpenRead(identity+".pub"); + buf=new byte[(int)(file.Length)]; + len=fis.Read(buf, 0, buf.Length); + fis.Close(); + } + catch + { + return; + } + + if(buf.Length>4 && // FSecure's public key + buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-') + { + + i=0; + do{i++;}while(buf.Length>i && buf[i]!=0x0a); + if(buf.Length<=i) return; + + while(true) + { + if(buf[i]==0x0a) + { + bool inheader=false; + for(int j=i+1; j=len) return; + start=i; + while(i>>24); + goo[1]=(byte)(session.getSessionId().Length>>>16); + goo[2]=(byte)(session.getSessionId().Length>>>8); + goo[3]=(byte)(session.getSessionId().Length); + rsa.update(goo); + rsa.update(session.getSessionId()); + */ + rsa.update(data); + byte[] sig = rsa.sign(); + Buffer buf=new Buffer("ssh-rsa".Length+4+ + sig.Length+4); + buf.putString( System.Text.Encoding.Default.GetBytes( "ssh-rsa" )); + buf.putString(sig); + return buf.buffer; + } + catch(Exception e) + { + Console.WriteLine(e); + } + return null; + } + + byte[] getSignature_dss(Session session, byte[] data) + { + /* + byte[] foo; + int i; + System.out.print("P "); + foo=P_array; + for(i=0; i>>24); + goo[1]=(byte)(session.getSessionId().Length>>>16); + goo[2]=(byte)(session.getSessionId().Length>>>8); + goo[3]=(byte)(session.getSessionId().Length); + dsa.update(goo); + dsa.update(session.getSessionId()); + */ + dsa.update(data); + byte[] sig = dsa.sign(); + Buffer buf=new Buffer("ssh-dss".Length+4+ + sig.Length+4); + buf.putString( System.Text.Encoding.Default.GetBytes( "ssh-dss" ) ); + buf.putString(sig); + return buf.buffer; + } + catch(Exception e) + { + Console.WriteLine("e "+e); + } + return null; + } + + public bool decrypt() + { + if(type==RSA) return decrypt_rsa(); + return decrypt_dss(); + } + + bool decrypt_rsa() + { +// byte[] p_array; +// byte[] q_array; +// byte[] dmp1_array; +// byte[] dmq1_array; +// byte[] iqmp_array; + + try + { + byte[] plain; + if(encrypted) + { + if(keytype==OPENSSH) + { + cipher.init(Cipher.DECRYPT_MODE, key, iv); + plain=new byte[encoded_data.Length]; + cipher.update(encoded_data, 0, encoded_data.Length, plain, 0); + } + else if(keytype==FSECURE) + { + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + + if(plain[index]!=0x02)return false; + index++; // INTEGER + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + index+=Length; + + //System.out.println("int: len="+Length); + //System.out.print(Integer.toHexString(plain[index-1]&0xff)+":"); + //System.out.println(""); + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + n_array=new byte[Length]; + Array.Copy(plain, index, n_array, 0, Length); + index+=Length; + /* + System.out.println("int: N len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + e_array=new byte[Length]; + Array.Copy(plain, index, e_array, 0, Length); + index+=Length; + /* + System.out.println("int: E len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + d_array=new byte[Length]; + Array.Copy(plain, index, d_array, 0, Length); + index+=Length; + /* + System.out.println("int: D len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + p_array=new byte[Length]; + Array.Copy(plain, index, p_array, 0, Length); + index+=Length; + /* + System.out.println("int: P len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + q_array=new byte[Length]; + Array.Copy(plain, index, q_array, 0, Length); + index+=Length; + /* + System.out.println("int: q len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + dmp1_array=new byte[Length]; + Array.Copy(plain, index, dmp1_array, 0, Length); + index+=Length; + /* + System.out.println("int: dmp1 len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + dmq1_array=new byte[Length]; + Array.Copy(plain, index, dmq1_array, 0, Length); + index+=Length; + /* + System.out.println("int: dmq1 len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + iqmp_array=new byte[Length]; + Array.Copy(plain, index, iqmp_array, 0, Length); + index+=Length; + /* + System.out.println("int: iqmp len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + + if(plain[index]!=0x02)return false; + index++; // INTEGER + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + P_array=new byte[Length]; + Array.Copy(plain, index, P_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + Q_array=new byte[Length]; + Array.Copy(plain, index, Q_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + G_array=new byte[Length]; + Array.Copy(plain, index, G_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + pub_array=new byte[Length]; + Array.Copy(plain, index, pub_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + prv_array=new byte[Length]; + Array.Copy(plain, index, prv_array, 0, Length); + index+=Length; + } + catch + { + //System.out.println(e); + //e.printStackTrace(); + return false; + } + return true; + } + + public bool isEncrypted() + { + return encrypted; + } + public String getName(){return identity;} + + private int writeSEQUENCE(byte[] buf, int index, int len) + { + buf[index++]=0x30; + index=writeLength(buf, index, len); + return index; + } + private int writeINTEGER(byte[] buf, int index, byte[] data) + { + buf[index++]=0x02; + index=writeLength(buf, index, data.Length); + Array.Copy(data, 0, buf, index, data.Length); + index+=data.Length; + return index; + } + + private int countLength(int i_len) + { + uint len = (uint)i_len; + int i=1; + if(len<=0x7f) return i; + while(len>0) + { + len>>=8; + i++; + } + return i; + } + + private int writeLength(byte[] data, int index, int i_len) + { + int len = (int)i_len; + int i=countLength(len)-1; + if(i==0) + { + data[index++]=(byte)len; + return index; + } + data[index++]=(byte)(0x80|i); + int j=index+i; + while(i>0) + { + data[index+i-1]=(byte)(len&0xff); + len>>=8; + i--; + } + return j; + } + + private byte a2b(byte c) + { + if('0'<=c&&c<='9') return (byte)(c-'0'); + if('a'<=c&&c<='z') return (byte)(c-'a'+10); + return (byte)(c-'A'+10); + } + private byte b2a(byte c) + { + if(0<=c&&c<=9) return (byte)(c+'0'); + return (byte)(c-10+'A'); + } + } + +} diff --git a/SharpSSH/jsch/JSch.cs b/SharpSSH/jsch/JSch.cs new file mode 100644 index 00000000..a320e482 --- /dev/null +++ b/SharpSSH/jsch/JSch.cs @@ -0,0 +1,241 @@ +using System; +using System.IO; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class JSch + { + + static System.Collections.Hashtable config; + + public static void Init() + { + config=new System.Collections.Hashtable(); + + // config.Add("kex", "diffie-hellman-group-exchange-sha1"); + config.Add("kex", "diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1"); + config.Add("server_host_key", "ssh-rsa,ssh-dss"); + //config.Add("server_host_key", "ssh-dss,ssh-rsa"); + + // config.Add("cipher.s2c", "3des-cbc,blowfish-cbc"); + // config.Add("cipher.c2s", "3des-cbc,blowfish-cbc"); + + config.Add("cipher.s2c", "3des-cbc,aes128-cbc"); + config.Add("cipher.c2s", "3des-cbc,aes128-cbc"); + + // config.Add("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96"); + // config.Add("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96"); + config.Add("mac.s2c", "hmac-md5,hmac-sha1"); + config.Add("mac.c2s", "hmac-md5,hmac-sha1"); + config.Add("compression.s2c", "none"); + config.Add("compression.c2s", "none"); + config.Add("lang.s2c", ""); + config.Add("lang.c2s", ""); + + config.Add("diffie-hellman-group-exchange-sha1", + "Tamir.SharpSsh.jsch.DHGEX"); + config.Add("diffie-hellman-group1-sha1", + "Tamir.SharpSsh.jsch.DHG1"); + + config.Add("dh", "Tamir.SharpSsh.jsch.jce.DH"); + config.Add("3des-cbc", "Tamir.SharpSsh.jsch.jce.TripleDESCBC"); + //config.Add("blowfish-cbc", "Tamir.SharpSsh.jsch.jce.BlowfishCBC"); + config.Add("hmac-sha1", "Tamir.SharpSsh.jsch.jce.HMACSHA1"); + config.Add("hmac-sha1-96", "Tamir.SharpSsh.jsch.jce.HMACSHA196"); + config.Add("hmac-md5", "Tamir.SharpSsh.jsch.jce.HMACMD5"); + config.Add("hmac-md5-96", "Tamir.SharpSsh.jsch.jce.HMACMD596"); + config.Add("sha-1", "Tamir.SharpSsh.jsch.jce.SHA1"); + config.Add("md5", "Tamir.SharpSsh.jsch.jce.MD5"); + config.Add("signature.dss", "Tamir.SharpSsh.jsch.jce.SignatureDSA"); + config.Add("signature.rsa", "Tamir.SharpSsh.jsch.jce.SignatureRSA"); + config.Add("keypairgen.dsa", "Tamir.SharpSsh.jsch.jce.KeyPairGenDSA"); + config.Add("keypairgen.rsa", "Tamir.SharpSsh.jsch.jce.KeyPairGenRSA"); + config.Add("random", "Tamir.SharpSsh.jsch.jce.Random"); + + config.Add("aes128-cbc", "Tamir.SharpSsh.jsch.jce.AES128CBC"); + + //config.Add("zlib", "com.jcraft.jsch.jcraft.Compression"); + + config.Add("StrictHostKeyChecking", "ask"); + } + + internal Tamir.SharpSsh.java.util.Vector pool=new Tamir.SharpSsh.java.util.Vector(); + internal Tamir.SharpSsh.java.util.Vector identities=new Tamir.SharpSsh.java.util.Vector(); + //private KnownHosts known_hosts=null; + private HostKeyRepository known_hosts=null; + + public JSch() + { + //known_hosts=new KnownHosts(this); + if (config==null) + Init(); + } + + public Session getSession(String username, String host) { return getSession(username, host, 22); } + public Session getSession(String username, String host, int port) + { + Session s=new Session(this); + s.setUserName(username); + s.setHost(host); + s.setPort(port); + pool.Add(s); + return s; + } + + internal bool removeSession(Session session) + { + lock(pool) + { + return pool.remove(session); + } + } + + public void setHostKeyRepository(HostKeyRepository foo) + { + known_hosts=foo; + } + public void setKnownHosts(String foo) + { + if(known_hosts==null) known_hosts=new KnownHosts(this); + if(known_hosts is KnownHosts) + { + lock(known_hosts) + { + ((KnownHosts)known_hosts).setKnownHosts(foo); + } + } + } + public void setKnownHosts(StreamReader foo) + { + if(known_hosts==null) known_hosts=new KnownHosts(this); + if(known_hosts is KnownHosts) + { + lock(known_hosts) + { + ((KnownHosts)known_hosts).setKnownHosts(foo); + } + } + } + /* + HostKeyRepository getKnownHosts(){ + if(known_hosts==null) known_hosts=new KnownHosts(this); + return known_hosts; + } + */ + public HostKeyRepository getHostKeyRepository() + { + if(known_hosts==null) known_hosts=new KnownHosts(this); + return known_hosts; + } + /* + public HostKey[] getHostKey(){ + if(known_hosts==null) return null; + return known_hosts.getHostKey(); + } + public void removeHostKey(String foo, String type){ + removeHostKey(foo, type, null); + } + public void removeHostKey(String foo, String type, byte[] key){ + if(known_hosts==null) return; + known_hosts.remove(foo, type, key); + } + */ + public void addIdentity(String foo) + { + addIdentity(foo, (String)null); + } + public void addIdentity(String foo, String bar) + { + Identity identity=new IdentityFile(foo, this); + if(bar!=null) identity.setPassphrase(bar); + identities.Add(identity); + } + internal String getConfig(String foo){ return (String)(config[foo]); } + + private System.Collections.ArrayList proxies; + void setProxy(String hosts, Proxy proxy) + { + String[] patterns=Util.split(hosts, ","); + if(proxies==null){proxies=new System.Collections.ArrayList();} + lock(proxies) + { + for(int i=0; i + /// Summary description for JSchException. + /// + public class JSchAuthCancelException : JSchException + { + public JSchAuthCancelException() : base() + { + // + // TODO: Add constructor logic here + // + } + + public JSchAuthCancelException(string msg) : base (msg) + { + } + } +} diff --git a/SharpSSH/jsch/JSchException.cs b/SharpSSH/jsch/JSchException.cs new file mode 100644 index 00000000..b7aa42bd --- /dev/null +++ b/SharpSSH/jsch/JSchException.cs @@ -0,0 +1,21 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /// + /// Summary description for JSchException. + /// + public class JSchException : java.Exception + { + public JSchException() : base() + { + // + // TODO: Add constructor logic here + // + } + + public JSchException(string msg) : base (msg) + { + } + } +} diff --git a/SharpSSH/jsch/JSchPartialAuthException.cs b/SharpSSH/jsch/JSchPartialAuthException.cs new file mode 100644 index 00000000..7176fd92 --- /dev/null +++ b/SharpSSH/jsch/JSchPartialAuthException.cs @@ -0,0 +1,26 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /// + /// Summary description for JSchException. + /// + public class JSchPartialAuthException : JSchException + { + string methods; + public JSchPartialAuthException() : base() + { + methods = null; + } + + public JSchPartialAuthException(string msg) : base (msg) + { + methods = msg; + } + + public String getMethods() + { + return methods; + } + } +} diff --git a/SharpSSH/jsch/KeyExchange.cs b/SharpSSH/jsch/KeyExchange.cs new file mode 100644 index 00000000..79014bcc --- /dev/null +++ b/SharpSSH/jsch/KeyExchange.cs @@ -0,0 +1,170 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public abstract class KeyExchange + { + + internal const int PROPOSAL_KEX_ALGS=0; + internal const int PROPOSAL_SERVER_HOST_KEY_ALGS=1; + internal const int PROPOSAL_ENC_ALGS_CTOS=2; + internal const int PROPOSAL_ENC_ALGS_STOC=3; + internal const int PROPOSAL_MAC_ALGS_CTOS=4; + internal const int PROPOSAL_MAC_ALGS_STOC=5; + internal const int PROPOSAL_COMP_ALGS_CTOS=6; + internal const int PROPOSAL_COMP_ALGS_STOC=7; + internal const int PROPOSAL_LANG_CTOS=8; + internal const int PROPOSAL_LANG_STOC=9; + internal const int PROPOSAL_MAX=10; + + //static String kex_algs="diffie-hellman-group-exchange-sha1"+ + // ",diffie-hellman-group1-sha1"; + + //static String kex="diffie-hellman-group-exchange-sha1"; + internal static String kex="diffie-hellman-group1-sha1"; + internal static String server_host_key="ssh-rsa,ssh-dss"; + internal static String enc_c2s="blowfish-cbc"; + internal static String enc_s2c="blowfish-cbc"; + internal static String mac_c2s="hmac-md5"; // hmac-md5,hmac-sha1,hmac-ripemd160, + // hmac-sha1-96,hmac-md5-96 + internal static String mac_s2c="hmac-md5"; + //static String comp_c2s="none"; // zlib + //static String comp_s2c="none"; + internal static String lang_c2s=""; + internal static String lang_s2c=""; + + public const int STATE_END=0; + + public Tamir.SharpSsh.java.String[] _guess=null; + protected Session session=null; + protected HASH sha=null; + protected byte[] K=null; + protected byte[] H=null; + protected byte[] K_S=null; + + public abstract void init(Session session, + byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C); + public abstract bool next(Buffer buf); + public abstract String getKeyType(); + public abstract int getState(); + + /* + void dump(byte[] foo){ + for(int i=0; i>4)&0x0f))); + outs.WriteByte(b2a((byte)(iv[j]&0x0f))); + } + Write(outs,cr); + Write(outs,cr); + } + int i=0; + while(i0) + { + len>>=8; + i++; + } + return i; + } + + internal int writeLength(byte[] data, int index, int len) + { + int i=countLength(len)-1; + if(i==0) + { + data[index++]=(byte)len; + return index; + } + data[index++]=(byte)(0x80|i); + int j=index+i; + while(i>0) + { + data[index+i-1]=(byte)(len&0xff); + len>>=8; + i--; + } + return j; + } + + private Random genRandom() + { + if(random==null) + { + try + { + Type t=Type.GetType(jsch.getConfig("random")); + random=(Random)Activator.CreateInstance(t); + } + catch(Exception e){ Console.Error.WriteLine("connect: random "+e); } + } + return random; + } + + private HASH genHash() + { + try + { + Type t=Type.GetType(jsch.getConfig("md5")); + hash=(HASH)Activator.CreateInstance(t); + hash.init(); + } + catch//(Exception e) + { + } + return hash; + } + private Cipher genCipher() + { + try + { + Type t; + t=Type.GetType(jsch.getConfig("3des-cbc")); + cipher=(Cipher)(Activator.CreateInstance(t)); + } + catch//(Exception e) + { + } + return cipher; + } + + /* + hash is MD5 + h(0) <- hash(passphrase, iv); + h(n) <- hash(h(n-1), passphrase, iv); + key <- (h(0),...,h(n))[0,..,key.Length]; + */ + [MethodImpl(MethodImplOptions.Synchronized)] + internal byte[] genKey(byte[] passphrase, byte[] iv) + { + if(cipher==null) cipher=genCipher(); + if(hash==null) hash=genHash(); + + byte[] key=new byte[cipher.getBlockSize()]; + int hsize=hash.getBlockSize(); + byte[] hn=new byte[key.Length/hsize*hsize+ + (key.Length%hsize==0?0:hsize)]; + try + { + byte[] tmp=null; + if(vendor==VENDOR_OPENSSH) + { + for(int index=0; index+hsize<=hn.Length;) + { + if(tmp!=null){ hash.update(tmp, 0, tmp.Length); } + hash.update(passphrase, 0, passphrase.Length); + hash.update(iv, 0, iv.Length); + tmp=hash.digest(); + Array.Copy(tmp, 0, hn, index, tmp.Length); + index+=tmp.Length; + } + Array.Copy(hn, 0, key, 0, key.Length); + } + else if(vendor==VENDOR_FSECURE) + { + for(int index=0; index+hsize<=hn.Length;) + { + if(tmp!=null){ hash.update(tmp, 0, tmp.Length); } + hash.update(passphrase, 0, passphrase.Length); + tmp=hash.digest(); + Array.Copy(tmp, 0, hn, index, tmp.Length); + index+=tmp.Length; + } + Array.Copy(hn, 0, key, 0, key.Length); + } + } + catch(Exception e) + { + Console.WriteLine(e); + } + return key; + } + + public void setPassphrase(String passphrase) + { + if(passphrase==null || passphrase.Length==0) + { + setPassphrase((byte[])null); + } + else + { + setPassphrase(Util.getBytes( passphrase )); + } + } + public void setPassphrase(byte[] passphrase) + { + if(passphrase!=null && passphrase.Length==0) + passphrase=null; + this.passphrase=passphrase; + } + + private bool encrypted=false; + private byte[] data=null; + private byte[] iv=null; + private byte[] publickeyblob=null; + + public bool isEncrypted(){ return encrypted; } + public bool decrypt(String _passphrase) + { + byte[] passphrase= Util.getBytes( _passphrase ); + byte[] foo=decrypt(data, passphrase, iv); + if(parse(foo)) + { + encrypted=false; + } + return !encrypted; + } + + public static KeyPair load(JSch jsch, String prvkey) + { + String pubkey=prvkey+".pub"; +// if(!new File(pubkey).exists()) + if(!File.Exists(pubkey)) + { + pubkey=null; + } + return load(jsch, prvkey, pubkey); + } + public static KeyPair load(JSch jsch, String prvkey, String pubkey) + { + + byte[] iv=new byte[8]; // 8 + bool encrypted=true; + byte[] data=null; + + byte[] publickeyblob=null; + + int type=ERROR; + int vendor=VENDOR_OPENSSH; + + try + { + //File file=new File(prvkey); + FileStream fis=File.OpenRead(prvkey); + byte[] buf=new byte[(int)(fis.Length)]; + int len=fis.Read(buf, 0, buf.Length); + fis.Close(); + + int i=0; + + while(i4 && // FSecure + data[0]==(byte)0x3f && + data[1]==(byte)0x6f && + data[2]==(byte)0xf9 && + data[3]==(byte)0xeb) + { + + Buffer _buf=new Buffer(data); + _buf.getInt(); // 0x3f6ff9be + _buf.getInt(); + byte[]_type=_buf.getString(); + //System.outs.println("type: "+new String(_type)); + byte[] _cipher=_buf.getString(); + String cipher=Util.getString(_cipher); + //System.outs.println("cipher: "+cipher); + if(cipher.Equals("3des-cbc")) + { + _buf.getInt(); + byte[] foo=new byte[data.Length-_buf.getOffSet()]; + _buf.getByte(foo); + data=foo; + encrypted=true; + throw new JSchException("unknown privatekey format: "+prvkey); + } + else if(cipher.Equals("none")) + { + _buf.getInt(); + _buf.getInt(); + + encrypted=false; + + byte[] foo=new byte[data.Length-_buf.getOffSet()]; + _buf.getByte(foo); + data=foo; + } + } + + if(pubkey!=null) + { + try + { + //file=new File(pubkey); + fis=File.OpenRead(pubkey); + buf=new byte[(int)(fis.Length)]; + len=fis.Read(buf, 0, buf.Length); + fis.Close(); + + if(buf.Length>4 && // FSecure's public key + buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-') + { + + bool valid=true; + i=0; + do{i++;}while(buf.Length>i && buf[i]!=0x0a); + if(buf.Length<=i) {valid=false;} + + while(valid) + { + if(buf[i]==0x0a) + { + bool inheader=false; + for(int j=i+1; j0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + + if(plain[index]!=0x02)return false; + index++; // INTEGER + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + P_array=new byte[Length]; + Array.Copy(plain, index, P_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + Q_array=new byte[Length]; + Array.Copy(plain, index, Q_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + G_array=new byte[Length]; + Array.Copy(plain, index, G_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + pub_array=new byte[Length]; + Array.Copy(plain, index, pub_array, 0, Length); + index+=Length; + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + prv_array=new byte[Length]; + Array.Copy(plain, index, prv_array, 0, Length); + index+=Length; + } + catch//(Exception e) + { + //System.out.println(e); + //e.printStackTrace(); + return false; + } + return true; + } + + public override byte[] getPublicKeyBlob() + { + byte[] foo=base.getPublicKeyBlob(); + if(foo!=null) return foo; + + if(P_array==null) return null; + + Buffer buf=new Buffer(sshdss.Length+4+ + P_array.Length+4+ + Q_array.Length+4+ + G_array.Length+4+ + pub_array.Length+4); + buf.putString(sshdss); + buf.putString(P_array); + buf.putString(Q_array); + buf.putString(G_array); + buf.putString(pub_array); + return buf.buffer; + } + + private static byte[] sshdss= Util.getBytes( "ssh-dss" ); + internal override byte[] getKeyTypeName(){return sshdss;} + public override int getKeyType(){return DSA;} + + public override int getKeySize(){return key_size; } + public override void dispose() + { + base.dispose(); + P_array=null; + Q_array=null; + G_array=null; + pub_array=null; + prv_array=null; + } + } + +} diff --git a/SharpSSH/jsch/KeyPairGenDSA.cs b/SharpSSH/jsch/KeyPairGenDSA.cs new file mode 100644 index 00000000..ecdc0f1c --- /dev/null +++ b/SharpSSH/jsch/KeyPairGenDSA.cs @@ -0,0 +1,44 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public interface KeyPairGenDSA + { + void init(int key_size); + byte[] getX(); + byte[] getY(); + byte[] getP(); + byte[] getQ(); + byte[] getG(); + } + +} diff --git a/SharpSSH/jsch/KeyPairGenRSA.cs b/SharpSSH/jsch/KeyPairGenRSA.cs new file mode 100644 index 00000000..aa739cd7 --- /dev/null +++ b/SharpSSH/jsch/KeyPairGenRSA.cs @@ -0,0 +1,48 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public interface KeyPairGenRSA + { + void init(int key_size); + byte[] getD(); + byte[] getE(); + byte[] getN(); + + byte[] getC(); + byte[] getEP(); + byte[] getEQ(); + byte[] getP(); + byte[] getQ(); + } + +} diff --git a/SharpSSH/jsch/KeyPairRSA.cs b/SharpSSH/jsch/KeyPairRSA.cs new file mode 100644 index 00000000..32046634 --- /dev/null +++ b/SharpSSH/jsch/KeyPairRSA.cs @@ -0,0 +1,352 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class KeyPairRSA : KeyPair + { + private byte[] prv_array; + private byte[] pub_array; + private byte[] n_array; + + private byte[] p_array; // prime p + private byte[] q_array; // prime q + private byte[] ep_array; // prime exponent p + private byte[] eq_array; // prime exponent q + private byte[] c_array; // coefficient + + //private int key_size=0; + private int key_size=1024; + + public KeyPairRSA(JSch jsch):base(jsch) + { + } + + internal override void generate(int key_size) + { + this.key_size=key_size; + try + { + Type t=Type.GetType(jsch.getConfig("keypairgen.rsa")); + KeyPairGenRSA keypairgen=(KeyPairGenRSA)(Activator.CreateInstance(t)); + keypairgen.init(key_size); + pub_array=keypairgen.getE(); + prv_array=keypairgen.getD(); + n_array=keypairgen.getN(); + + p_array=keypairgen.getP(); + q_array=keypairgen.getQ(); + ep_array=keypairgen.getEP(); + eq_array=keypairgen.getEQ(); + c_array=keypairgen.getC(); + + keypairgen=null; + } + catch(Exception e) + { + Console.WriteLine("KeyPairRSA: "+e); + throw new JSchException(e.ToString()); + } + } + + private static byte[] begin= Util.getBytes( "-----BEGIN RSA PRIVATE KEY-----"); + private static byte[] end=Util.getBytes("-----END RSA PRIVATE KEY-----"); + + internal override byte[] getBegin(){ return begin; } + internal override byte[] getEnd(){ return end; } + + internal override byte[] getPrivateKey() + { + int content= + 1+countLength(1) + 1 + // INTEGER + 1+countLength(n_array.Length) + n_array.Length + // INTEGER N + 1+countLength(pub_array.Length) + pub_array.Length + // INTEGER pub + 1+countLength(prv_array.Length) + prv_array.Length+ // INTEGER prv + 1+countLength(p_array.Length) + p_array.Length+ // INTEGER p + 1+countLength(q_array.Length) + q_array.Length+ // INTEGER q + 1+countLength(ep_array.Length) + ep_array.Length+ // INTEGER ep + 1+countLength(eq_array.Length) + eq_array.Length+ // INTEGER eq + 1+countLength(c_array.Length) + c_array.Length; // INTEGER c + + int total= + 1+countLength(content)+content; // SEQUENCE + + byte[] plain=new byte[total]; + int index=0; + index=writeSEQUENCE(plain, index, content); + index=writeINTEGER(plain, index, new byte[1]); // 0 + index=writeINTEGER(plain, index, n_array); + index=writeINTEGER(plain, index, pub_array); + index=writeINTEGER(plain, index, prv_array); + index=writeINTEGER(plain, index, p_array); + index=writeINTEGER(plain, index, q_array); + index=writeINTEGER(plain, index, ep_array); + index=writeINTEGER(plain, index, eq_array); + index=writeINTEGER(plain, index, c_array); + return plain; + } + + internal override bool parse(byte [] plain) + { + /* + byte[] p_array; + byte[] q_array; + byte[] dmp1_array; + byte[] dmq1_array; + byte[] iqmp_array; + */ + try + { + int index=0; + int Length=0; + + if(vendor==VENDOR_FSECURE) + { + if(plain[index]!=0x30) + { // FSecure + Buffer buf=new Buffer(plain); + pub_array=buf.getMPIntBits(); + prv_array=buf.getMPIntBits(); + n_array=buf.getMPIntBits(); + byte[] u_array=buf.getMPIntBits(); + p_array=buf.getMPIntBits(); + q_array=buf.getMPIntBits(); + return true; + } + return false; + } + + index++; // SEQUENCE + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + + if(plain[index]!=0x02)return false; + index++; // INTEGER + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + index+=Length; + + //System.out.println("int: len="+Length); + //System.out.print(Integer.toHexString(plain[index-1]&0xff)+":"); + //System.out.println(""); + + index++; + Length=plain[index++]&0xff; + if((Length&0x80)!=0) + { + int foo=Length&0x7f; Length=0; + while(foo-->0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + n_array=new byte[Length]; + Array.Copy(plain, index, n_array, 0, Length); + index+=Length; + /* + System.out.println("int: N len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + pub_array=new byte[Length]; + Array.Copy(plain, index, pub_array, 0, Length); + index+=Length; + /* + System.out.println("int: E len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + prv_array=new byte[Length]; + Array.Copy(plain, index, prv_array, 0, Length); + index+=Length; + /* + System.out.println("int: prv len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + p_array=new byte[Length]; + Array.Copy(plain, index, p_array, 0, Length); + index+=Length; + /* + System.out.println("int: P len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + q_array=new byte[Length]; + Array.Copy(plain, index, q_array, 0, Length); + index+=Length; + /* + System.out.println("int: q len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + ep_array=new byte[Length]; + Array.Copy(plain, index, ep_array, 0, Length); + index+=Length; + /* + System.out.println("int: ep len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + eq_array=new byte[Length]; + Array.Copy(plain, index, eq_array, 0, Length); + index+=Length; + /* + System.out.println("int: eq len="+Length); + for(int i=0; i0){ Length=(Length<<8)+(plain[index++]&0xff); } + } + c_array=new byte[Length]; + Array.Copy(plain, index, c_array, 0, Length); + index+=Length; + /* + System.out.println("int: c len="+Length); + for(int i=0; i=bufl) + { + addInvalidLine(System.Text.Encoding.Default.GetString(buf, 0, bufl)); + goto loop; + } + + sb.Length = 0; + while(j=bufl || host.Length==0) + { + addInvalidLine(System.Text.Encoding.Default.GetString(buf, 0, bufl)); + goto loop; + } + + sb.Length=0; + type=-1; + while(j=bufl) + { + addInvalidLine(Util.getString(buf, 0, bufl)); + goto loop; + } + + sb.Length=0; + while(j>24); +// tmp[1]=(byte)(len>>16); +// tmp[2]=(byte)(len>>8); +// tmp[3]=(byte)(len); +// Array.Copy(tmp, 0, buffer.buffer, 0, 4); +// buffer.buffer[4]=(byte)pad; +// lock(random) +// { +// random.fill(buffer.buffer, buffer.index, pad); +// } +// buffer.skip(pad); +// //buffer.putPad(pad); +// /* +// for(int i=0; i>24); + tmp[1]=(byte)(len>>16); + tmp[2]=(byte)(len>>8); + tmp[3]=(byte)(len); + Array.Copy(tmp, 0, buffer.buffer, 0, 4); + buffer.buffer[4]=(byte)pad; + lock(random) + { + random.fill(buffer.buffer, buffer.index, pad); + } + buffer.skip(pad); + //buffer.putPad(pad); + /* + for(int i=0; i0) + { + socket.setSoTimeout(timeout); + } + socket.setTcpNoDelay(true); + + outs.write(new String("CONNECT "+host+":"+port+" HTTP/1.0\r\n").getBytes()); + + if(user!=null && passwd!=null) + { + byte[] _code=(user+":"+passwd).getBytes(); + _code=Util.toBase64(_code, 0, _code.Length); + outs.write(new String("Proxy-Authorization: Basic ").getBytes()); + outs.write(_code); + outs.write(new String("\r\n").getBytes()); + } + + outs.write(new String("\r\n").getBytes()); + outs.flush(); + + int foo=0; + + StringBuffer sb=new StringBuffer(); + while(foo>=0) + { + foo=ins.read(); if(foo!=13){sb.append((char)foo); continue;} + foo=ins.read(); if(foo!=10){continue;} + break; + } + if(foo<0) + { + throw new System.IO.IOException(); + } + + String response=sb.toString(); + String reason="Unknow reason"; + int code=-1; + try + { + foo=response.indexOf(' '); + int bar=response.indexOf(' ', foo+1); + code=Integer.parseInt(response.substring(foo+1, bar)); + reason=response.substring(bar+1); + } + catch(Exception e) + { + } + if(code!=200) + { + throw new System.IO.IOException("proxy error: "+reason); + } + + /* + while(foo>=0){ + foo=in.read(); if(foo!=13) continue; + foo=in.read(); if(foo!=10) continue; + foo=in.read(); if(foo!=13) continue; + foo=in.read(); if(foo!=10) continue; + break; + } + */ + + int count=0; + while(true) + { + count=0; + while(foo>=0) + { + foo=ins.read(); if(foo!=13){count++; continue;} + foo=ins.read(); if(foo!=10){continue;} + break; + } + if(foo<0) + { + throw new System.IO.IOException(); + } + if(count==0)break; + } + } + catch(RuntimeException e) + { + throw e; + } + catch(Exception e) + { + try{ if(socket!=null)socket.close(); } + catch(Exception eee) + { + } + String message="ProxyHTTP: "+e.toString(); + throw e; + } + } + public Stream getInputStream(){ return ins.s; } + public Stream getOutputStream(){ return outs.s; } + public Socket getSocket(){ return socket; } + public void close() + { + try + { + if(ins!=null)ins.close(); + if(outs!=null)outs.close(); + if(socket!=null)socket.close(); + } + catch(Exception e) + { + } + ins=null; + outs=null; + socket=null; + } + public static int getDefaultPort() + { + return DEFAULTPORT; + } + } +} diff --git a/SharpSSH/jsch/Random.cs b/SharpSSH/jsch/Random.cs new file mode 100644 index 00000000..0df9578a --- /dev/null +++ b/SharpSSH/jsch/Random.cs @@ -0,0 +1,38 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public interface Random + { + void fill(byte[] foo, int start, int len); + } +} diff --git a/SharpSSH/jsch/Request.cs b/SharpSSH/jsch/Request.cs new file mode 100644 index 00000000..6a2b345b --- /dev/null +++ b/SharpSSH/jsch/Request.cs @@ -0,0 +1,39 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + internal interface Request + { + bool waitForReply(); + void request(Session session, Channel channel); + } +} diff --git a/SharpSSH/jsch/RequestExec.cs b/SharpSSH/jsch/RequestExec.cs new file mode 100644 index 00000000..56f56640 --- /dev/null +++ b/SharpSSH/jsch/RequestExec.cs @@ -0,0 +1,62 @@ +using System; +using Str = Tamir.SharpSsh.java.String; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + internal class RequestExec : Request + { + private String command=""; + internal RequestExec(String foo) + { + this.command=foo; + } + public void request(Session session, Channel channel) + { + Packet packet=session.packet; + Buffer buf=session.buf; + // send + // byte SSH_MSG_CHANNEL_REQUEST(98) + // uint32 recipient channel + // string request type // "exec" + // boolean want reply // 0 + // string command + packet.reset(); + buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString(new Str("exec").getBytes()); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putString(new Str(command).getBytes()); + session.write(packet); + } + public bool waitForReply(){ return false; } + } +} diff --git a/SharpSSH/jsch/RequestPtyReq.cs b/SharpSSH/jsch/RequestPtyReq.cs new file mode 100644 index 00000000..80d8553c --- /dev/null +++ b/SharpSSH/jsch/RequestPtyReq.cs @@ -0,0 +1,60 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + class RequestPtyReq : Request + { + void setCode(String cookie) + { + } + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + packet.reset(); + buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString(Util.getBytes("pty-req")); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putString(Util.getBytes("vt100")); + buf.putInt(80); + buf.putInt(24); + buf.putInt(640); + buf.putInt(480); + buf.putString(Util.getBytes("")); + session.write(packet); + } + public bool waitForReply(){ return false; } + } + +} diff --git a/SharpSSH/jsch/RequestSftp.cs b/SharpSSH/jsch/RequestSftp.cs new file mode 100644 index 00000000..0e61ab2b --- /dev/null +++ b/SharpSSH/jsch/RequestSftp.cs @@ -0,0 +1,73 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class RequestSftp : Request + { + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + bool reply=waitForReply(); + if(reply) + { + channel.reply=-1; + } + + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString(Util.getBytes("subsystem")); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putString(Util.getBytes("sftp")); + session.write(packet); + + if(reply) + { + while(channel.reply==-1) + { + try{System.Threading.Thread.Sleep(10);} + catch//(Exception ee) + { + } + } + if(channel.reply==0) + { + throw new JSchException("failed to send sftp request"); + } + } + } + public bool waitForReply(){ return true; } + } + +} diff --git a/SharpSSH/jsch/RequestShell.cs b/SharpSSH/jsch/RequestShell.cs new file mode 100644 index 00000000..9df51494 --- /dev/null +++ b/SharpSSH/jsch/RequestShell.cs @@ -0,0 +1,56 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + class RequestShell : Request + { + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + // send + // byte SSH_MSG_CHANNEL_REQUEST(98) + // uint32 recipient channel + // string request type // "shell" + // boolean want reply // 0 + packet.reset(); + buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString(Util.getBytes("shell")); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + session.write(packet); + } + public bool waitForReply(){ return false; } + } + +} diff --git a/SharpSSH/jsch/RequestSignal.cs b/SharpSSH/jsch/RequestSignal.cs new file mode 100644 index 00000000..321381d8 --- /dev/null +++ b/SharpSSH/jsch/RequestSignal.cs @@ -0,0 +1,54 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + class RequestSignal : Request + { + String signal="KILL"; + public void setSignal(String foo){ signal=foo; } + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + packet.reset(); + buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString( Util.getBytes("signal")); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putString(Util.getBytes(signal)); + session.write(packet); + } + public bool waitForReply(){ return false; } + } + +} diff --git a/SharpSSH/jsch/RequestSubsystem.cs b/SharpSSH/jsch/RequestSubsystem.cs new file mode 100644 index 00000000..d8ae0e90 --- /dev/null +++ b/SharpSSH/jsch/RequestSubsystem.cs @@ -0,0 +1,83 @@ + +using Tamir.SharpSsh.java; +using Tamir.SharpSsh.java.lang; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ + /* + Copyright (c) 2005 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class RequestSubsystem : Request + { + private bool want_reply=true; + private String subsystem=null; + public void request(Session session, Channel channel, String subsystem, bool want_reply) + { + this.subsystem=subsystem; + this.want_reply=want_reply; + this.request(session, channel); + } + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + bool reply=waitForReply(); + if(reply) + { + channel.reply=-1; + } + + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString( new String( "subsystem" ).getBytes()); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putString(subsystem.getBytes()); + session.write(packet); + + if(reply) + { + while(channel.reply==-1) + { + try{Thread.sleep(10);} + catch//(System.Exception ee) + { + } + } + if(channel.reply==0) + { + throw new JSchException("failed to send subsystem request"); + } + } + } + public bool waitForReply(){ return want_reply; } + } + +} diff --git a/SharpSSH/jsch/RequestWindowChange.cs b/SharpSSH/jsch/RequestWindowChange.cs new file mode 100644 index 00000000..491902e5 --- /dev/null +++ b/SharpSSH/jsch/RequestWindowChange.cs @@ -0,0 +1,74 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class RequestWindowChange : Request + { + internal int width_columns=80; + internal int height_rows=24; + internal int width_pixels=640; + internal int height_pixels=480; + public void setSize(int row, int col, int wp, int hp) + { + this.width_columns=row; + this.height_rows=col; + this.width_pixels=wp; + this.height_pixels=hp; + } + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + //byte SSH_MSG_CHANNEL_REQUEST + //uint32 recipient_channel + //string "window-change" + //boolean FALSE + //uint32 terminal width, columns + //uint32 terminal height, rows + //uint32 terminal width, pixels + //uint32 terminal height, pixels + packet.reset(); + buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString(Util.getBytes("window-change")); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putInt(width_columns); + buf.putInt(height_rows); + buf.putInt(width_pixels); + buf.putInt(height_pixels); + session.write(packet); + } + public bool waitForReply(){ return false; } + } + +} diff --git a/SharpSSH/jsch/RequestX11.cs b/SharpSSH/jsch/RequestX11.cs new file mode 100644 index 00000000..23c186e2 --- /dev/null +++ b/SharpSSH/jsch/RequestX11.cs @@ -0,0 +1,67 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + class RequestX11 : Request + { + public void setCookie(String cookie) + { + ChannelX11.cookie=Util.getBytes(cookie); + } + public void request(Session session, Channel channel) + { + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + + // byte SSH_MSG_CHANNEL_REQUEST(98) + // uint32 recipient channel + // string request type // "x11-req" + // boolean want reply // 0 + // boolean single connection + // string x11 authentication protocol // "MIT-MAGIC-COOKIE-1". + // string x11 authentication cookie + // uint32 x11 screen number + packet.reset(); + buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST); + buf.putInt(channel.getRecipient()); + buf.putString(Util.getBytes("x11-req")); + buf.putByte((byte)(waitForReply() ? 1 : 0)); + buf.putByte((byte)0); + buf.putString(Util.getBytes("MIT-MAGIC-COOKIE-1")); + buf.putString(ChannelX11.getFakedCookie(session)); + buf.putInt(0); + session.write(packet); + } + public bool waitForReply(){ return false; } + } + +} diff --git a/SharpSSH/jsch/ServerSocketFactory.cs b/SharpSSH/jsch/ServerSocketFactory.cs new file mode 100644 index 00000000..efd9602c --- /dev/null +++ b/SharpSSH/jsch/ServerSocketFactory.cs @@ -0,0 +1,13 @@ +using System; +using Tamir.SharpSsh.java.net; + +namespace Tamir.SharpSsh.jsch +{ + /// + /// Summary description for ServerSocketFactory. + /// + public interface ServerSocketFactory + { + ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr); + } +} diff --git a/SharpSSH/jsch/Session.cs b/SharpSSH/jsch/Session.cs new file mode 100644 index 00000000..4e046419 --- /dev/null +++ b/SharpSSH/jsch/Session.cs @@ -0,0 +1,1792 @@ +//using System; +using System.IO; +using System.Runtime.CompilerServices; +using Tamir.SharpSsh.java; +using Tamir.SharpSsh.java.util; +using Tamir.SharpSsh.java.net; +using Tamir.SharpSsh.java.lang; +using Exception = System.Exception; +using NullReferenceException = System.NullReferenceException; +using ThreadInterruptedException = System.Threading.ThreadInterruptedException; + +namespace Tamir.SharpSsh.jsch +{ + + + public class Session : Runnable + { + private static String version="SharpSSH-"+Tamir.SharpSsh.SshBase.Version.ToString()+"-JSCH-0.1.28"; + + // http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt + internal const int SSH_MSG_DISCONNECT= 1; + internal const int SSH_MSG_IGNORE= 2; + internal const int SSH_MSG_UNIMPLEMENTED= 3; + internal const int SSH_MSG_DEBUG= 4; + internal const int SSH_MSG_SERVICE_REQUEST= 5; + internal const int SSH_MSG_SERVICE_ACCEPT= 6; + internal const int SSH_MSG_KEXINIT= 20; + internal const int SSH_MSG_NEWKEYS= 21; + internal const int SSH_MSG_KEXDH_INIT= 30; + internal const int SSH_MSG_KEXDH_REPLY= 31; + internal const int SSH_MSG_KEX_DH_GEX_GROUP= 31; + internal const int SSH_MSG_KEX_DH_GEX_INIT= 32; + internal const int SSH_MSG_KEX_DH_GEX_REPLY= 33; + internal const int SSH_MSG_KEX_DH_GEX_REQUEST= 34; + internal const int SSH_MSG_USERAUTH_REQUEST= 50; + internal const int SSH_MSG_USERAUTH_FAILURE= 51; + internal const int SSH_MSG_USERAUTH_SUCCESS= 52; + internal const int SSH_MSG_USERAUTH_BANNER= 53; + internal const int SSH_MSG_USERAUTH_INFO_REQUEST= 60; + internal const int SSH_MSG_USERAUTH_INFO_RESPONSE= 61; + internal const int SSH_MSG_USERAUTH_PK_OK= 60; + internal const int SSH_MSG_GLOBAL_REQUEST= 80; + internal const int SSH_MSG_REQUEST_SUCCESS= 81; + internal const int SSH_MSG_REQUEST_FAILURE= 82; + internal const int SSH_MSG_CHANNEL_OPEN= 90; + internal const int SSH_MSG_CHANNEL_OPEN_CONFIRMATION= 91; + internal const int SSH_MSG_CHANNEL_OPEN_FAILURE= 92; + internal const int SSH_MSG_CHANNEL_WINDOW_ADJUST= 93; + internal const int SSH_MSG_CHANNEL_DATA= 94; + internal const int SSH_MSG_CHANNEL_EXTENDED_DATA= 95; + internal const int SSH_MSG_CHANNEL_EOF= 96; + internal const int SSH_MSG_CHANNEL_CLOSE= 97; + internal const int SSH_MSG_CHANNEL_REQUEST= 98; + internal const int SSH_MSG_CHANNEL_SUCCESS= 99; + internal const int SSH_MSG_CHANNEL_FAILURE= 100; + + private byte[] V_S; // server version + private byte[] V_C=("SSH-2.0-"+version).getBytes(); // client version + + private byte[] I_C; // the payload of the client's SSH_MSG_KEXINIT + private byte[] I_S; // the payload of the server's SSH_MSG_KEXINIT + private byte[] K_S; // the host key + + private byte[] session_id; + + private byte[] IVc2s; + private byte[] IVs2c; + private byte[] Ec2s; + private byte[] Es2c; + private byte[] MACc2s; + private byte[] MACs2c; + + private int seqi=0; + private int seqo=0; + + private Cipher s2ccipher; + private Cipher c2scipher; + private MAC s2cmac; + private MAC c2smac; + private byte[] mac_buf; + + private Compression deflater; + private Compression inflater; + + private IO io; + private Socket socket; + private int timeout=0; + + private bool _isConnected=false; + + private bool isAuthed=false; + + private Thread connectThread=null; + + internal bool x11_forwarding=false; + + internal Stream In=null; + internal Stream Out=null; + + internal static Random random; + + internal Buffer buf; + internal Packet packet; + + internal SocketFactory socket_factory=null; + + private Hashtable config=null; + + private Proxy proxy=null; + private UserInfo userinfo; + + internal String host="127.0.0.1"; + internal int port=22; + + internal String username=null; + internal String password=null; + + internal JSch jsch; + + internal Session(JSch jsch) + { + ; + this.jsch=jsch; + buf=new Buffer(); + packet=new Packet(buf); + } + + public void connect() + { + connect(timeout); + } + + public void connect(int connectTimeout) + { + if(_isConnected) + { + throw new JSchException("session is already connected"); + } + io=new IO(); + if(random==null) + { + try + { + Class c=Class.forName(getConfig("random")); + random=(Random)(c.newInstance()); + } + catch(Exception e) + { + System.Console.Error.WriteLine("connect: random "+e); + } + } + Packet.setRandom(random); + + try + { + int i, j; + int pad=0; + + if(proxy==null) + { + proxy=jsch.getProxy(host); + if(proxy!=null) + { + lock(proxy) + { + proxy.close(); + } + } + } + + if(proxy==null) + { + Stream In; + Stream Out; + if(socket_factory==null) + { + socket=Util.createSocket(host, port, connectTimeout); + In=socket.getInputStream(); + Out=socket.getOutputStream(); + } + else + { + socket=socket_factory.createSocket(host, port); + In=socket_factory.getInputStream(socket); + Out=socket_factory.getOutputStream(socket); + } + //if(timeout>0){ socket.setSoTimeout(timeout); } + socket.setTcpNoDelay(true); + io.setInputStream(In); + io.setOutputStream(Out); + } + else + { + lock(proxy) + { + proxy.connect(socket_factory, host, port, connectTimeout); + io.setInputStream(proxy.getInputStream()); + io.setOutputStream(proxy.getOutputStream()); + socket=proxy.getSocket(); + } + } + + if(connectTimeout>0 && socket!=null) + { + socket.setSoTimeout(connectTimeout); + } + + _isConnected=true; + + while(true) + { + + i=0; + j=0; + while(i4 && (i!=buf.buffer.Length) && + (buf.buffer[0]!='S'||buf.buffer[1]!='S'|| + buf.buffer[2]!='H'||buf.buffer[3]!='-')) + { + //System.err.println(new String(buf.buffer, 0, i); + continue; + } + + if(i==buf.buffer.Length || + i<7 || // SSH-1.99 or SSH-2.0 + (buf.buffer[4]=='1' && buf.buffer[6]!='9') // SSH-1.5 + ) + { + throw new JSchException("invalid server's version String"); + } + break; + } + + V_S=new byte[i]; Tamir.SharpSsh.java.System.arraycopy(buf.buffer, 0, V_S, 0, i); + //System.Console.WriteLine("V_S: ("+i+") ["+new String(V_S)+"]"); + + //io.put(V_C, 0, V_C.Length); io.put("\n".getBytes(), 0, 1); + { + // Some Cisco devices will miss to read '\n' if it is sent separately. + byte[] foo=new byte[V_C.Length+1]; + Tamir.SharpSsh.java.System.arraycopy(V_C, 0, foo, 0, V_C.Length); + foo[foo.Length-1]=(byte)'\n'; + io.put(foo, 0, foo.Length); + } + + buf=read(buf); + //System.Console.WriteLine("read: 20 ? "+buf.buffer[5]); + if(buf.buffer[5]!=SSH_MSG_KEXINIT) + { + throw new JSchException("invalid protocol: "+buf.buffer[5]); + } + KeyExchange kex=receive_kexinit(buf); + + while(true) + { + buf=read(buf); + if(kex.getState()==buf.buffer[5]) + { + bool result=kex.next(buf); + if(!result) + { + //System.Console.WriteLine("verify: "+result); + in_kex=false; + throw new JSchException("verify: "+result); + } + } + else + { + in_kex=false; + throw new JSchException("invalid protocol(kex): "+buf.buffer[5]); + } + if(kex.getState()==KeyExchange.STATE_END) + { + break; + } + } + + try{ checkHost(host, kex); } + catch(JSchException ee) + { + in_kex=false; + throw ee; + } + + send_newkeys(); + + // receive SSH_MSG_NEWKEYS(21) + buf=read(buf); + //System.Console.WriteLine("read: 21 ? "+buf.buffer[5]); + if(buf.buffer[5]==SSH_MSG_NEWKEYS) + { + receive_newkeys(buf, kex); + } + else + { + in_kex=false; + throw new JSchException("invalid protocol(newkyes): "+buf.buffer[5]); + } + + bool auth=false; + bool auth_cancel=false; + + UserAuthNone usn=new UserAuthNone(userinfo); + auth=usn.start(this); + + String methods=null; + if(!auth) + { + methods=usn.getMethods(); + if(methods!=null) + { + methods=methods.toLowerCase(); + } + else + { + // methods: publickey,password,keyboard-interactive + methods="publickey,password,keyboard-interactive"; + } + } + + loop: + while(true) + { + + //System.Console.WriteLine("methods: "+methods); + + while(!auth && + methods!=null && methods.Length()>0) + { + + //System.Console.WriteLine(" methods: "+methods); + + UserAuth us=null; + if(methods.startsWith("publickey")) + { + //System.Console.WriteLine(" jsch.identities.size()="+jsch.identities.size()); + lock(jsch.identities) + { + if(jsch.identities.size()>0) + { + us=new UserAuthPublicKey(userinfo); + } + } + } + else if(methods.startsWith("keyboard-interactive")) + { + if(userinfo is UIKeyboardInteractive) + { + us=new UserAuthKeyboardInteractive(userinfo); + } + } + else if(methods.startsWith("password")) + { + us=new UserAuthPassword(userinfo); + } + if(us!=null) + { + try + { + auth=us.start(this); + auth_cancel=false; + } + catch(JSchAuthCancelException ee) + { + //System.Console.WriteLine(ee); + auth_cancel=true; + } + catch(JSchPartialAuthException ee) + { + methods=ee.getMethods(); + //System.Console.WriteLine("PartialAuth: "+methods); + auth_cancel=false; + continue;//loop; + } + catch(RuntimeException ee) + { + throw ee; + } + catch(Exception ee) + { + System.Console.WriteLine("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures + } + } + if(!auth) + { + int comma=methods.indexOf(","); + if(comma==-1) break; + methods=methods.subString(comma+1); + } + } + break; + } + + if(connectTimeout>0 || timeout>0) + { + socket.setSoTimeout(timeout); + } + + if(auth) + { + isAuthed=true; + connectThread=new Thread(this); + connectThread.setName("Connect thread "+host+" session"); + connectThread.start(); + return; + } + if(auth_cancel) + throw new JSchException("Auth cancel"); + throw new JSchException("Auth fail"); + } + catch(Exception e) + { + in_kex=false; + if(_isConnected) + { + try + { + packet.reset(); + buf.putByte((byte)SSH_MSG_DISCONNECT); + buf.putInt(3); + buf.putString(new String(e.ToString()).getBytes()); + buf.putString(new String("en").getBytes()); + write(packet); + disconnect(); + } + catch(Exception ee) + { + } + } + _isConnected=false; + //e.printStackTrace(); + if(e is RuntimeException) throw (RuntimeException)e; + if(e is JSchException) throw (JSchException)e; + throw new JSchException("Session.connect: "+e); + } + } + + private KeyExchange receive_kexinit(Buffer buf) + { + int j=buf.getInt(); + if(j!=buf.getLength()) + { // packet was compressed and + buf.getByte(); // j is the size of deflated packet. + I_S=new byte[buf.index-5]; + } + else + { + I_S=new byte[j-1-buf.getByte()]; + } + Tamir.SharpSsh.java.System.arraycopy(buf.buffer, buf.s, I_S, 0, I_S.Length); + /* + try{ + byte[] tmp=new byte[I_S.Length]; + Tamir.SharpSsh.java.System.arraycopy(I_S, 0, tmp, 0, I_S.Length); + Buffer tmpb=new Buffer(tmp); + System.Console.WriteLine("I_S: len="+I_S.Length); + tmpb.setOffSet(17); + System.Console.WriteLine("kex: "+new String(tmpb.getString())); + System.Console.WriteLine("server_host_key: "+new String(tmpb.getString())); + System.Console.WriteLine("cipher.c2s: "+new String(tmpb.getString())); + System.Console.WriteLine("cipher.s2c: "+new String(tmpb.getString())); + System.Console.WriteLine("mac.c2s: "+new String(tmpb.getString())); + System.Console.WriteLine("mac.s2c: "+new String(tmpb.getString())); + System.Console.WriteLine("compression.c2s: "+new String(tmpb.getString())); + System.Console.WriteLine("compression.s2c: "+new String(tmpb.getString())); + System.Console.WriteLine("lang.c2s: "+new String(tmpb.getString())); + System.Console.WriteLine("lang.s2c: "+new String(tmpb.getString())); + System.Console.WriteLine("?: "+(tmpb.getByte()&0xff)); + System.Console.WriteLine("??: "+tmpb.getInt()); + } + catch(Exception e){ + System.Console.WriteLine(e); + } + */ + + send_kexinit(); + String[] guess=KeyExchange.guess(I_S, I_C); + if(guess==null) + { + throw new JSchException("Algorithm negotiation fail"); + } + + if(!isAuthed && + (guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS].equals("none") || + (guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC].equals("none")))) + { + throw new JSchException("NONE Cipher should not be chosen before authentification is successed."); + } + + KeyExchange kex=null; + try + { + Class c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_KEX_ALGS])); + kex=(KeyExchange)(c.newInstance()); + } + catch(Exception e){ System.Console.Error.WriteLine("kex: "+e); } + kex._guess=guess; + kex.init(this, V_S, V_C, I_S, I_C); + return kex; + } + + private bool in_kex=false; + public void rekey() + { + send_kexinit(); + } + private void send_kexinit() + { + if(in_kex) return; + in_kex=true; + + // byte SSH_MSG_KEXINIT(20) + // byte[16] cookie (random bytes) + // String kex_algorithms + // String server_host_key_algorithms + // String encryption_algorithms_client_to_server + // String encryption_algorithms_server_to_client + // String mac_algorithms_client_to_server + // String mac_algorithms_server_to_client + // String compression_algorithms_client_to_server + // String compression_algorithms_server_to_client + // String languages_client_to_server + // String languages_server_to_client + packet.reset(); + buf.putByte((byte) SSH_MSG_KEXINIT); + lock(random) + { + random.fill(buf.buffer, buf.index, 16); buf.skip(16); + } + buf.putString(getConfig("kex").getBytes()); + buf.putString(getConfig("server_host_key").getBytes()); + buf.putString(getConfig("cipher.c2s").getBytes()); + buf.putString(getConfig("cipher.s2c").getBytes()); + buf.putString(getConfig("mac.c2s").getBytes()); + buf.putString(getConfig("mac.s2c").getBytes()); + buf.putString(getConfig("compression.c2s").getBytes()); + buf.putString(getConfig("compression.s2c").getBytes()); + buf.putString(getConfig("lang.c2s").getBytes()); + buf.putString(getConfig("lang.s2c").getBytes()); + buf.putByte((byte)0); + buf.putInt(0); + + buf.setOffSet(5); + I_C=new byte[buf.getLength()]; + buf.getByte(I_C); + + write(packet); + } + + private void send_newkeys() + { + // send SSH_MSG_NEWKEYS(21) + packet.reset(); + buf.putByte((byte)SSH_MSG_NEWKEYS); + write(packet); + } + + private void checkHost(String host, KeyExchange kex) + { + String shkc=getConfig("StrictHostKeyChecking"); + + //System.Console.WriteLine("shkc: "+shkc); + + byte[] K_S=kex.getHostKey(); + String key_type=kex.getKeyType(); + String key_fprint=kex.getFingerPrint(); + + hostkey=new HostKey(host, K_S); + + HostKeyRepository hkr=jsch.getHostKeyRepository(); + int i=0; + lock(hkr) + { + i=hkr.check(host, K_S); + } + + bool insert=false; + + if((shkc.equals("ask") || shkc.equals("yes")) && + i==HostKeyRepository.CHANGED) + { + String file=null; + lock(hkr) + { + file=hkr.getKnownHostsRepositoryID(); + } + if(file==null){file="known_hosts";} + String message= + "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"+ + "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"+ + "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"+ + "It is also possible that the "+key_type+" host key has just been changed.\n"+ + "The fingerprint for the "+key_type+" key sent by the remote host is\n"+ + key_fprint+".\n"+ + "Please contact your system administrator.\n"+ + "Add correct host key in "+file+" to get rid of this message."; + + bool b=false; + + if(userinfo!=null) + { + //userinfo.showMessage(message); + b=userinfo.promptYesNo(message+ + "\nDo you want to delete the old key and insert the new key?"); + } + //throw new JSchException("HostKey has been changed: "+host); + if(!b) + { + throw new JSchException("HostKey has been changed: "+host); + } + else + { + lock(hkr) + { + hkr.remove(host, + (key_type.equals("DSA") ? "ssh-dss" : "ssh-rsa"), + null); + insert=true; + } + } + } + + // bool insert=false; + + if((shkc.equals("ask") || shkc.equals("yes")) && + (i!=HostKeyRepository.OK) && !insert) + { + if(shkc.equals("yes")) + { + throw new JSchException("reject HostKey: "+host); + } + //System.Console.WriteLine("finger-print: "+key_fprint); + if(userinfo!=null) + { + bool foo=userinfo.promptYesNo( + "The authenticity of host '"+host+"' can't be established.\n"+ + key_type+" key fingerprint is "+key_fprint+".\n"+ + "Are you sure you want to continue connecting?" + ); + if(!foo) + { + throw new JSchException("reject HostKey: "+host); + } + insert=true; + } + else + { + if(i==HostKeyRepository.NOT_INCLUDED) + throw new JSchException("UnknownHostKey: "+host+". "+key_type+" key fingerprint is "+key_fprint); + else throw new JSchException("HostKey has been changed: "+host); + } + } + + if(shkc.equals("no") && + HostKeyRepository.NOT_INCLUDED==i) + { + insert=true; + } + + if(insert) + { + lock(hkr) + { + hkr.add(host, K_S, userinfo); + } + } + + } + + //public void start(){ (new Thread(this)).start(); } + + public Channel openChannel(String type) + { + if(!_isConnected) + { + throw new JSchException("session is down"); + } + try + { + Channel channel=Channel.getChannel(type); + addChannel(channel); + channel.init(); + return channel; + } + catch(Exception e) + { + System.Console.WriteLine(e); + } + return null; + } + + // encode will bin invoked in write with synchronization. + public void encode(Packet packet) + { + //System.Console.WriteLine("encode: "+packet.buffer.buffer[5]); + //System.Console.WriteLine(" "+packet.buffer.index); + //if(packet.buffer.buffer[5]==96){ + //Thread.dumpStack(); + //} + if(deflater!=null) + { + packet.buffer.index=deflater.compress(packet.buffer.buffer, + 5, packet.buffer.index); + } + if(c2scipher!=null) + { + packet.padding(c2scipher.getIVSize()); + int pad=packet.buffer.buffer[4]; + lock(random) + { + random.fill(packet.buffer.buffer, packet.buffer.index-pad, pad); + } + } + else + { + packet.padding(8); + } + byte[] mac=null; + if(c2smac!=null) + { + c2smac.update(seqo); + c2smac.update(packet.buffer.buffer, 0, packet.buffer.index); + mac=c2smac.doFinal(); + } + if(c2scipher!=null) + { + byte[] buf=packet.buffer.buffer; + c2scipher.update(buf, 0, packet.buffer.index, buf, 0); + } + if(mac!=null) + { + packet.buffer.putByte(mac); + } + } + + int[] uncompress_len=new int[1]; + + private int cipher_size=8; + public Buffer read(Buffer buf) + { + int j=0; + while(true) + { + buf.reset(); + io.getByte(buf.buffer, buf.index, cipher_size); buf.index+=cipher_size; + if(s2ccipher!=null) + { + s2ccipher.update(buf.buffer, 0, cipher_size, buf.buffer, 0); + } +// j=((buf.buffer[0]<<24)&0xff000000)| +// ((buf.buffer[1]<<16)&0x00ff0000)| +// ((buf.buffer[2]<< 8)&0x0000ff00)| +// ((buf.buffer[3] )&0x000000ff); + j=Util.ToInt32( buf.buffer, 0 ); + j=j-4-cipher_size+8; + if(j<0 || (buf.index+j)>buf.buffer.Length) + { + throw new IOException("invalid data"); + } + if(j>0) + { + io.getByte(buf.buffer, buf.index, j); buf.index+=(j); + if(s2ccipher!=null) + { + s2ccipher.update(buf.buffer, cipher_size, j, buf.buffer, cipher_size); + } + } + + if(s2cmac!=null) + { + s2cmac.update(seqi); + s2cmac.update(buf.buffer, 0, buf.index); + byte[] result=s2cmac.doFinal(); + io.getByte(mac_buf, 0, mac_buf.Length); + if(!Arrays.equals(result, mac_buf)) + { + throw new IOException("MAC Error"); + } + } + seqi++; + + if(inflater!=null) + { + //inflater.uncompress(buf); + int pad=buf.buffer[4]; + uncompress_len[0]=buf.index-5-pad; + byte[] foo=inflater.uncompress(buf.buffer, 5, uncompress_len); + if(foo!=null) + { + buf.buffer=foo; + buf.index=5+uncompress_len[0]; + } + else + { + System.Console.Error.WriteLine("fail in inflater"); + break; + } + } + + int type=buf.buffer[5]&0xff; + //System.Console.WriteLine("read: "+type); + if(type==SSH_MSG_DISCONNECT) + { + buf.rewind(); + buf.getInt();buf.getShort(); + int reason_code=buf.getInt(); + byte[] description=buf.getString(); + byte[] language_tag=buf.getString(); + /* + System.Console.Error.WriteLine("SSH_MSG_DISCONNECT:"+ + " "+reason_code+ + " "+new String(description)+ + " "+new String(language_tag)); + */ + throw new JSchException("SSH_MSG_DISCONNECT:"+ + " "+reason_code+ + " "+new String(description)+ + " "+new String(language_tag)); + //break; + } + else if(type==SSH_MSG_IGNORE) + { + } + else if(type==SSH_MSG_DEBUG) + { + buf.rewind(); + buf.getInt();buf.getShort(); + /* + byte always_display=(byte)buf.getByte(); + byte[] message=buf.getString(); + byte[] language_tag=buf.getString(); + System.Console.Error.WriteLine("SSH_MSG_DEBUG:"+ + " "+new String(message)+ + " "+new String(language_tag)); + */ + } + else if(type==SSH_MSG_CHANNEL_WINDOW_ADJUST) + { + buf.rewind(); + buf.getInt();buf.getShort(); + Channel c=Channel.getChannel(buf.getInt(), this); + if(c==null) + { + } + else + { + c.addRemoteWindowSize(buf.getInt()); + } + } + else + { + break; + } + } + buf.rewind(); + return buf; + } + + internal byte[] getSessionId() + { + return session_id; + } + + private void receive_newkeys(Buffer buf, KeyExchange kex) + { + // send_newkeys(); + updateKeys(kex); + in_kex=false; + } + private void updateKeys(KeyExchange kex) + { + byte[] K=kex.getK(); + byte[] H=kex.getH(); + HASH hash=kex.getHash(); + + String[] guess=kex._guess; + + if(session_id==null) + { + session_id=new byte[H.Length]; + Tamir.SharpSsh.java.System.arraycopy(H, 0, session_id, 0, H.Length); + } + + /* + Initial IV client to server: HASH (K || H || "A" || session_id) + Initial IV server to client: HASH (K || H || "B" || session_id) + Encryption key client to server: HASH (K || H || "C" || session_id) + Encryption key server to client: HASH (K || H || "D" || session_id) + Integrity key client to server: HASH (K || H || "E" || session_id) + Integrity key server to client: HASH (K || H || "F" || session_id) + */ + + buf.reset(); + buf.putMPInt(K); + buf.putByte(H); + buf.putByte((byte)0x41); + buf.putByte(session_id); + hash.update(buf.buffer, 0, buf.index); + IVc2s=hash.digest(); + + int j=buf.index-session_id.Length-1; + + buf.buffer[j]++; + hash.update(buf.buffer, 0, buf.index); + IVs2c=hash.digest(); + + buf.buffer[j]++; + hash.update(buf.buffer, 0, buf.index); + Ec2s=hash.digest(); + + buf.buffer[j]++; + hash.update(buf.buffer, 0, buf.index); + Es2c=hash.digest(); + + buf.buffer[j]++; + hash.update(buf.buffer, 0, buf.index); + MACc2s=hash.digest(); + + buf.buffer[j]++; + hash.update(buf.buffer, 0, buf.index); + MACs2c=hash.digest(); + + try + { + Class c; + + c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC])); + s2ccipher=(Cipher)(c.newInstance()); + while(s2ccipher.getBlockSize()>Es2c.Length) + { + buf.reset(); + buf.putMPInt(K); + buf.putByte(H); + buf.putByte(Es2c); + hash.update(buf.buffer, 0, buf.index); + byte[] foo=hash.digest(); + byte[] bar=new byte[Es2c.Length+foo.Length]; + Tamir.SharpSsh.java.System.arraycopy(Es2c, 0, bar, 0, Es2c.Length); + Tamir.SharpSsh.java.System.arraycopy(foo, 0, bar, Es2c.Length, foo.Length); + Es2c=bar; + } + s2ccipher.init(Cipher.DECRYPT_MODE, Es2c, IVs2c); + cipher_size=s2ccipher.getIVSize(); + c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC])); + s2cmac=(MAC)(c.newInstance()); + s2cmac.init(MACs2c); + mac_buf=new byte[s2cmac.getBlockSize()]; + + c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS])); + c2scipher=(Cipher)(c.newInstance()); + while(c2scipher.getBlockSize()>Ec2s.Length) + { + buf.reset(); + buf.putMPInt(K); + buf.putByte(H); + buf.putByte(Ec2s); + hash.update(buf.buffer, 0, buf.index); + byte[] foo=hash.digest(); + byte[] bar=new byte[Ec2s.Length+foo.Length]; + Tamir.SharpSsh.java.System.arraycopy(Ec2s, 0, bar, 0, Ec2s.Length); + Tamir.SharpSsh.java.System.arraycopy(foo, 0, bar, Ec2s.Length, foo.Length); + Ec2s=bar; + } + c2scipher.init(Cipher.ENCRYPT_MODE, Ec2s, IVc2s); + + c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS])); + c2smac=(MAC)(c.newInstance()); + c2smac.init(MACc2s); + + if(!guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS].equals("none")) + { + String foo=getConfig(guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS]); + if(foo!=null) + { + try + { + c=Class.forName(foo); + deflater=(Compression)(c.newInstance()); + int level=6; + try{ level=Integer.parseInt(getConfig("compression_level"));} + catch(Exception ee){ } + deflater.init(Compression.DEFLATER, level); + } + catch(Exception ee) + { + System.Console.Error.WriteLine(foo+" isn't accessible."); + } + } + } + else + { + if(deflater!=null) + { + deflater=null; + } + } + if(!guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC].equals("none")) + { + String foo=getConfig(guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC]); + if(foo!=null) + { + try + { + c=Class.forName(foo); + inflater=(Compression)(c.newInstance()); + inflater.init(Compression.INFLATER, 0); + } + catch(Exception ee) + { + System.Console.Error.WriteLine(foo+" isn't accessible."); + } + } + } + else + { + if(inflater!=null) + { + inflater=null; + } + } + } + catch(Exception e){ System.Console.Error.WriteLine("updatekeys: "+e); } + } + + public void write(Packet packet, Channel c, int length) + { + while(true) + { + if(in_kex) + { + try{Thread.Sleep(10);} + catch(ThreadInterruptedException e){}; + continue; + } + lock(c) + { + if(c.rwsize>=length) + { + c.rwsize-=length; + break; + } + } + if(c._close || !c.isConnected()) + { + throw new IOException("channel is broken"); + } + + bool sendit=false; + int s=0; + byte command=0; + int recipient=-1; + lock(c) + { + if(c.rwsize>0) + { + int len=c.rwsize; + if(len>length) + { + len=length; + } + if(len!=length) + { + s=packet.shift(len, (c2smac!=null ? c2smac.getBlockSize() : 0)); + } + command=packet.buffer.buffer[5]; + recipient=c.getRecipient(); + length-=len; + c.rwsize-=len; + sendit=true; + } + } + if(sendit) + { + _write(packet); + if(length==0) + { + return; + } + packet.unshift(command, recipient, s, length); + lock(c) + { + if(c.rwsize>=length) + { + c.rwsize-=length; + break; + } + } + } + + try{Thread.Sleep(100);} + catch(ThreadInterruptedException e){}; + } + _write(packet); + } + /* + public lockpublic void write(Packet packet) { + encode(packet); + if(io!=null){ + io.put(packet); + seqo++; + } + } + */ + public void write(Packet packet) + { + // System.Console.WriteLine("in_kex="+in_kex+" "+(packet.buffer.buffer[5])); + while(in_kex) + { + byte command=packet.buffer.buffer[5]; + //System.Console.WriteLine("command: "+command); + if(command==SSH_MSG_KEXINIT || + command==SSH_MSG_NEWKEYS || + command==SSH_MSG_KEXDH_INIT || + command==SSH_MSG_KEXDH_REPLY || + command==SSH_MSG_DISCONNECT || + command==SSH_MSG_KEX_DH_GEX_GROUP || + command==SSH_MSG_KEX_DH_GEX_INIT || + command==SSH_MSG_KEX_DH_GEX_REPLY || + command==SSH_MSG_KEX_DH_GEX_REQUEST) + { + break; + } + try{Thread.Sleep(10);} + catch(ThreadInterruptedException e){}; + } + _write(packet); + } + [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.Synchronized)] + private void _write(Packet packet) + { + encode(packet); + if(io!=null) + { + io.put(packet); + seqo++; + } + } + + Runnable thread; + public void run() + { + thread=this; + + byte[] foo; + Buffer buf=new Buffer(); + Packet packet=new Packet(buf); + int i=0; + Channel channel; + int[] start=new int[1]; + int[] length=new int[1]; + KeyExchange kex=null; + + try + { + while(_isConnected && + thread!=null) + { + buf=read(buf); + int msgType=buf.buffer[5]&0xff; + // if(msgType!=94) + //System.Console.WriteLine("read: 94 ? "+msgType); + + if(kex!=null && kex.getState()==msgType) + { + bool result=kex.next(buf); + if(!result) + { + throw new JSchException("verify: "+result); + } + continue; + } + + switch(msgType) + { + case SSH_MSG_KEXINIT: + //System.Console.WriteLine("KEXINIT"); + kex=receive_kexinit(buf); + break; + + case SSH_MSG_NEWKEYS: + //System.Console.WriteLine("NEWKEYS"); + send_newkeys(); + receive_newkeys(buf, kex); + kex=null; + break; + + case SSH_MSG_CHANNEL_DATA: + buf.getInt(); + buf.getByte(); + buf.getByte(); + i=buf.getInt(); + channel=Channel.getChannel(i, this); + foo=buf.getString(start, length); + if(channel==null) + { + break; + } + try + { + channel.write(foo, start[0], length[0]); + } + catch(Exception e) + { + //System.Console.WriteLine(e); + try{channel.disconnect();} + catch(Exception ee){} + break; + } + int len=length[0]; + channel.setLocalWindowSize(channel.lwsize-len); + if(channel.lwsize0) + { + attr.extended=new String[count*2]; + for(int i=0; i0) + { + for(int i=0; i0) + { + for(int i=0; i0 + ||(name.Length>0 || instruction.Length>0) + ){ + UIKeyboardInteractive kbi=(UIKeyboardInteractive)userinfo; + if(userinfo!=null){ + response=kbi.promptKeyboardInteractive(dest, + name, + instruction, + prompt, + echo); + } + } + // byte SSH_MSG_USERAUTH_INFO_RESPONSE(61) + // int num-responses + // string response[1] (ISO-10646 UTF-8) + // ... + // string response[num-responses] (ISO-10646 UTF-8) +//if(response!=null) +//System.out.println("response.length="+response.length); +//else +//System.out.println("response is null"); + packet.reset(); + buf.putByte((byte)Session.SSH_MSG_USERAUTH_INFO_RESPONSE); + if(num>0 && + (response==null || // cancel + num!=response.Length)){ + buf.putInt(0); + if(response==null) + cancel=true; + } + else{ + buf.putInt(num); + for(int i=0; i>24); + tmp[1]=(byte)(sidlen>>16); + tmp[2]=(byte)(sidlen>>8); + tmp[3]=(byte)(sidlen); + Array.Copy(sid, 0, tmp, 4, sidlen); + Array.Copy(buf.buffer, 5, tmp, 4+sidlen, buf.index-5); + + byte[] signature=identity.getSignature(session, tmp); + if(signature==null) + { // for example, too long key length. + break; + } + buf.putString(signature); + + session.write(packet); + + loop2: + while(true) + { + // receive + // byte SSH_MSG_USERAUTH_SUCCESS(52) + // string service name + buf=session.read(buf); + //System.out.println("read: 52 ? "+ buf.buffer[5]); + if(buf.buffer[5]==Session.SSH_MSG_USERAUTH_SUCCESS) + { + return true; + } + else if(buf.buffer[5]==Session.SSH_MSG_USERAUTH_BANNER) + { + buf.getInt(); buf.getByte(); buf.getByte(); + byte[] _message=buf.getString(); + byte[] lang=buf.getString(); + String message=null; + try{ message=Util.getStringUTF8(_message); } + catch + {//(java.io.UnsupportedEncodingException e){ + message=Util.getString(_message); + } + if(userinfo!=null) + { + userinfo.showMessage(message); + } + goto loop2; + } + else if(buf.buffer[5]==Session.SSH_MSG_USERAUTH_FAILURE) + { + buf.getInt(); buf.getByte(); buf.getByte(); + byte[] foo=buf.getString(); + int partial_success=buf.getByte(); + //System.out.println(new String(foo)+ + // " partial_success:"+(partial_success!=0)); + if(partial_success!=0) + { + throw new JSchPartialAuthException(Util.getString(foo)); + } + break; + } + //System.out.println("USERAUTH fail ("+buf.buffer[5]+")"); + //throw new JSchException("USERAUTH fail ("+buf.buffer[5]+")"); + break; + } + } + return false; + } + } + +} diff --git a/SharpSSH/jsch/UserInfo.cs b/SharpSSH/jsch/UserInfo.cs new file mode 100644 index 00000000..b3a36519 --- /dev/null +++ b/SharpSSH/jsch/UserInfo.cs @@ -0,0 +1,43 @@ +using System; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public interface UserInfo + { + String getPassphrase(); + String getPassword(); + bool promptPassword(String message); + bool promptPassphrase(String message); + bool promptYesNo(String message); + void showMessage(String message); + } +} diff --git a/SharpSSH/jsch/Util.cs b/SharpSSH/jsch/Util.cs new file mode 100644 index 00000000..689b54fc --- /dev/null +++ b/SharpSSH/jsch/Util.cs @@ -0,0 +1,580 @@ +using System; +using System.Threading; + +namespace Tamir.SharpSsh.jsch +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + + public class Util + { + + /// + /// Converts a time_t to DateTime + /// + public static DateTime Time_T2DateTime(uint time_t) + { + long win32FileTime = 10000000*(long)time_t + 116444736000000000; + return DateTime.FromFileTimeUtc(win32FileTime).ToLocalTime(); + } + + private static byte[] b64 = System.Text.Encoding.Default.GetBytes( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); + private static byte val(byte foo) + { + if(foo == '=') return 0; + for(int j=0; j>4)); + if(buf[i+2]==(byte)'='){ j++; break;} + foo[j+1]=(byte)(((val(buf[i+1])&0x0f)<<4)|((val(buf[i+2])&0x3c)>>2)); + if(buf[i+3]==(byte)'='){ j+=2; break;} + foo[j+2]=(byte)(((val(buf[i+2])&0x03)<<6)|(val(buf[i+3])&0x3f)); + j+=3; + } + byte[] bar=new byte[j]; + Array.Copy(foo, 0, bar, 0, j); + return bar; + } + internal static byte[] toBase64(byte[] buf, int start, int length) + { + + byte[] tmp=new byte[length*2]; + int i,j,k; + + int foo=(length/3)*3+start; + i=0; + for(j=start; j>2)&0x3f; + tmp[i++]=b64[k]; + k=(buf[j]&0x03)<<4|(buf[j+1]>>4)&0x0f; + tmp[i++]=b64[k]; + k=(buf[j+1]&0x0f)<<2|(buf[j+2]>>6)&0x03; + tmp[i++]=b64[k]; + k=buf[j+2]&0x3f; + tmp[i++]=b64[k]; + } + + foo=(start+length)-foo; + if(foo==1) + { + k=(buf[j]>>2)&0x3f; + tmp[i++]=b64[k]; + k=((buf[j]&0x03)<<4)&0x3f; + tmp[i++]=b64[k]; + tmp[i++]=(byte)'='; + tmp[i++]=(byte)'='; + } + else if(foo==2) + { + k=(buf[j]>>2)&0x3f; + tmp[i++]=b64[k]; + k=(buf[j]&0x03)<<4|(buf[j+1]>>4)&0x0f; + tmp[i++]=b64[k]; + k=((buf[j+1]&0x0f)<<2)&0x3f; + tmp[i++]=b64[k]; + tmp[i++]=(byte)'='; + } + byte[] bar=new byte[i]; + Array.Copy(tmp, 0, bar, 0, i); + return bar; + + // return sun.misc.BASE64Encoder().encode(buf); + } + + internal static String[] split(String foo, String split) + { + byte[] buf=Util.getBytes(foo); + System.Collections.ArrayList bar=new System.Collections.ArrayList(); + int start=0; + int index; + while(true) + { + index=foo.IndexOf(split, start); + if(index>=0) + { + bar.Add(Util.getString(buf, start, index-start)); + start=index+1; + continue; + } + bar.Add(Util.getString(buf, start, buf.Length-start)); + break; + } + String[] result=new String[bar.Count]; + for(int i=0; i>4)&0xf]); + sb.Append(chars[(bar)&0xf]); + if(i+1>>1. + if ((ooffset < 0) || (toffset < 0) || (toffset > (long)orig.Length - len) || + (ooffset > (long)other.Length - len)) + { + return false; + } + while (len-- > 0) + { + char c1 = ta[to++]; + char c2 = pa[po++]; + if (c1 == c2) + { + continue; + } + if (ignoreCase) + { + // If characters don't match but case may be ignored, + // try converting both characters to uppercase. + // If the results match, then the comparison scan should + // continue. + char u1 = char.ToUpper(c1); + char u2 = char.ToUpper(c2); + if (u1 == u2) + { + continue; + } + // Unfortunately, conversion to uppercase does not work properly + // for the Georgian alphabet, which has strange rules about case + // conversion. So we need to make one last check before + // exiting. + if (char.ToLower(u1) == char.ToLower(u2)) + { + continue; + } + } + return false; + } + return true; + } + + public static uint ToUInt32( byte [] ptr ,int Index) + { + uint ui = 0; + + ui = ( (uint) ptr[ Index++ ] ) << 24; + ui += ( (uint) ptr[ Index++ ] ) << 16; + ui += ( (uint) ptr[ Index++ ] ) << 8; + ui += (uint) ptr[ Index++ ]; + + return ui; + } + + public static int ToInt32( byte [] ptr ,int Index) + { + return (int)ToUInt32( ptr, Index ); + } + + public static ushort ToUInt16( byte [] ptr , int Index) + { + ushort u = 0; + + u = ( ushort ) ptr[ Index++ ]; + u *= 256; + u += ( ushort ) ptr[ Index++ ]; + + return u; + } + public static bool ArrayContains( Object[] arr, Object o) + { + for(int i=0; iivsize) + { + tmp=new byte[ivsize]; + Array.Copy(iv, 0, tmp, 0, tmp.Length); + iv=tmp; + } + if(key.Length>bsize) + { + tmp=new byte[bsize]; + Array.Copy(key, 0, tmp, 0, tmp.Length); + key=tmp; + } + + try + { + // SecretKeySpec keyspec=new SecretKeySpec(key, "AES"); + // cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad); + + // cipher.init((mode==ENCRYPT_MODE? + // javax.crypto.Cipher.ENCRYPT_MODE: + // javax.crypto.Cipher.DECRYPT_MODE), + // keyspec, new IvParameterSpec(iv)); + cipher = (mode==ENCRYPT_MODE? + rijndael.CreateEncryptor(key, iv): + rijndael.CreateDecryptor(key, iv)); + } + catch(Exception e) + { + Console.WriteLine(e); + cipher=null; + } + } + public override void update(byte[] foo, int s1, int len, byte[] bar, int s2) + { + //cipher.update(foo, s1, len, bar, s2); + cipher.TransformBlock(foo, s1, len, bar, s2); + } + + public override string ToString() + { + return "aes128-cbc"; + } + } + +} diff --git a/SharpSSH/jsch/jce/BlowfishCBC.cs b/SharpSSH/jsch/jce/BlowfishCBC.cs new file mode 100644 index 00000000..afbe35eb --- /dev/null +++ b/SharpSSH/jsch/jce/BlowfishCBC.cs @@ -0,0 +1,17 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /// + /// Summary description for BlowfishCBC. + /// + public class BlowfishCBC + { + public BlowfishCBC() + { + // + // TODO: Add constructor logic here + // + } + } +} diff --git a/SharpSSH/jsch/jce/DH.cs b/SharpSSH/jsch/jce/DH.cs new file mode 100644 index 00000000..6e65f73b --- /dev/null +++ b/SharpSSH/jsch/jce/DH.cs @@ -0,0 +1,76 @@ +using System; +using Org.Mentalis.Security.Cryptography; //For DiffieHellman usage + + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class DH : Tamir.SharpSsh.jsch.DH + { + internal byte[] p; + internal byte[] g; + internal byte[] e; // my public key + internal byte[] e_array; + internal byte[] f; // your public key + internal byte[] K; // shared secret key + internal byte[] K_array; + + private DiffieHellman dh; + public void init() + { + } + public byte[] getE() + { + if(e_array==null) + { + + dh = new DiffieHellmanManaged(p , g, 0); + e_array = dh.CreateKeyExchange(); + } + return e_array; + } + public byte[] getK() + { + if(K_array==null) + { + K_array = dh.DecryptKeyExchange( f); + } + return K_array; + } + public void setP(byte[] p){ this.p=p; } + public void setG(byte[] g){ this.g=g; } + public void setF(byte[] f){ this.f=f; } + // void setP(BigInteger p){this.p=p;} + // void setG(BigInteger g){this.g=g;} + // void setF(BigInteger f){this.f=f;} + } + +} diff --git a/SharpSSH/jsch/jce/HMACMD5.cs b/SharpSSH/jsch/jce/HMACMD5.cs new file mode 100644 index 00000000..e60234f5 --- /dev/null +++ b/SharpSSH/jsch/jce/HMACMD5.cs @@ -0,0 +1,88 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class HMACMD5 : MAC + { + private const String name="hmac-md5"; + private const int bsize=16; + private Org.Mentalis.Security.Cryptography.HMAC mentalis_mac; + private System.Security.Cryptography.CryptoStream cs; + //private Mac mac; + public int getBlockSize(){return bsize;} + public void init(byte[] key) + { + if(key.Length>bsize) + { + byte[] tmp=new byte[bsize]; + Array.Copy(key, 0, tmp, 0, bsize); + key=tmp; + } + // SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5"); + // mac=Mac.getInstance("HmacMD5"); + // mac.init(skey); + mentalis_mac = new Org.Mentalis.Security.Cryptography.HMAC(new System.Security.Cryptography.MD5CryptoServiceProvider(), key); + cs = new System.Security.Cryptography.CryptoStream( System.IO.Stream.Null, mentalis_mac, System.Security.Cryptography.CryptoStreamMode.Write); + } + + private byte[] tmp=new byte[4]; + public void update(int i) + { + tmp[0]=(byte)(i>>24); + tmp[1]=(byte)(i>>16); + tmp[2]=(byte)(i>>8); + tmp[3]=(byte)i; + update(tmp, 0, 4); + } + public void update(byte[] foo, int s, int l) + { + //mac.update(foo, s, l); + cs.Write( foo, s, l); + } + public byte[] doFinal() + { + //return mac.doFinal(); + cs.Close(); + byte[] result = mentalis_mac.Hash; + byte[] key = mentalis_mac.Key; + mentalis_mac.Clear(); + init(key); + + return result; + } + public String getName() + { + return name; + } + } + +} diff --git a/SharpSSH/jsch/jce/HMACMD596.cs b/SharpSSH/jsch/jce/HMACMD596.cs new file mode 100644 index 00000000..c0cf26bc --- /dev/null +++ b/SharpSSH/jsch/jce/HMACMD596.cs @@ -0,0 +1,82 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class HMACMD596 : MAC + { + private const String name="hmac-md5-96"; + private const int bsize=12; + private Org.Mentalis.Security.Cryptography.HMAC mentalis_mac; + private System.Security.Cryptography.CryptoStream cs; + //private Mac mac; + public int getBlockSize(){return bsize;} + public void init(byte[] key) + { + if(key.Length>16) + { + byte[] tmp=new byte[16]; + Array.Copy(key, 0, tmp, 0, 16); + key=tmp; + } + // SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5"); + // mac=Mac.getInstance("HmacMD5"); + // mac.init(skey); + mentalis_mac = new Org.Mentalis.Security.Cryptography.HMAC(new System.Security.Cryptography.MD5CryptoServiceProvider(), key); + cs = new System.Security.Cryptography.CryptoStream( System.IO.Stream.Null, mentalis_mac, System.Security.Cryptography.CryptoStreamMode.Write); + } + private byte[] tmp=new byte[4]; + public void update(int i) + { + tmp[0]=(byte)(i>>24); + tmp[1]=(byte)(i>>16); + tmp[2]=(byte)(i>>8); + tmp[3]=(byte)i; + update(tmp, 0, 4); + } + public void update(byte[] foo, int s, int l) + { + //mac.update(foo, s, l); + cs.Write( foo, s, l); + } + private byte[] buf=new byte[12]; + public byte[] doFinal() + { + cs.Close(); + Array.Copy( mentalis_mac.Hash, 0, buf, 0, 12); + return buf; + } + public String getName() + { + return name; + } + } +} diff --git a/SharpSSH/jsch/jce/HMACSHA1.cs b/SharpSSH/jsch/jce/HMACSHA1.cs new file mode 100644 index 00000000..cde94b56 --- /dev/null +++ b/SharpSSH/jsch/jce/HMACSHA1.cs @@ -0,0 +1,88 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class HMACSHA1 : MAC + { + private const String name="hmac-sha1"; + private const int bsize=20; + private Org.Mentalis.Security.Cryptography.HMAC mentalis_mac; + private System.Security.Cryptography.CryptoStream cs; + //private Mac mac; + public int getBlockSize(){return bsize;} + public void init(byte[] key) + { + if(key.Length>bsize) + { + byte[] tmp=new byte[bsize]; + Array.Copy(key, 0, tmp, 0, bsize); + key=tmp; + } + // SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1"); + // mac=Mac.getInstance("HmacSHA1"); + // mac.init(skey); + mentalis_mac = new Org.Mentalis.Security.Cryptography.HMAC(new System.Security.Cryptography.SHA1CryptoServiceProvider(), key); + cs = new System.Security.Cryptography.CryptoStream( System.IO.Stream.Null, mentalis_mac, System.Security.Cryptography.CryptoStreamMode.Write); + } + private byte[] tmp=new byte[4]; + public void update(int i) + { + tmp[0]=(byte)(i>>24); + tmp[1]=(byte)(i>>16); + tmp[2]=(byte)(i>>8); + tmp[3]=(byte)i; + update(tmp, 0, 4); + } + public void update(byte[] foo, int s, int l) + { + //mac.update(foo, s, l); + cs.Write( foo , s, l); + } + public byte[] doFinal() + { + Console.WriteLine("Sha1"); + //return mac.doFinal(); + cs.Close(); + byte[] result = mentalis_mac.Hash; + byte[] key = mentalis_mac.Key; + mentalis_mac.Clear(); + init(key); + + return result; + } + public String getName() + { + return name; + } + } + +} diff --git a/SharpSSH/jsch/jce/HMACSHA196.cs b/SharpSSH/jsch/jce/HMACSHA196.cs new file mode 100644 index 00000000..d009954c --- /dev/null +++ b/SharpSSH/jsch/jce/HMACSHA196.cs @@ -0,0 +1,85 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class HMACSHA196 : MAC + { + private const String name="hmac-sha1-96"; + private const int bsize=12; + private Org.Mentalis.Security.Cryptography.HMAC mentalis_mac; + private System.Security.Cryptography.CryptoStream cs; + //private Mac mac; + public int getBlockSize(){return bsize;} + public void init(byte[] key) + { + if(key.Length>20) + { + byte[] tmp=new byte[20]; + Array.Copy(key, 0, tmp, 0, 20); + key=tmp; + } + // SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1"); + // mac=Mac.getInstance("HmacSHA1"); + // mac.init(skey); + mentalis_mac = new Org.Mentalis.Security.Cryptography.HMAC(new System.Security.Cryptography.MD5CryptoServiceProvider(), key); + cs = new System.Security.Cryptography.CryptoStream( System.IO.Stream.Null, mentalis_mac, System.Security.Cryptography.CryptoStreamMode.Write); + } + private byte[] tmp=new byte[4]; + public void update(int i) + { + tmp[0]=(byte)(i>>24); + tmp[1]=(byte)(i>>16); + tmp[2]=(byte)(i>>8); + tmp[3]=(byte)i; + update(tmp, 0, 4); + } + public void update(byte[] foo, int s, int l) + { + //mac.update(foo, s, l); + cs.Write( foo , s, l); + } + private byte[] buf=new byte[12]; + public byte[] doFinal() + { + // System.arraycopy(mac.doFinal(), 0, buf, 0, 12); + // return buf; + cs.Close(); + Array.Copy( mentalis_mac.Hash, 0, buf, 0, 12); + return buf; + } + public String getName() + { + return name; + } + } + +} diff --git a/SharpSSH/jsch/jce/KeyPairGenDSA.cs b/SharpSSH/jsch/jce/KeyPairGenDSA.cs new file mode 100644 index 00000000..1a44f26b --- /dev/null +++ b/SharpSSH/jsch/jce/KeyPairGenDSA.cs @@ -0,0 +1,74 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class KeyPairGenDSA : Tamir.SharpSsh.jsch.KeyPairGenDSA + { + byte[] x; // private + byte[] y; // public + byte[] p; + byte[] q; + byte[] g; + + public void init(int key_size) + { +// KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); +// keyGen.initialize(key_size, new SecureRandom()); +// KeyPair pair = keyGen.generateKeyPair(); +// PublicKey pubKey=pair.getPublic(); +// PrivateKey prvKey=pair.getPrivate(); + + System.Security.Cryptography.DSACryptoServiceProvider dsa = new System.Security.Cryptography.DSACryptoServiceProvider(key_size); + System.Security.Cryptography.DSAParameters DSAKeyInfo = dsa.ExportParameters(true); + +// x=((DSAPrivateKey)prvKey).getX().toByteArray(); +// y=((DSAPublicKey)pubKey).getY().toByteArray(); +// +// DSAParams _params=((DSAKey)prvKey).getParams(); +// p=_params.getP().toByteArray(); +// q=_params.getQ().toByteArray(); +// g=_params.getG().toByteArray(); + + x = DSAKeyInfo.X; + y = DSAKeyInfo.Y; + p = DSAKeyInfo.P; + q = DSAKeyInfo.Q; + g = DSAKeyInfo.G; + } + public byte[] getX(){return x;} + public byte[] getY(){return y;} + public byte[] getP(){return p;} + public byte[] getQ(){return q;} + public byte[] getG(){return g;} + } + +} diff --git a/SharpSSH/jsch/jce/KeyPairGenRSA.cs b/SharpSSH/jsch/jce/KeyPairGenRSA.cs new file mode 100644 index 00000000..0fda8a1a --- /dev/null +++ b/SharpSSH/jsch/jce/KeyPairGenRSA.cs @@ -0,0 +1,93 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class KeyPairGenRSA : Tamir.SharpSsh.jsch.KeyPairGenRSA + { + byte[] d; // private + byte[] e; // public + byte[] n; + + byte[] c; // coefficient + byte[] ep; // exponent p + byte[] eq; // exponent q + byte[] p; // prime p + byte[] q; // prime q + + System.Security.Cryptography.RSAParameters RSAKeyInfo; + + public void init(int key_size) + { + // KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + // keyGen.initialize(key_size, new SecureRandom()); + // KeyPair pair = keyGen.generateKeyPair(); + // + // PublicKey pubKey=pair.getPublic(); + // PrivateKey prvKey=pair.getPrivate(); + + System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(key_size); + RSAKeyInfo = rsa.ExportParameters(true); + + // d=((RSAPrivateKey)prvKey).getPrivateExponent().toByteArray(); + // e=((RSAPublicKey)pubKey).getPublicExponent().toByteArray(); + // n=((RSAKey)prvKey).getModulus().toByteArray(); + // + // c=((RSAPrivateCrtKey)prvKey).getCrtCoefficient().toByteArray(); + // ep=((RSAPrivateCrtKey)prvKey).getPrimeExponentP().toByteArray(); + // eq=((RSAPrivateCrtKey)prvKey).getPrimeExponentQ().toByteArray(); + // p=((RSAPrivateCrtKey)prvKey).getPrimeP().toByteArray(); + // q=((RSAPrivateCrtKey)prvKey).getPrimeQ().toByteArray(); + + d= RSAKeyInfo.D ; + e=RSAKeyInfo.Exponent ; + n=RSAKeyInfo.Modulus ; + + c=RSAKeyInfo.InverseQ ; + ep=RSAKeyInfo.DP ; + eq=RSAKeyInfo.DQ ; + p=RSAKeyInfo.P ; + q=RSAKeyInfo.Q ; + } + public byte[] getD(){return d;} + public byte[] getE(){return e;} + public byte[] getN(){return n;} + public byte[] getC(){return c;} + public byte[] getEP(){return ep;} + public byte[] getEQ(){return eq;} + public byte[] getP(){return p;} + public byte[] getQ(){return q;} + public System.Security.Cryptography.RSAParameters KeyInfo + { + get{return RSAKeyInfo;} + } + } +} diff --git a/SharpSSH/jsch/jce/MD5.cs b/SharpSSH/jsch/jce/MD5.cs new file mode 100644 index 00000000..4a2a4e4d --- /dev/null +++ b/SharpSSH/jsch/jce/MD5.cs @@ -0,0 +1,69 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class MD5 : Tamir.SharpSsh.jsch.HASH + { + //MessageDigest md; + internal System.Security.Cryptography.MD5CryptoServiceProvider md; + private System.Security.Cryptography.CryptoStream cs; + + public override int getBlockSize(){return 16;} + public override void init() + { + try + { + //md=MessageDigest.getInstance("MD5"); + md = new System.Security.Cryptography.MD5CryptoServiceProvider(); + cs = new System.Security.Cryptography.CryptoStream( System.IO.Stream.Null, md, System.Security.Cryptography.CryptoStreamMode.Write); + } + catch(Exception e) + { + Console.WriteLine(e); + } + } + public override void update(byte[] foo, int start, int len) + { + //md.update(foo, start, len); + cs.Write(foo, start, len); + } + public override byte[] digest() + { + cs.Close(); + byte[] result = md.Hash; + md.Clear();//Reinitiazing hash objects + init(); + + return result; + } + } +} diff --git a/SharpSSH/jsch/jce/Random.cs b/SharpSSH/jsch/jce/Random.cs new file mode 100644 index 00000000..0c717871 --- /dev/null +++ b/SharpSSH/jsch/jce/Random.cs @@ -0,0 +1,75 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class Random : Tamir.SharpSsh.jsch.Random + { + private byte[] tmp=new byte[16]; + //private SecureRandom random; + private System.Security.Cryptography.RNGCryptoServiceProvider rand; + public Random() + { + // random=null; + // random = new SecureRandom(); + // + // try{ random=SecureRandom.getInstance("SHA1PRNG"); } + // catch(java.security.NoSuchAlgorithmException e){ + // // System.out.println(e); + // + // // The following code is for IBM's JCE + // try{ random=SecureRandom.getInstance("IBMSecureRandom"); } + // catch(java.security.NoSuchAlgorithmException ee){ + // System.out.println(ee); + // } + // } + rand = new System.Security.Cryptography.RNGCryptoServiceProvider(); + } + static int times = 0; + public void fill(byte[] foo, int start, int len) + { + try + { + if(len>tmp.Length){ tmp=new byte[len]; } + //random.nextBytes(tmp); + rand.GetBytes(tmp); + Array.Copy(tmp, 0, foo, start, len); + } + catch(Exception e) + { + times++; + Console.WriteLine(times+") Array.Copy(tmp={0}, 0, foo={1}, {2}, {3}", tmp.Length, foo.Length, start, len); + //Console.WriteLine(e.StackTrace); + } + } + } + +} diff --git a/SharpSSH/jsch/jce/SHA1.cs b/SharpSSH/jsch/jce/SHA1.cs new file mode 100644 index 00000000..d3ee84be --- /dev/null +++ b/SharpSSH/jsch/jce/SHA1.cs @@ -0,0 +1,66 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +public class SHA1 : Tamir.SharpSsh.jsch.HASH{ + //MessageDigest md; + internal System.Security.Cryptography.SHA1CryptoServiceProvider md; + private System.Security.Cryptography.CryptoStream cs; + + public override int getBlockSize(){return 20;} + public override void init(){ + try + { + //md=MessageDigest.getInstance("SHA-1"); + md=new System.Security.Cryptography.SHA1CryptoServiceProvider(); + cs = new System.Security.Cryptography.CryptoStream( System.IO.Stream.Null, md, System.Security.Cryptography.CryptoStreamMode.Write); + } + catch(Exception e){ + Console.WriteLine(e); + } + } + public override void update(byte[] foo, int start, int len){ + //md.update(foo, start, len); + cs.Write(foo, start, len); + } + public override byte[] digest() { + //return md.digest(); + cs.Close(); + byte[] result = md.Hash; + md.Clear(); + init(); //Reinitiazing hash objects + + return result; + } +} + +} diff --git a/SharpSSH/jsch/jce/SignatureDSA.cs b/SharpSSH/jsch/jce/SignatureDSA.cs new file mode 100644 index 00000000..446a23bc --- /dev/null +++ b/SharpSSH/jsch/jce/SignatureDSA.cs @@ -0,0 +1,117 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class SignatureDSA : Tamir.SharpSsh.jsch.SignatureDSA + { + + //java.security.Signature signature; + // KeyFactory keyFactory; + System.Security.Cryptography.DSAParameters DSAKeyInfo; + System.Security.Cryptography.SHA1CryptoServiceProvider sha1; + System.Security.Cryptography.CryptoStream cs; + + public void init() + { + sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider(); + cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, sha1, System.Security.Cryptography.CryptoStreamMode.Write); + } + public void setPubKey(byte[] y, byte[] p, byte[] q, byte[] g) + { + DSAKeyInfo.Y = Util.stripLeadingZeros( y ); + DSAKeyInfo.P = Util.stripLeadingZeros( p ) ; + DSAKeyInfo.Q = Util.stripLeadingZeros( q ); + DSAKeyInfo.G = Util.stripLeadingZeros( g ) ; + } + public void setPrvKey(byte[] x, byte[] p, byte[] q, byte[] g) + { + DSAKeyInfo.X = Util.stripLeadingZeros( x ); + DSAKeyInfo.P = Util.stripLeadingZeros( p ); + DSAKeyInfo.Q = Util.stripLeadingZeros( q ); + DSAKeyInfo.G = Util.stripLeadingZeros( g ); + } + + public byte[] sign() + { + //byte[] sig=signature.sign(); + cs.Close(); + System.Security.Cryptography.DSACryptoServiceProvider DSA = new System.Security.Cryptography.DSACryptoServiceProvider(); + DSA.ImportParameters(DSAKeyInfo); + System.Security.Cryptography.DSASignatureFormatter DSAFormatter = new System.Security.Cryptography.DSASignatureFormatter(DSA); + DSAFormatter.SetHashAlgorithm("SHA1"); + + byte[] sig =DSAFormatter.CreateSignature( sha1 ); + return sig; + } + public void update(byte[] foo) + { + //signature.update(foo); + cs.Write( foo , 0, foo.Length); + } + public bool verify(byte[] sig) + { + cs.Close(); + System.Security.Cryptography.DSACryptoServiceProvider DSA = new System.Security.Cryptography.DSACryptoServiceProvider(); + DSA.ImportParameters(DSAKeyInfo); + System.Security.Cryptography.DSASignatureDeformatter DSADeformatter = new System.Security.Cryptography.DSASignatureDeformatter(DSA); + DSADeformatter.SetHashAlgorithm("SHA1"); + + long i=0; + long j=0; + byte[] tmp; + + //This makes sure sig is always 40 bytes? + 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; + } + bool res = DSADeformatter.VerifySignature(sha1, sig); + return res; + } + } + +} diff --git a/SharpSSH/jsch/jce/SignatureRSA.cs b/SharpSSH/jsch/jce/SignatureRSA.cs new file mode 100644 index 00000000..bc2e57af --- /dev/null +++ b/SharpSSH/jsch/jce/SignatureRSA.cs @@ -0,0 +1,157 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + public class SignatureRSA : Tamir.SharpSsh.jsch.SignatureRSA + { + + //java.security.Signature signature; + // KeyFactory keyFactory; + System.Security.Cryptography.RSAParameters RSAKeyInfo; + System.Security.Cryptography.SHA1CryptoServiceProvider sha1; + System.Security.Cryptography.CryptoStream cs; + + public void init() + { + // signature=java.security.Signature.getInstance("SHA1withRSA"); + // keyFactory=KeyFactory.getInstance("RSA"); + sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider(); + cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, sha1, System.Security.Cryptography.CryptoStreamMode.Write); + } + public void setPubKey(byte[] e, byte[] n) + { + // RSAPublicKeySpec rsaPubKeySpec = + // new RSAPublicKeySpec(new BigInteger(n), + // new BigInteger(e)); + // PublicKey pubKey=keyFactory.generatePublic(rsaPubKeySpec); + // signature.initVerify(pubKey); + RSAKeyInfo.Modulus = Util.stripLeadingZeros( n ); + RSAKeyInfo.Exponent = e; +// Util.Dump("C:\\e.bin", e); +// Util.Dump("C:\\n.bin", n); + } + public void setPrvKey(byte[] d, byte[] n) + { + // RSAPrivateKeySpec rsaPrivKeySpec = + // new RSAPrivateKeySpec(new BigInteger(n), + // new BigInteger(d)); + // PrivateKey prvKey = keyFactory.generatePrivate(rsaPrivKeySpec); + // signature.initSign(prvKey); + + RSAKeyInfo.D = d ; + RSAKeyInfo.Modulus = n ; + } + + public void setPrvKey(byte[] e, byte[] n, byte[] d, byte[] p, byte[] q, byte[] dp, byte[] dq, byte[] c) + { + RSAKeyInfo.Exponent = e ; + RSAKeyInfo.D = Util.stripLeadingZeros( d ) ; + RSAKeyInfo.Modulus = Util.stripLeadingZeros( n ) ; + RSAKeyInfo.P = Util.stripLeadingZeros(p); + RSAKeyInfo.Q = Util.stripLeadingZeros(q); + RSAKeyInfo.DP = Util.stripLeadingZeros(dp); + RSAKeyInfo.DQ = Util.stripLeadingZeros(dq); + RSAKeyInfo.InverseQ = Util.stripLeadingZeros(c); + } + + public void setPrvKey(System.Security.Cryptography.RSAParameters keyInfo) + { + // RSAPrivateKeySpec rsaPrivKeySpec = + // new RSAPrivateKeySpec(new BigInteger(n), + // new BigInteger(d)); + // PrivateKey prvKey = keyFactory.generatePrivate(rsaPrivKeySpec); + // signature.initSign(prvKey); + RSAKeyInfo = keyInfo; + } + + public byte[] sign() + { + // byte[] sig=signature.sign(); + // return sig; + cs.Close(); + System.Security.Cryptography.RSACryptoServiceProvider RSA = new System.Security.Cryptography.RSACryptoServiceProvider(); + RSA.ImportParameters(RSAKeyInfo); + System.Security.Cryptography.RSAPKCS1SignatureFormatter RSAFormatter = new System.Security.Cryptography.RSAPKCS1SignatureFormatter(RSA); + RSAFormatter.SetHashAlgorithm("SHA1"); + + byte[] sig = RSAFormatter.CreateSignature( sha1 ); + return sig; + + + } + public void update(byte[] foo) + { + //signature.update(foo); + cs.Write( foo , 0, foo.Length); + } + public bool verify(byte[] sig) + { + cs.Close(); + System.Security.Cryptography.RSACryptoServiceProvider RSA = new System.Security.Cryptography.RSACryptoServiceProvider(); + RSA.ImportParameters(RSAKeyInfo); + System.Security.Cryptography.RSAPKCS1SignatureDeformatter RSADeformatter = new System.Security.Cryptography.RSAPKCS1SignatureDeformatter(RSA); + RSADeformatter.SetHashAlgorithm("SHA1"); + + + long i=0; + long j=0; + byte[] tmp; + + //Util.Dump("c:\\sig.bin", sig); + + 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; + } + //System.out.println("j="+j+" "+Integer.toHexString(sig[0]&0xff)); + //return signature.verify(sig); + bool verify = RSADeformatter.VerifySignature(sha1, sig); + return verify; + } + } + +} diff --git a/SharpSSH/jsch/jce/TripleDESCBC.cs b/SharpSSH/jsch/jce/TripleDESCBC.cs new file mode 100644 index 00000000..356d98d1 --- /dev/null +++ b/SharpSSH/jsch/jce/TripleDESCBC.cs @@ -0,0 +1,104 @@ +using System; + +namespace Tamir.SharpSsh.jsch.jce +{ + /* -*-mode:java; c-basic-offset:2; -*- */ + /* + Copyright (c) 2002,2003,2004 ymnk, JCraft,Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + public class TripleDESCBC : Tamir.SharpSsh.jsch.Cipher + { + private const int ivsize=8; + private const int bsize=24; + private System.Security.Cryptography.TripleDES triDes; + private System.Security.Cryptography.ICryptoTransform cipher; + //private javax.crypto.Cipher cipher; + public override int getIVSize(){return ivsize;} + public override int getBlockSize(){return bsize;} + public override void init(int mode, byte[] key, byte[] iv) + { + triDes = new System.Security.Cryptography.TripleDESCryptoServiceProvider(); + triDes.Mode=System.Security.Cryptography.CipherMode.CBC; + triDes.Padding=System.Security.Cryptography.PaddingMode.None; + //String pad="NoPadding"; + //if(padding) pad="PKCS5Padding"; + byte[] tmp; + if(iv.Length>ivsize) + { + tmp=new byte[ivsize]; + Array.Copy(iv, 0, tmp, 0, tmp.Length); + iv=tmp; + } + if(key.Length>bsize) + { + tmp=new byte[bsize]; + Array.Copy(key, 0, tmp, 0, tmp.Length); + key=tmp; + } + + try + { + // cipher=javax.crypto.Cipher.getInstance("DESede/CBC/"+pad); + /* + // The following code does not work on IBM's JDK 1.4.1 + SecretKeySpec skeySpec = new SecretKeySpec(key, "DESede"); + cipher.init((mode==ENCRYPT_MODE? + javax.crypto.Cipher.ENCRYPT_MODE: + javax.crypto.Cipher.DECRYPT_MODE), + skeySpec, new IvParameterSpec(iv)); + */ + // DESedeKeySpec keyspec=new DESedeKeySpec(key); + // SecretKeyFactory keyfactory=SecretKeyFactory.getInstance("DESede"); + // SecretKey _key=keyfactory.generateSecret(keyspec); + // cipher.init((mode==ENCRYPT_MODE? + // javax.crypto.Cipher.ENCRYPT_MODE: + // javax.crypto.Cipher.DECRYPT_MODE), + // _key, new IvParameterSpec(iv)); + cipher = (mode==ENCRYPT_MODE? + triDes.CreateEncryptor(key, iv): + triDes.CreateDecryptor(key, iv)); + } + catch(Exception e) + { + Console.WriteLine(e); + cipher=null; + } + } + public override void update(byte[] foo, int s1, int len, byte[] bar, int s2) + { + // cipher.update(foo, s1, len, bar, s2); + cipher.TransformBlock(foo, s1, len, bar, s2); + } + public override string ToString() + { + return "3des-cbc"; + } + + } + +} diff --git a/SharpSSH/lib/DiffieHellman.dll b/SharpSSH/lib/DiffieHellman.dll new file mode 100644 index 00000000..aa310511 Binary files /dev/null and b/SharpSSH/lib/DiffieHellman.dll differ diff --git a/SharpSSH/lib/Org.Mentalis.Security.dll b/SharpSSH/lib/Org.Mentalis.Security.dll new file mode 100644 index 00000000..bac39dd9 Binary files /dev/null and b/SharpSSH/lib/Org.Mentalis.Security.dll differ