Logo Search packages:      
Sourcecode: bareftp version File versions  Download package

Session.cs

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Net.Sockets;
using bareFTP.Preferences;

namespace bareFTP.Protocol.Sftp
{
      

      public class Session
      {
            private static string version="bareFTP-0.0.0";

            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= System.Text.Encoding.Default.GetBytes("SSH-2.0-"+version); // 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 Stream In=null;
            internal Stream Out=null;

            internal static bareFTP.Protocol.Sftp.jce.Random random;

            internal Buffer buf;
            internal Packet packet;
            
            private UserInfo userinfo;

            internal string host="127.0.0.1";
            internal int port=22;

            internal string username=null;
            internal string password=null;
            
            private bareFTP.Protocol.IDialogHost dhost;
            private Config conf;
            
            internal Session(Config conf)  
            {
                  this.conf = conf;
                  buf=new Buffer();
                  packet=new Packet(buf);
            }
                        
            public IDialogHost DialogHost
            {
                  get { return dhost; }
                  set { dhost = value; }
            }
            
            public void connect() 
            {
                  connect(timeout);
            }

            public void connect(int connectTimeout) 
            {
                  
                  if(_isConnected)
                  {
                        throw new Exception("session is already connected");
                  }
                  io=new IO();
                  if(random==null)
                  {
                        try
                        {
                              random = new bareFTP.Protocol.Sftp.jce.Random();
                              
                        }
                        catch(Exception e)
                        {
                              System.Console.Error.WriteLine("connect: random "+e);
                        }
                  }
                  Packet.setRandom(random);
                  
                  try   
                  {
                        int i, j;
                        
                        Stream In;
                        Stream Out;
                        
      
                        socket=Util.createSocket(host, port, connectTimeout);
                        In = new NetworkStream(socket); //;socket.getInputStream();
                        Out = new NetworkStream(socket); //;socket.getOutputStream();
                        
                        //if(timeout>0){ socket.setSoTimeout(timeout); }
                        socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1);
                        //socket.setTcpNoDelay(true);
                        
                        io.setInputStream(In);
                        io.setOutputStream(Out);
                        
                        if(connectTimeout>0 && socket!=null)
                        {
                              //socket.setSoTimeout(connectTimeout);
                              socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, connectTimeout);
                              socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, connectTimeout);
                        }

                        _isConnected=true;

                        while(true)
                        {

                              i=0;
                              j=0;
                              while(i<buf.buffer.Length)
                              {
                                    j=io.getByte();
                                    if(j<0)break;
                                    buf.buffer[i]=(byte)j; i++;
                                    if(j==10)break;
                              }
                              if(j<0)
                              {
                                    throw new Exception("connection is closed by foreign host");
                              }

                              if(buf.buffer[i-1]==10)
                              {    // 0x0a
                                    i--;
                                    if(buf.buffer[i-1]==13)
                                    {  // 0x0d
                                          i--;
                                    }
                              }

                              if(i>4 && (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 Exception("invalid server's version String");
                              }
                              break;
                        }                       

                        V_S=new byte[i]; Util.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];
                        Util.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 Exception("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 Exception("verify: "+result);
                                    }
                              }
                              else
                              {
                                    in_kex=false;
                                    throw new Exception("invalid protocol(kex): "+buf.buffer[5]);
                              }
                              if(kex.getState()==KeyExchange.STATE_END)
                              {
                                    break;
                              }
                        }

                        try{ checkHost(host, kex); }
                        catch(Exception 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 Exception("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.ToLower();
                              }
                              else
                              {
                                    // methods: publickey,password,keyboard-interactive
                                    methods="password";
                              }
                        }

                        while(true)
                        {
                              while(!auth && methods!=null && methods.Length > 0)
                              {

                                    UserAuth us = null;
                                    us=new UserAuthPassword(userinfo);
                                    if(us!=null)
                                    {
                                          try
                                          {
                                                auth=us.start(this);
                                                auth_cancel=false;
                                          }
                                          catch(JSchAuthCancelException)
                                          {
                                                auth_cancel=true;
                                          }
                                          catch(JSchPartialAuthException ee)
                                          {
                                                methods=ee.Methods;
                                                auth_cancel=false;
                                                continue;
                                          }
                                          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.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, connectTimeout);
                              socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, connectTimeout);
                        }

                        if(auth)
                        {
                              isAuthed=true;
                              connectThread=new Thread(this.run);
                              connectThread.Name = "Connect thread "+host+" session";
                              connectThread.Start();
                              return;
                        }
                        if(auth_cancel)
                              throw new Exception("Authentication canceled");
                        throw new Exception("Authentication failed");
                  }
                  catch(Exception e) 
                  {
                        in_kex=false;
                        if(_isConnected)
                        {
                              try
                              {
                                    packet.reset();
                                    buf.putByte((byte)SSH_MSG_DISCONNECT);
                                    buf.putInt(3);
                                    buf.putString(System.Text.Encoding.UTF8.GetBytes(e.ToString()));
                                    buf.putString(System.Text.Encoding.UTF8.GetBytes("en"));
                                    write(packet);
                                    disconnect();
                              }
                              catch(Exception)
                              {
                              }
                        }
                        _isConnected=false;
                        if(e is Exception) throw (Exception)e;
                        throw new Exception("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()];
                  }
                  Util.arraycopy(buf.buffer, buf.s, I_S, 0, I_S.Length);
                  
                  send_kexinit();
                  string[] guess=KeyExchange.guess(I_S, I_C);
                  if(guess==null)
                  {
                        throw new Exception("Algorithm negotiation fail");
                  }

                  if(!isAuthed &&
                        (guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS] == "none") ||
                        (guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC] == "none"))
                  {
                        throw new Exception("NONE Cipher should not be chosen before authentification is successed.");
                  }

                  KeyExchange kex=null;
                  try
                  {
                        kex = (KeyExchange)System.Activator.CreateInstance(System.Type.GetType(conf.getSSHAlgorithm((guess[KeyExchange.PROPOSAL_KEX_ALGS]))));
                  }
                  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;

                  packet.reset();
                  buf.putByte((byte) SSH_MSG_KEXINIT);
                  lock(random)
                  {
                        random.fill(buf.buffer, buf.index, 16); buf.skip(16);
            }

                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("kex")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("server_host_key")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("cipher.c2s")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("cipher.s2c")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("mac.c2s")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("mac.s2c")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("compression.c2s")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("compression.s2c")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("lang.c2s")));
                  buf.putString(System.Text.Encoding.Default.GetBytes(conf.getSSHAlgorithm("lang.s2c")));

                  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= conf.SSHStrictKeyCheck;

                  byte[] K_S=kex.getHostKey();
                  string key_type=kex.getKeyType();
                  string key_fprint=kex.getFingerPrint();
                  
                  HostKeyRepository hkr= new KnownHosts(conf);
                  int i=0;
                  lock(hkr)
                  {
                        i=hkr.check(host, K_S);
                  }

                  bool insert=false;

                  if((shkc == "ask" || shkc == "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(dhost!=null)
                        {
                              b=dhost.DisplayDialogQuestion(message+
                                    "\nDo you want to delete the old key and insert the new key?");
                        }
                        
                        if(!b)
                        {
                              throw new Exception("HostKey has been changed: "+host);
                        }
                        else
                        {
                              lock(hkr)
                              {
                                    string foo = "";
                                    if(key_type == "DSA")
                                          foo = "ssh-dss";
                                    else
                                          foo = "ssh-rsa";
                                    
                                    hkr.remove(host, foo, null);
                                    insert=true;
                              }
                        }
                  }

                  //insert=true;

                  if((shkc == "ask" || shkc == "yes") && (i!=HostKeyRepository.OK) && !insert)
                  {
                        if(shkc == "yes")
                        {
                              throw new Exception("reject HostKey: "+host);
                        }
                        
                        if(dhost!=null)
                        {
                              bool foo=dhost.DisplayDialogQuestion(
                                    "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 Exception("reject HostKey: "+host);
                              }
                              insert=true;
                        }
                        else
                        {
                              if(i==HostKeyRepository.NOT_INCLUDED)
                                    throw new Exception("UnknownHostKey: "+host+". "+key_type+" key fingerprint is "+key_fprint);
                              else throw new Exception("HostKey has been changed: "+host);
                        }
                  }

                  if(shkc == "no" && HostKeyRepository.NOT_INCLUDED==i)
                  {
                        insert=true;
                }

                  if(insert)
                  {
                        lock(hkr)
                        {

                              HostKey myhostkey = new HostKey(conf, host, 0,  K_S);
                              myhostkey.hash();                         
                              hkr.add(myhostkey, DialogHost);

                        }
                  }
            }

            public Channel openChannel(string type) 
            {
                  if(!_isConnected)
                  {
                        throw new Exception("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) 
            {
                  if(deflater!=null)
                  {
                        packet.buffer.index=deflater.compress(packet.buffer.buffer,
                              5, packet.buffer.index);
                  }
                  if(c2scipher!=null)
                  {
                        packet.padding(c2scipher.IVSize);
                        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=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(!Util.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;
                        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();
                              
                              throw new Exception("SSH_MSG_DISCONNECT:"+
                                    " "+reason_code+
                                    " "+ System.Text.Encoding.UTF8.GetString(description)+
                                    " "+ System.Text.Encoding.UTF8.GetString(language_tag));
                              
                        }
                        else if(type==SSH_MSG_IGNORE)
                        {
                        }
                        else if(type==SSH_MSG_DEBUG)
                        {
                              buf.rewind();
                              buf.getInt();buf.getShort();
                        }
                        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;
            }

            

            private void receive_newkeys(Buffer buf, KeyExchange kex)  
            {
                  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];
                        Util.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
                  {
                        s2ccipher=(Cipher)System.Activator.CreateInstance(System.Type.GetType(conf.getSSHAlgorithm(guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC])));
                        while(s2ccipher.BlockSize >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];
                              Util.arraycopy(Es2c, 0, bar, 0, Es2c.Length);
                              Util.arraycopy(foo, 0, bar, Es2c.Length, foo.Length);
                              Es2c=bar;
                        }
                        s2ccipher.init(Cipher.DECRYPT_MODE, Es2c, IVs2c);
                        cipher_size = s2ccipher.IVSize;
                        s2cmac=(MAC)System.Activator.CreateInstance(System.Type.GetType(conf.getSSHAlgorithm(guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC])));
                        s2cmac.init(MACs2c);
                        mac_buf=new byte[s2cmac.BlockSize];

                        c2scipher=(Cipher)System.Activator.CreateInstance(System.Type.GetType(conf.getSSHAlgorithm(guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS])));
                        while(c2scipher.BlockSize > 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];
                              Util.arraycopy(Ec2s, 0, bar, 0, Ec2s.Length);
                              Util.arraycopy(foo, 0, bar, Ec2s.Length, foo.Length);
                              Ec2s=bar;
                        }
                        c2scipher.init(Cipher.ENCRYPT_MODE, Ec2s, IVc2s);

                        c2smac=(MAC)System.Activator.CreateInstance(System.Type.GetType(conf.getSSHAlgorithm(guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS])));
                        c2smac.init(MACc2s);

                        if(guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS] != "none")
                        {
                              string foo = conf.getSSHAlgorithm(guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS]);
                              if(foo!=null)
                              {
                                    try
                                    {
                                          deflater=(Compression)System.Activator.CreateInstance(System.Type.GetType(foo));
                                          int level=6;
                                          deflater.init(Compression.DEFLATER, level);
                                    }
                                    catch(Exception)
                                    {
                                          System.Console.Error.WriteLine(foo+" isn't accessible.");
                                    }
                              }
                        }
                        else
                        {
                              if(deflater!=null)
                              {
                                    deflater=null;
                              }
                        }
                        if(guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC] != "none")
                        {
                              string foo = conf.getSSHAlgorithm(guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC]);
                              if(foo!=null)
                              {
                                    try
                                    {
                                          inflater=(Compression)System.Activator.CreateInstance(System.Type.GetType(foo));
                                          inflater.init(Compression.INFLATER, 0);
                                    }
                                    catch(Exception)
                                    {
                                          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){};
                              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.BlockSize : 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){};
                  }
                  _write(packet);
            }
            
            public void write(Packet packet) 
            {
                  
                  while(in_kex)
                  {
                        byte command=packet.buffer.buffer[5];
                        
                        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){};
                  }
                  _write(packet);
            }
            [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.Synchronized)]
            private void _write(Packet packet) 
            {
                  encode(packet);
                  if(io!=null)
                  {
                        io.put(packet);
                        seqo++;
                  }
            }

            
            public void run()
            {
                  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)
                        {
                              buf=read(buf);
                              int msgType=buf.buffer[5]&0xff;
            
                              if(kex!=null && kex.getState()==msgType)
                              {
                                    bool result=kex.next(buf);
                                    if(!result)
                                    {
                                          throw new Exception("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:
                                    //System.Console.WriteLine("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)
                                          {
                                                //System.Console.WriteLine(e);
                                                try{channel.disconnect();}
                                                catch(Exception){}
                                                break;
                                          }
                                          int len=length[0];
                                          channel.setLocalWindowSize(channel.lwsize-len);
                                          if(channel.lwsize<channel.lwsize_max/2)
                                          {
                                                packet.reset();
                                                buf.putByte((byte)SSH_MSG_CHANNEL_WINDOW_ADJUST);
                                                buf.putInt(channel.getRecipient());
                                                buf.putInt(channel.lwsize_max-channel.lwsize);
                                                write(packet);
                                                channel.setLocalWindowSize(channel.lwsize_max);
                                          }
                                          break;

                              case SSH_MSG_CHANNEL_WINDOW_ADJUST:
                                    //System.Console.WriteLine("WINDOW_ADJUST");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          if(channel==null)
                                          {
                                                break;
                                          }
                                          channel.addRemoteWindowSize(buf.getInt());
                                          break;

                              case SSH_MSG_CHANNEL_EOF:
                                    //System.Console.WriteLine("EOF");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          if(channel!=null)
                                          {
                                                channel.eof_remote();
                                          }
                                          break;
                              case SSH_MSG_CHANNEL_CLOSE:
                                    //System.Console.WriteLine("CLOSE");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          if(channel!=null)
                                          {
                                                channel.disconnect();
                                          }
                                          break;
                              case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
                                    //System.Console.WriteLine("OPEN_CONFIRMATION");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          channel.setRecipient(buf.getInt());
                                          channel.setRemoteWindowSize(buf.getInt());
                                          channel.setRemotePacketSize(buf.getInt());
                                          break;
                              case SSH_MSG_CHANNEL_OPEN_FAILURE:
                                    //System.Console.WriteLine("OPEN_FAILURE");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          int reason_code=buf.getInt();
                                          channel.exitstatus=reason_code;
                                          channel._close=true;
                                          channel._eof_remote=true;
                                          channel.setRecipient(0);
                                          break;
                              case SSH_MSG_CHANNEL_REQUEST:
                                    //System.Console.WriteLine("REQUEST");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          foo=buf.getString();
                                          bool reply=(buf.getByte()!=0);
                                          channel=Channel.getChannel(i, this);
                                          if(channel!=null)
                                          {
                                                byte reply_type=(byte)SSH_MSG_CHANNEL_FAILURE;
                                                if(System.Text.Encoding.UTF8.GetString(foo) == "exit-status")
                                                {
                                                      i=buf.getInt();             // exit-status
                                                      channel.setExitStatus(i);
                                                      reply_type=(byte)SSH_MSG_CHANNEL_SUCCESS;
                                                }
                                                if(reply)
                                                {
                                                      packet.reset();
                                                      buf.putByte(reply_type);
                                                      buf.putInt(channel.getRecipient());
                                                      write(packet);
                                                }
                                          }
                                          else
                                          {
                                          }
                                          break;
                              case SSH_MSG_CHANNEL_OPEN:
                                    //System.Console.WriteLine("OPEN");
                                          buf.getInt();
                                          buf.getShort();
                                          foo=buf.getString();
                                          string ctyp= System.Text.Encoding.UTF8.GetString(foo);
                                          channel=Channel.getChannel(ctyp);
                                          addChannel(channel);
                                          channel.getData(buf);
                                          channel.init();
                                          packet.reset();
                                          buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
                                          buf.putInt(channel.getRecipient());
                                          buf.putInt(channel.id);
                                          buf.putInt(channel.lwsize);
                                          buf.putInt(channel.lmpsize);
                                          write(packet);
                                          Thread tmp=new Thread(channel.run);
                                          tmp.Name = "Channel "+ctyp+" "+host;
                                          tmp.Start();
                                          break;
                              case SSH_MSG_CHANNEL_SUCCESS:
                                    //System.Console.WriteLine("SUCCESS");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          if(channel==null)
                                          {
                                                break;
                                          }
                                          channel.reply=1;
                                          break;
                              case SSH_MSG_CHANNEL_FAILURE:
                                    //System.Console.WriteLine("FAILURE");
                                          buf.getInt();
                                          buf.getShort();
                                          i=buf.getInt();
                                          channel=Channel.getChannel(i, this);
                                          if(channel==null)
                                          {
                                                break;
                                          }
                                          channel.reply=0;
                                          break;
                              case SSH_MSG_GLOBAL_REQUEST:
                                    //System.Console.WriteLine("GLOBAL_REQUEST");
                                          buf.getInt();
                                          buf.getShort();
                                          foo=buf.getString();       // request name
                                          reply=(buf.getByte()!=0);
                                          if(reply)
                                          {
                                                packet.reset();
                                                buf.putByte((byte)SSH_MSG_REQUEST_FAILURE);
                                                write(packet);
                                          }
                                          break;
                                    case SSH_MSG_REQUEST_FAILURE:
                              case SSH_MSG_REQUEST_SUCCESS:
                                    //System.Console.WriteLine("REQUEST_SUCCESS");
                                          Thread t=grr.getThread();
                                          if(t!=null)
                                          {
                                                grr.setReply(msgType==SSH_MSG_REQUEST_SUCCESS? 1 : 0);
                                                t.Interrupt();
                                          }
                                          break;
                                    default:
                                          System.Console.WriteLine("Session.run: unsupported type "+msgType);
                                          throw new IOException("Unknown SSH message type "+msgType);
                              }
                        }
                  }
                  catch(Exception)
                  {
                        
                  }
                  try
                  {
                        disconnect();
                  }
                  catch(NullReferenceException)
                  {
                        
                  }
                  catch(Exception)
                  {
                        
                  }
                  _isConnected=false;
            }


            public void disconnect()
            {
                  if(!_isConnected) return;


                  Channel.disconnect(this);

                  _isConnected=false;

                  
                  lock(connectThread)
                  {
                        connectThread.Interrupt();
                        connectThread=null;
                  }
                  //thread=null;
                  try
                  {
                        if(io!=null)
                        {
                              if(io.ins!=null) io.ins.Close();
                              if(io.outs!=null) io.outs.Close();
                  
                        }
                        
                        if(socket!=null)
                              socket.Close();
                        
                        
                  }
                  catch(Exception)
                  {
                  
                  }
                  io=null;
                  socket=null;
                  
                  //jsch.removeSession(this);

            }
            
            private class GlobalRequestReply
            {
                  private Thread thread=null;
                  private int reply=-1;
                  internal void setThread(Thread thread)
                  {
                        this.thread=thread;
                        this.reply=-1;
                  }
                  internal Thread getThread(){ return thread; }
                  internal void setReply(int reply){ this.reply=reply; }
                  internal int getReply(){ return this.reply; }
            }
            private GlobalRequestReply grr=new GlobalRequestReply();
            
            internal void addChannel(Channel channel)
            {
                  channel.session=this;
          }

            public void setHost(string host){ this.host=host; }
            public void setPort(int port){ this.port=port; }
            public void setPassword(string foo){ this.password=foo; }
            public void setUserInfo(UserInfo userinfo){ this.userinfo=userinfo; }
            public void setInputStream(Stream In){ this.In=In; }
            public void setOutputStream(Stream Out){ this.Out=Out; }
            
            public bool isConnected(){ return _isConnected; }
            public int getTimeout(){ return timeout; }
            public void setTimeout(int foo)  
            {
                  if(socket==null)
                  {
                        if(foo<0)
                        {
                              throw new Exception("invalid timeout value");
                        }
                        this.timeout=foo;
                        return;
                  }
                  try
                  {
                        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, foo);
                        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, foo);
                        timeout=foo;
                  }
                  catch(Exception e)
                  {
                        throw new Exception(e.ToString());
                  }
            }
            public string getServerVersion()
            {
                  return System.Text.Encoding.UTF8.GetString(V_S);
            }
            
            public void sendIgnore() 
            {
                  Buffer buf=new Buffer();
                  Packet packet=new Packet(buf);
                  packet.reset();
                  buf.putByte((byte)SSH_MSG_IGNORE);
                  write(packet);
            }
            
            private static byte[] keepalivemsg = System.Text.Encoding.UTF8.GetBytes("keepalive@jcraft.com");
            public void sendKeepAliveMsg()
            {
                  Buffer buf=new Buffer();
                  Packet packet=new Packet(buf);
                  packet.reset();
                  buf.putByte((byte)SSH_MSG_GLOBAL_REQUEST);
                  buf.putString(keepalivemsg);
                  buf.putByte((byte)1);
                  write(packet);
            }

            private HostKey hostkey=null;
            public HostKey getHostKey(){ return hostkey; }
            public string getHost(){return host;}
            public string getUserName(){return username;}
            public int getPort(){return port;}

            public string getMac()
            {
                  string mac="";
                  if(s2cmac!=null)
                        mac = s2cmac.Name;
                  return mac;

            }
            public string getCipher()
            {
                  string cipher="";
                  if(s2ccipher!=null)
                        cipher= s2ccipher.ToString();
                  return cipher;
            }

            public int BufferLength
            {
                  get{return this.buf.buffer.Length;}
            }
            
        public event EventHandler LogTextEmitted;
            public virtual void OnLogTextEmitted(LogTextEmittedArgs e)
            {
                  LogTextEmitted(this, e);
            }     
      }

}

Generated by  Doxygen 1.6.0   Back to index