]> Joshua Wise's Git repositories - dumload.git/blob - src/com/jcraft/jsch/Session.java
Initial commit.
[dumload.git] / src / com / jcraft / jsch / Session.java
1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
2 /*
3 Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8   1. Redistributions of source code must retain the above copyright notice,
9      this list of conditions and the following disclaimer.
10
11   2. Redistributions in binary form must reproduce the above copyright 
12      notice, this list of conditions and the following disclaimer in 
13      the documentation and/or other materials provided with the distribution.
14
15   3. The names of the authors may not be used to endorse or promote products
16      derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 package com.jcraft.jsch;
31
32 import java.io.*;
33 import java.net.*;
34
35 public class Session implements Runnable{
36   static private final String version="JSCH-0.1.43";
37
38   // http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt
39   static final int SSH_MSG_DISCONNECT=                      1;
40   static final int SSH_MSG_IGNORE=                          2;
41   static final int SSH_MSG_UNIMPLEMENTED=                   3;
42   static final int SSH_MSG_DEBUG=                           4;
43   static final int SSH_MSG_SERVICE_REQUEST=                 5;
44   static final int SSH_MSG_SERVICE_ACCEPT=                  6;
45   static final int SSH_MSG_KEXINIT=                        20;
46   static final int SSH_MSG_NEWKEYS=                        21;
47   static final int SSH_MSG_KEXDH_INIT=                     30;
48   static final int SSH_MSG_KEXDH_REPLY=                    31;
49   static final int SSH_MSG_KEX_DH_GEX_GROUP=               31;
50   static final int SSH_MSG_KEX_DH_GEX_INIT=                32;
51   static final int SSH_MSG_KEX_DH_GEX_REPLY=               33;
52   static final int SSH_MSG_KEX_DH_GEX_REQUEST=             34;
53   static final int SSH_MSG_GLOBAL_REQUEST=                 80;
54   static final int SSH_MSG_REQUEST_SUCCESS=                81;
55   static final int SSH_MSG_REQUEST_FAILURE=                82;
56   static final int SSH_MSG_CHANNEL_OPEN=                   90;
57   static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION=      91;
58   static final int SSH_MSG_CHANNEL_OPEN_FAILURE=           92;
59   static final int SSH_MSG_CHANNEL_WINDOW_ADJUST=          93;
60   static final int SSH_MSG_CHANNEL_DATA=                   94;
61   static final int SSH_MSG_CHANNEL_EXTENDED_DATA=          95;
62   static final int SSH_MSG_CHANNEL_EOF=                    96;
63   static final int SSH_MSG_CHANNEL_CLOSE=                  97;
64   static final int SSH_MSG_CHANNEL_REQUEST=                98;
65   static final int SSH_MSG_CHANNEL_SUCCESS=                99;
66   static final int SSH_MSG_CHANNEL_FAILURE=               100;
67
68   private static final int PACKET_MAX_SIZE = 256 * 1024;
69
70   private byte[] V_S;                                 // server version
71   private byte[] V_C=Util.str2byte("SSH-2.0-"+version); // client version
72
73   private byte[] I_C; // the payload of the client's SSH_MSG_KEXINIT
74   private byte[] I_S; // the payload of the server's SSH_MSG_KEXINIT
75   private byte[] K_S; // the host key
76
77   private byte[] session_id;
78
79   private byte[] IVc2s;
80   private byte[] IVs2c;
81   private byte[] Ec2s;
82   private byte[] Es2c;
83   private byte[] MACc2s;
84   private byte[] MACs2c;
85
86   private int seqi=0;
87   private int seqo=0;
88
89   String[] guess=null;
90   private Cipher s2ccipher;
91   private Cipher c2scipher;
92   private MAC s2cmac;
93   private MAC c2smac;
94   //private byte[] mac_buf;
95   private byte[] s2cmac_result1;
96   private byte[] s2cmac_result2;
97
98   private Compression deflater;
99   private Compression inflater;
100
101   private IO io;
102   private Socket socket;
103   private int timeout=0;
104
105   private boolean isConnected=false;
106
107   private boolean isAuthed=false;
108
109   private Thread connectThread=null;
110   private Object lock=new Object();
111
112   boolean x11_forwarding=false;
113   boolean agent_forwarding=false;
114
115   InputStream in=null;
116   OutputStream out=null;
117
118   static Random random;
119
120   Buffer buf;
121   Packet packet;
122
123   SocketFactory socket_factory=null;
124
125   private java.util.Hashtable config=null;
126
127   private Proxy proxy=null;
128   private UserInfo userinfo;
129
130   private String hostKeyAlias=null;
131   private int serverAliveInterval=0;
132   private int serverAliveCountMax=1;
133
134   protected boolean daemon_thread=false;
135
136   private long kex_start_time=0L;
137
138   String host="127.0.0.1";
139   int port=22;
140
141   String username=null;
142   byte[] password=null;
143
144   JSch jsch;
145
146   Session(JSch jsch) throws JSchException{
147     super();
148     this.jsch=jsch;
149     buf=new Buffer();
150     packet=new Packet(buf);
151   }
152
153   public void connect() throws JSchException{
154     connect(timeout);
155   }
156
157   public void connect(int connectTimeout) throws JSchException{
158     if(isConnected){
159       throw new JSchException("session is already connected");
160     }
161
162     io=new IO();
163     if(random==null){
164       try{
165         Class c=Class.forName(getConfig("random"));
166         random=(Random)(c.newInstance());
167       }
168       catch(Exception e){ 
169         throw new JSchException(e.toString(), e);
170       }
171     }
172     Packet.setRandom(random);
173
174     if(JSch.getLogger().isEnabled(Logger.INFO)){
175       JSch.getLogger().log(Logger.INFO, 
176                            "Connecting to "+host+" port "+port);
177     }
178
179     try {
180       int i, j;
181
182       if(proxy==null){
183         InputStream in;
184         OutputStream out;
185         if(socket_factory==null){
186           socket=Util.createSocket(host, port, connectTimeout);
187           in=socket.getInputStream();
188           out=socket.getOutputStream();
189         }
190         else{
191           socket=socket_factory.createSocket(host, port);
192           in=socket_factory.getInputStream(socket);
193           out=socket_factory.getOutputStream(socket);
194         }
195         //if(timeout>0){ socket.setSoTimeout(timeout); }
196         socket.setTcpNoDelay(true);
197         io.setInputStream(in);
198         io.setOutputStream(out);
199       }
200       else{
201         synchronized(proxy){
202           proxy.connect(socket_factory, host, port, connectTimeout);
203           io.setInputStream(proxy.getInputStream());
204           io.setOutputStream(proxy.getOutputStream());
205           socket=proxy.getSocket();
206         }
207       }
208
209       if(connectTimeout>0 && socket!=null){
210         socket.setSoTimeout(connectTimeout);
211       }
212
213       isConnected=true;
214
215       if(JSch.getLogger().isEnabled(Logger.INFO)){
216         JSch.getLogger().log(Logger.INFO, 
217                              "Connection established");
218       }
219
220       jsch.addSession(this);
221
222       {
223         // Some Cisco devices will miss to read '\n' if it is sent separately.
224         byte[] foo=new byte[V_C.length+1];
225         System.arraycopy(V_C, 0, foo, 0, V_C.length);
226         foo[foo.length-1]=(byte)'\n';
227         io.put(foo, 0, foo.length);
228       }
229
230       while(true){
231         i=0;
232         j=0;
233         while(i<buf.buffer.length){
234           j=io.getByte();
235           if(j<0)break;
236           buf.buffer[i]=(byte)j; i++; 
237           if(j==10)break;
238         }
239         if(j<0){
240           throw new JSchException("connection is closed by foreign host");
241         }
242
243         if(buf.buffer[i-1]==10){    // 0x0a
244           i--;
245           if(i>0 && buf.buffer[i-1]==13){  // 0x0d
246             i--;
247           }
248         }
249
250         if(i<=3 || 
251            ((i!=buf.buffer.length) &&
252             (buf.buffer[0]!='S'||buf.buffer[1]!='S'||
253              buf.buffer[2]!='H'||buf.buffer[3]!='-'))){
254           // It must not start with 'SSH-'
255           //System.err.println(new String(buf.buffer, 0, i);
256           continue;
257         }
258
259         if(i==buf.buffer.length ||
260            i<7 ||                                      // SSH-1.99 or SSH-2.0
261            (buf.buffer[4]=='1' && buf.buffer[6]!='9')  // SSH-1.5
262            ){
263           throw new JSchException("invalid server's version string");
264         }
265         break;
266       }
267
268       V_S=new byte[i]; System.arraycopy(buf.buffer, 0, V_S, 0, i);
269       //System.err.println("V_S: ("+i+") ["+new String(V_S)+"]");
270
271       if(JSch.getLogger().isEnabled(Logger.INFO)){
272         JSch.getLogger().log(Logger.INFO, 
273                              "Remote version string: "+Util.byte2str(V_S));
274         JSch.getLogger().log(Logger.INFO, 
275                              "Local version string: "+Util.byte2str(V_C));
276       }
277
278       send_kexinit();
279
280       buf=read(buf);
281       if(buf.getCommand()!=SSH_MSG_KEXINIT){
282         in_kex=false;
283         throw new JSchException("invalid protocol: "+buf.getCommand());
284       }
285
286       if(JSch.getLogger().isEnabled(Logger.INFO)){
287         JSch.getLogger().log(Logger.INFO, 
288                              "SSH_MSG_KEXINIT received");
289       }
290
291       KeyExchange kex=receive_kexinit(buf);
292
293       while(true){
294         buf=read(buf);
295         if(kex.getState()==buf.getCommand()){
296           kex_start_time=System.currentTimeMillis();
297           boolean result=kex.next(buf);
298           if(!result){
299             //System.err.println("verify: "+result);
300             in_kex=false;
301             throw new JSchException("verify: "+result);
302           }
303         }
304         else{
305           in_kex=false;
306           throw new JSchException("invalid protocol(kex): "+buf.getCommand());
307         }
308         if(kex.getState()==KeyExchange.STATE_END){
309           break;
310         }
311       }
312
313       try{ checkHost(host, port, kex); }
314       catch(JSchException ee){
315         in_kex=false;
316         throw ee;
317       }
318
319       send_newkeys();
320
321       // receive SSH_MSG_NEWKEYS(21)
322       buf=read(buf);
323       //System.err.println("read: 21 ? "+buf.getCommand());
324       if(buf.getCommand()==SSH_MSG_NEWKEYS){
325
326         if(JSch.getLogger().isEnabled(Logger.INFO)){
327           JSch.getLogger().log(Logger.INFO, 
328                                "SSH_MSG_NEWKEYS received");
329         }
330
331         receive_newkeys(buf, kex);
332       }
333       else{
334         in_kex=false;
335         throw new JSchException("invalid protocol(newkyes): "+buf.getCommand());
336       }
337
338       boolean auth=false;
339       boolean auth_cancel=false;
340
341       UserAuth ua=null;
342       try{
343         Class c=Class.forName(getConfig("userauth.none"));
344         ua=(UserAuth)(c.newInstance());
345       }
346       catch(Exception e){ 
347         throw new JSchException(e.toString(), e);
348       }
349
350       auth=ua.start(this);
351
352       String cmethods=getConfig("PreferredAuthentications");
353       String[] cmethoda=Util.split(cmethods, ",");
354
355       String smethods=null;
356       if(!auth){
357         smethods=((UserAuthNone)ua).getMethods();
358         if(smethods!=null){
359           smethods=smethods.toLowerCase();
360         }
361         else{
362           // methods: publickey,password,keyboard-interactive
363           //smethods="publickey,password,keyboard-interactive";
364           smethods=cmethods;
365         }
366       }
367
368       String[] smethoda=Util.split(smethods, ",");
369
370       int methodi=0;
371
372       loop:
373       while(true){
374
375 //System.err.println("methods: "+methods);
376
377         while(!auth && 
378               cmethoda!=null && methodi<cmethoda.length){
379
380           String method=cmethoda[methodi++];
381           boolean acceptable=false;
382           for(int k=0; k<smethoda.length; k++){
383             if(smethoda[k].equals(method)){
384               acceptable=true;
385               break;
386             }
387           }
388           if(!acceptable){
389             continue;
390           }
391
392           //System.err.println("  method: "+method);
393
394           if(JSch.getLogger().isEnabled(Logger.INFO)){
395             String str="Authentications that can continue: ";
396             for(int k=methodi-1; k<cmethoda.length; k++){
397               str+=cmethoda[k];
398               if(k+1<cmethoda.length)
399                 str+=",";
400             }
401             JSch.getLogger().log(Logger.INFO, 
402                                  str);
403             JSch.getLogger().log(Logger.INFO, 
404                                  "Next authentication method: "+method);
405           }
406
407           ua=null;
408           try{
409             Class c=null;
410             if(getConfig("userauth."+method)!=null){
411               c=Class.forName(getConfig("userauth."+method));
412               ua=(UserAuth)(c.newInstance());
413             }
414           }
415           catch(Exception e){
416             if(JSch.getLogger().isEnabled(Logger.WARN)){
417               JSch.getLogger().log(Logger.WARN, 
418                                    "failed to load "+method+" method");
419             }
420           }
421
422           if(ua!=null){
423             auth_cancel=false;
424             try{ 
425               auth=ua.start(this); 
426               if(auth && 
427                  JSch.getLogger().isEnabled(Logger.INFO)){
428                 JSch.getLogger().log(Logger.INFO, 
429                                      "Authentication succeeded ("+method+").");
430               }
431             }
432             catch(JSchAuthCancelException ee){
433               auth_cancel=true;
434             }
435             catch(JSchPartialAuthException ee){
436               String tmp = smethods;
437               smethods=ee.getMethods();
438               smethoda=Util.split(smethods, ",");
439               if(!tmp.equals(smethods)){
440                 methodi=0;
441               }
442               //System.err.println("PartialAuth: "+methods);
443               auth_cancel=false;
444               continue loop;
445             }
446             catch(RuntimeException ee){
447               throw ee;
448             }
449             catch(Exception ee){
450               //System.err.println("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures
451               break loop;
452             }
453           }
454         }
455         break;
456       }
457
458       if(!auth){
459         if(auth_cancel)
460           throw new JSchException("Auth cancel");
461         throw new JSchException("Auth fail");
462       }
463
464       if(connectTimeout>0 || timeout>0){
465         socket.setSoTimeout(timeout);
466       }
467
468       isAuthed=true;
469
470       synchronized(lock){
471         if(isConnected){
472           connectThread=new Thread(this);
473           connectThread.setName("Connect thread "+host+" session");
474           if(daemon_thread){
475             connectThread.setDaemon(daemon_thread);
476           }
477           connectThread.start();
478         }
479         else{
480           // The session has been already down and
481           // we don't have to start new thread.
482         }
483       }
484     }
485     catch(Exception e) {
486       in_kex=false;
487       if(isConnected){
488         try{
489           packet.reset();
490           buf.putByte((byte)SSH_MSG_DISCONNECT);
491           buf.putInt(3);
492           buf.putString(Util.str2byte(e.toString()));
493           buf.putString(Util.str2byte("en"));
494           write(packet);
495           disconnect();
496         }
497         catch(Exception ee){
498         }
499       }
500       isConnected=false;
501       //e.printStackTrace();
502       if(e instanceof RuntimeException) throw (RuntimeException)e;
503       if(e instanceof JSchException) throw (JSchException)e;
504       throw new JSchException("Session.connect: "+e);
505     }
506     finally{
507       Util.bzero(this.password);
508       this.password=null;
509     }
510   }
511
512   private KeyExchange receive_kexinit(Buffer buf) throws Exception {
513     int j=buf.getInt();
514     if(j!=buf.getLength()){    // packet was compressed and
515       buf.getByte();           // j is the size of deflated packet.
516       I_S=new byte[buf.index-5];
517     }
518     else{
519       I_S=new byte[j-1-buf.getByte()];
520     }
521    System.arraycopy(buf.buffer, buf.s, I_S, 0, I_S.length);
522
523    if(!in_kex){     // We are in rekeying activated by the remote!
524      send_kexinit();
525    }
526
527     guess=KeyExchange.guess(I_S, I_C);
528     if(guess==null){
529       throw new JSchException("Algorithm negotiation fail");
530     }
531
532     if(!isAuthed &&
533        (guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS].equals("none") ||
534         (guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC].equals("none")))){
535       throw new JSchException("NONE Cipher should not be chosen before authentification is successed.");
536     }
537
538     KeyExchange kex=null;
539     try{
540       Class c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_KEX_ALGS]));
541       kex=(KeyExchange)(c.newInstance());
542     }
543     catch(Exception e){ 
544       throw new JSchException(e.toString(), e);
545     }
546
547     kex.init(this, V_S, V_C, I_S, I_C);
548     return kex;
549   }
550
551   private boolean in_kex=false;
552   public void rekey() throws Exception {
553     send_kexinit();
554   }
555   private void send_kexinit() throws Exception {
556     if(in_kex)
557       return;
558
559     String cipherc2s=getConfig("cipher.c2s");
560     String ciphers2c=getConfig("cipher.s2c");
561
562     String[] not_available=checkCiphers(getConfig("CheckCiphers"));
563     if(not_available!=null && not_available.length>0){
564       cipherc2s=Util.diffString(cipherc2s, not_available);
565       ciphers2c=Util.diffString(ciphers2c, not_available);
566       if(cipherc2s==null || ciphers2c==null){
567         throw new JSchException("There are not any available ciphers.");
568       }
569     }
570
571     in_kex=true;
572     kex_start_time=System.currentTimeMillis();
573
574     // byte      SSH_MSG_KEXINIT(20)
575     // byte[16]  cookie (random bytes)
576     // string    kex_algorithms
577     // string    server_host_key_algorithms
578     // string    encryption_algorithms_client_to_server
579     // string    encryption_algorithms_server_to_client
580     // string    mac_algorithms_client_to_server
581     // string    mac_algorithms_server_to_client
582     // string    compression_algorithms_client_to_server
583     // string    compression_algorithms_server_to_client
584     // string    languages_client_to_server
585     // string    languages_server_to_client
586     Buffer buf = new Buffer();                // send_kexinit may be invoked
587     Packet packet = new Packet(buf);          // by user thread.
588     packet.reset();
589     buf.putByte((byte) SSH_MSG_KEXINIT);
590     synchronized(random){
591       random.fill(buf.buffer, buf.index, 16); buf.skip(16);
592     }
593     buf.putString(Util.str2byte(getConfig("kex")));
594     buf.putString(Util.str2byte(getConfig("server_host_key")));
595     buf.putString(Util.str2byte(cipherc2s));
596     buf.putString(Util.str2byte(ciphers2c));
597     buf.putString(Util.str2byte(getConfig("mac.c2s")));
598     buf.putString(Util.str2byte(getConfig("mac.s2c")));
599     buf.putString(Util.str2byte(getConfig("compression.c2s")));
600     buf.putString(Util.str2byte(getConfig("compression.s2c")));
601     buf.putString(Util.str2byte(getConfig("lang.c2s")));
602     buf.putString(Util.str2byte(getConfig("lang.s2c")));
603     buf.putByte((byte)0);
604     buf.putInt(0);
605
606     buf.setOffSet(5);
607     I_C=new byte[buf.getLength()];
608     buf.getByte(I_C);
609
610     write(packet);
611
612     if(JSch.getLogger().isEnabled(Logger.INFO)){
613       JSch.getLogger().log(Logger.INFO, 
614                            "SSH_MSG_KEXINIT sent");
615     }
616   }
617
618   private void send_newkeys() throws Exception {
619     // send SSH_MSG_NEWKEYS(21)
620     packet.reset();
621     buf.putByte((byte)SSH_MSG_NEWKEYS);
622     write(packet);
623
624     if(JSch.getLogger().isEnabled(Logger.INFO)){
625       JSch.getLogger().log(Logger.INFO, 
626                            "SSH_MSG_NEWKEYS sent");
627     }
628   }
629
630   private void checkHost(String chost, int port, KeyExchange kex) throws JSchException {
631     String shkc=getConfig("StrictHostKeyChecking");
632
633     if(hostKeyAlias!=null){
634       chost=hostKeyAlias;
635     }
636
637     //System.err.println("shkc: "+shkc);
638
639     byte[] K_S=kex.getHostKey();
640     String key_type=kex.getKeyType();
641     String key_fprint=kex.getFingerPrint();
642
643     if(hostKeyAlias==null && port!=22){
644       chost=("["+chost+"]:"+port);
645     }
646
647 //    hostkey=new HostKey(chost, K_S);
648
649     HostKeyRepository hkr=jsch.getHostKeyRepository();
650     int i=0;
651     synchronized(hkr){
652       i=hkr.check(chost, K_S);
653     }
654
655     boolean insert=false;
656
657     if((shkc.equals("ask") || shkc.equals("yes")) &&
658        i==HostKeyRepository.CHANGED){
659       String file=null;
660       synchronized(hkr){
661         file=hkr.getKnownHostsRepositoryID();
662       }
663       if(file==null){file="known_hosts";}
664
665       boolean b=false;
666
667       if(userinfo!=null){
668         String message=
669 "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"+
670 "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"+
671 "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"+
672 "It is also possible that the "+key_type+" host key has just been changed.\n"+
673 "The fingerprint for the "+key_type+" key sent by the remote host is\n"+
674 key_fprint+".\n"+
675 "Please contact your system administrator.\n"+
676 "Add correct host key in "+file+" to get rid of this message.";
677
678         if(shkc.equals("ask")){
679           b=userinfo.promptYesNo(message+
680                                  "\nDo you want to delete the old key and insert the new key?");
681         }
682         else{  // shkc.equals("yes")
683           userinfo.showMessage(message);
684         }
685       }
686
687       if(!b){
688         throw new JSchException("HostKey has been changed: "+chost);
689       }
690
691       synchronized(hkr){
692         hkr.remove(chost, 
693                    (key_type.equals("DSA") ? "ssh-dss" : "ssh-rsa"), 
694                    null);
695         insert=true;
696       }
697     }
698
699     if((shkc.equals("ask") || shkc.equals("yes")) &&
700        (i!=HostKeyRepository.OK) && !insert){
701       if(shkc.equals("yes")){
702         throw new JSchException("reject HostKey: "+host);
703       }
704       //System.err.println("finger-print: "+key_fprint);
705       if(userinfo!=null){
706         boolean foo=userinfo.promptYesNo(
707 "The authenticity of host '"+host+"' can't be established.\n"+
708 key_type+" key fingerprint is "+key_fprint+".\n"+
709 "Are you sure you want to continue connecting?"
710                                          );
711         if(!foo){
712           throw new JSchException("reject HostKey: "+host);
713         }
714         insert=true;
715       }
716       else{
717         if(i==HostKeyRepository.NOT_INCLUDED) 
718           throw new JSchException("UnknownHostKey: "+host+". "+key_type+" key fingerprint is "+key_fprint);
719         else 
720           throw new JSchException("HostKey has been changed: "+host);
721       }
722     }
723
724     if(shkc.equals("no") && 
725        HostKeyRepository.NOT_INCLUDED==i){
726       insert=true;
727     }
728
729     if(i==HostKeyRepository.OK &&
730        JSch.getLogger().isEnabled(Logger.INFO)){
731       JSch.getLogger().log(Logger.INFO, 
732                            "Host '"+host+"' is known and mathces the "+key_type+" host key");
733     }
734
735     if(insert &&
736        JSch.getLogger().isEnabled(Logger.WARN)){
737       JSch.getLogger().log(Logger.WARN, 
738                            "Permanently added '"+host+"' ("+key_type+") to the list of known hosts.");
739     }
740
741     String hkh=getConfig("HashKnownHosts");
742     if(hkh.equals("yes") && (hkr instanceof KnownHosts)){
743       hostkey=((KnownHosts)hkr).createHashedHostKey(chost, K_S);
744     }
745     else{
746       hostkey=new HostKey(chost, K_S);
747     }
748
749     if(insert){
750       synchronized(hkr){
751         hkr.add(hostkey, userinfo);
752       }
753
754     }
755
756   }
757
758 //public void start(){ (new Thread(this)).start();  }
759
760   public Channel openChannel(String type) throws JSchException{
761     if(!isConnected){
762       throw new JSchException("session is down");
763     }
764     try{
765       Channel channel=Channel.getChannel(type);
766       addChannel(channel);
767       channel.init();
768       return channel;
769     }
770     catch(Exception e){
771       //e.printStackTrace();
772     }
773     return null;
774   }
775
776   // encode will bin invoked in write with synchronization.
777   public void encode(Packet packet) throws Exception{
778 //System.err.println("encode: "+packet.buffer.getCommand());
779 //System.err.println("        "+packet.buffer.index);
780 //if(packet.buffer.getCommand()==96){
781 //Thread.dumpStack();
782 //}
783     if(deflater!=null){
784       packet.buffer.index=deflater.compress(packet.buffer.buffer, 
785                                             5, packet.buffer.index);
786     }
787     if(c2scipher!=null){
788       //packet.padding(c2scipher.getIVSize());
789       packet.padding(c2scipher_size);
790       int pad=packet.buffer.buffer[4];
791       synchronized(random){
792         random.fill(packet.buffer.buffer, packet.buffer.index-pad, pad);
793       }
794     }
795     else{
796       packet.padding(8);
797     }
798
799     if(c2smac!=null){
800       c2smac.update(seqo);
801       c2smac.update(packet.buffer.buffer, 0, packet.buffer.index);
802       c2smac.doFinal(packet.buffer.buffer, packet.buffer.index);
803     }
804     if(c2scipher!=null){
805       byte[] buf=packet.buffer.buffer;
806       c2scipher.update(buf, 0, packet.buffer.index, buf, 0);
807     }
808     if(c2smac!=null){
809       packet.buffer.skip(c2smac.getBlockSize());
810     }
811   }
812
813   int[] uncompress_len=new int[1];
814
815   private int s2ccipher_size=8;
816   private int c2scipher_size=8;
817   public Buffer read(Buffer buf) throws Exception{
818     int j=0;
819     while(true){
820       buf.reset();
821       io.getByte(buf.buffer, buf.index, s2ccipher_size); 
822       buf.index+=s2ccipher_size;
823       if(s2ccipher!=null){
824         s2ccipher.update(buf.buffer, 0, s2ccipher_size, buf.buffer, 0);
825       }
826       j=((buf.buffer[0]<<24)&0xff000000)|
827         ((buf.buffer[1]<<16)&0x00ff0000)|
828         ((buf.buffer[2]<< 8)&0x0000ff00)|
829         ((buf.buffer[3]    )&0x000000ff);
830       // RFC 4253 6.1. Maximum Packet Length
831       if(j<5 || j>PACKET_MAX_SIZE){
832         start_discard(buf, s2ccipher, s2cmac, j, PACKET_MAX_SIZE);
833       }
834       int need = j+4-s2ccipher_size;
835       //if(need<0){
836       //  throw new IOException("invalid data");
837       //}
838       if((buf.index+need)>buf.buffer.length){
839         byte[] foo=new byte[buf.index+need];
840         System.arraycopy(buf.buffer, 0, foo, 0, buf.index);
841         buf.buffer=foo;
842       }
843
844       if((need%s2ccipher_size)!=0){
845         String message="Bad packet length "+need;
846         if(JSch.getLogger().isEnabled(Logger.FATAL)){
847           JSch.getLogger().log(Logger.FATAL, message); 
848         }
849         start_discard(buf, s2ccipher, s2cmac, j, PACKET_MAX_SIZE-s2ccipher_size);
850       }
851
852       if(need>0){
853         io.getByte(buf.buffer, buf.index, need); buf.index+=(need);
854         if(s2ccipher!=null){
855           s2ccipher.update(buf.buffer, s2ccipher_size, need, buf.buffer, s2ccipher_size);
856         }
857       }
858
859       if(s2cmac!=null){
860         s2cmac.update(seqi);
861         s2cmac.update(buf.buffer, 0, buf.index);
862
863         s2cmac.doFinal(s2cmac_result1, 0);
864         io.getByte(s2cmac_result2, 0, s2cmac_result2.length);
865         if(!java.util.Arrays.equals(s2cmac_result1, s2cmac_result2)){
866           if(need > PACKET_MAX_SIZE){
867             throw new IOException("MAC Error");
868           }
869           start_discard(buf, s2ccipher, s2cmac, j, PACKET_MAX_SIZE-need);
870           continue;
871         }
872       }
873
874       seqi++;
875
876       if(inflater!=null){
877         //inflater.uncompress(buf);
878         int pad=buf.buffer[4];
879         uncompress_len[0]=buf.index-5-pad;
880         byte[] foo=inflater.uncompress(buf.buffer, 5, uncompress_len);
881         if(foo!=null){
882           buf.buffer=foo;
883           buf.index=5+uncompress_len[0];
884         }
885         else{
886           System.err.println("fail in inflater");
887           break;
888         }
889       }
890
891       int type=buf.getCommand()&0xff;
892       //System.err.println("read: "+type);
893       if(type==SSH_MSG_DISCONNECT){
894         buf.rewind();
895         buf.getInt();buf.getShort();
896         int reason_code=buf.getInt();
897         byte[] description=buf.getString();
898         byte[] language_tag=buf.getString();
899         throw new JSchException("SSH_MSG_DISCONNECT: "+
900                                     reason_code+
901                                 " "+Util.byte2str(description)+
902                                 " "+Util.byte2str(language_tag));
903         //break;
904       }
905       else if(type==SSH_MSG_IGNORE){
906       }
907       else if(type==SSH_MSG_UNIMPLEMENTED){
908         buf.rewind();
909         buf.getInt();buf.getShort();
910         int reason_id=buf.getInt();
911         if(JSch.getLogger().isEnabled(Logger.INFO)){
912           JSch.getLogger().log(Logger.INFO, 
913                                "Received SSH_MSG_UNIMPLEMENTED for "+reason_id);
914         }
915       }
916       else if(type==SSH_MSG_DEBUG){
917         buf.rewind();
918         buf.getInt();buf.getShort();
919 /*
920         byte always_display=(byte)buf.getByte();
921         byte[] message=buf.getString();
922         byte[] language_tag=buf.getString();
923         System.err.println("SSH_MSG_DEBUG:"+
924                            " "+Util.byte2str(message)+
925                            " "+Util.byte2str(language_tag));
926 */
927       }
928       else if(type==SSH_MSG_CHANNEL_WINDOW_ADJUST){
929           buf.rewind();
930           buf.getInt();buf.getShort();
931           Channel c=Channel.getChannel(buf.getInt(), this);
932           if(c==null){
933           }
934           else{
935             c.addRemoteWindowSize(buf.getInt()); 
936           }
937       }
938       else if(type==UserAuth.SSH_MSG_USERAUTH_SUCCESS){
939         isAuthed=true;
940         if(inflater==null && deflater==null){
941           String method;
942           method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
943           initDeflater(method);
944
945           method=guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC];
946           initInflater(method);
947         }
948         break;
949       }
950       else{
951         break;
952       }
953     }
954     buf.rewind();
955     return buf;
956   }
957
958   private void start_discard(Buffer buf, Cipher cipher, MAC mac, 
959                              int packet_length, int discard) throws JSchException, IOException{
960     MAC discard_mac = null;
961
962     if(!cipher.isCBC()){
963       throw new JSchException("Packet corrupt");
964     }
965
966     if(packet_length!=PACKET_MAX_SIZE && mac != null){
967       discard_mac = mac;
968     }
969
970     discard -= buf.index;
971
972     while(discard>0){
973       buf.reset();
974       int len = discard>buf.buffer.length ? buf.buffer.length : discard;
975       io.getByte(buf.buffer, 0, len);
976       if(discard_mac!=null){
977         discard_mac.update(buf.buffer, 0, len);
978       }
979       discard -= len;
980     }
981
982     if(discard_mac!=null){
983       discard_mac.doFinal(buf.buffer, 0);
984     }
985
986     throw new JSchException("Packet corrupt");
987   }
988
989   byte[] getSessionId(){
990     return session_id;
991   }
992
993   private void receive_newkeys(Buffer buf, KeyExchange kex) throws Exception {
994     updateKeys(kex);
995     in_kex=false;
996   }
997   private void updateKeys(KeyExchange kex) throws Exception{
998     byte[] K=kex.getK();
999     byte[] H=kex.getH();
1000     HASH hash=kex.getHash();
1001
1002 //    String[] guess=kex.guess;
1003
1004     if(session_id==null){
1005       session_id=new byte[H.length];
1006       System.arraycopy(H, 0, session_id, 0, H.length);
1007     }
1008
1009     /*
1010       Initial IV client to server:     HASH (K || H || "A" || session_id)
1011       Initial IV server to client:     HASH (K || H || "B" || session_id)
1012       Encryption key client to server: HASH (K || H || "C" || session_id)
1013       Encryption key server to client: HASH (K || H || "D" || session_id)
1014       Integrity key client to server:  HASH (K || H || "E" || session_id)
1015       Integrity key server to client:  HASH (K || H || "F" || session_id)
1016     */
1017
1018     buf.reset();
1019     buf.putMPInt(K);
1020     buf.putByte(H);
1021     buf.putByte((byte)0x41);
1022     buf.putByte(session_id);
1023     hash.update(buf.buffer, 0, buf.index);
1024     IVc2s=hash.digest();
1025
1026     int j=buf.index-session_id.length-1;
1027
1028     buf.buffer[j]++;
1029     hash.update(buf.buffer, 0, buf.index);
1030     IVs2c=hash.digest();
1031
1032     buf.buffer[j]++;
1033     hash.update(buf.buffer, 0, buf.index);
1034     Ec2s=hash.digest();
1035
1036     buf.buffer[j]++;
1037     hash.update(buf.buffer, 0, buf.index);
1038     Es2c=hash.digest();
1039
1040     buf.buffer[j]++;
1041     hash.update(buf.buffer, 0, buf.index);
1042     MACc2s=hash.digest();
1043
1044     buf.buffer[j]++;
1045     hash.update(buf.buffer, 0, buf.index);
1046     MACs2c=hash.digest();
1047
1048     try{
1049       Class c;
1050       String method;
1051   
1052       method=guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC];
1053       c=Class.forName(getConfig(method));
1054       s2ccipher=(Cipher)(c.newInstance());
1055       while(s2ccipher.getBlockSize()>Es2c.length){
1056         buf.reset();
1057         buf.putMPInt(K);
1058         buf.putByte(H);
1059         buf.putByte(Es2c);
1060         hash.update(buf.buffer, 0, buf.index);
1061         byte[] foo=hash.digest();
1062         byte[] bar=new byte[Es2c.length+foo.length];
1063         System.arraycopy(Es2c, 0, bar, 0, Es2c.length);
1064         System.arraycopy(foo, 0, bar, Es2c.length, foo.length);
1065         Es2c=bar;
1066       }
1067       s2ccipher.init(Cipher.DECRYPT_MODE, Es2c, IVs2c);
1068       s2ccipher_size=s2ccipher.getIVSize();
1069
1070       method=guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC];
1071       c=Class.forName(getConfig(method));
1072       s2cmac=(MAC)(c.newInstance());
1073       s2cmac.init(MACs2c);
1074       //mac_buf=new byte[s2cmac.getBlockSize()];
1075       s2cmac_result1=new byte[s2cmac.getBlockSize()];
1076       s2cmac_result2=new byte[s2cmac.getBlockSize()];
1077
1078       method=guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS];
1079       c=Class.forName(getConfig(method));
1080       c2scipher=(Cipher)(c.newInstance());
1081       while(c2scipher.getBlockSize()>Ec2s.length){
1082         buf.reset();
1083         buf.putMPInt(K);
1084         buf.putByte(H);
1085         buf.putByte(Ec2s);
1086         hash.update(buf.buffer, 0, buf.index);
1087         byte[] foo=hash.digest();
1088         byte[] bar=new byte[Ec2s.length+foo.length];
1089         System.arraycopy(Ec2s, 0, bar, 0, Ec2s.length);
1090         System.arraycopy(foo, 0, bar, Ec2s.length, foo.length);
1091         Ec2s=bar;
1092       }
1093       c2scipher.init(Cipher.ENCRYPT_MODE, Ec2s, IVc2s);
1094       c2scipher_size=c2scipher.getIVSize();
1095
1096       method=guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS];
1097       c=Class.forName(getConfig(method));
1098       c2smac=(MAC)(c.newInstance());
1099       c2smac.init(MACc2s);
1100
1101       method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
1102       initDeflater(method);
1103
1104       method=guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC];
1105       initInflater(method);
1106     }
1107     catch(Exception e){ 
1108       if(e instanceof JSchException)
1109         throw e;
1110       throw new JSchException(e.toString(), e);
1111       //System.err.println("updatekeys: "+e); 
1112     }
1113   }
1114
1115   /*public*/ /*synchronized*/ void write(Packet packet, Channel c, int length) throws Exception{
1116     long t = getTimeout();
1117     while(true){
1118       if(in_kex){
1119         if(t>0L && (System.currentTimeMillis()-kex_start_time)>t){
1120           throw new JSchException("timeout in wating for rekeying process.");
1121         }
1122         try{Thread.sleep(10);}
1123         catch(java.lang.InterruptedException e){};
1124         continue;
1125       }
1126       synchronized(c){
1127         if(c.rwsize>=length){
1128           c.rwsize-=length;
1129           break;
1130         }
1131       }
1132       if(c.close || !c.isConnected()){
1133         throw new IOException("channel is broken");
1134       }
1135
1136       boolean sendit=false;
1137       int s=0;
1138       byte command=0;
1139       int recipient=-1;
1140       synchronized(c){
1141         if(c.rwsize>0){
1142           long len=c.rwsize;
1143           if(len>length){
1144             len=length;
1145           }
1146           if(len!=length){
1147             s=packet.shift((int)len, (c2smac!=null ? c2smac.getBlockSize() : 0));
1148           }
1149           command=packet.buffer.getCommand();
1150           recipient=c.getRecipient();
1151           length-=len;
1152           c.rwsize-=len;
1153           sendit=true;
1154         }
1155       }
1156       if(sendit){
1157         _write(packet);
1158         if(length==0){
1159           return;
1160         }
1161         packet.unshift(command, recipient, s, length);
1162       }
1163
1164       synchronized(c){
1165         if(in_kex){
1166           continue;
1167         }
1168         if(c.rwsize>=length){
1169           c.rwsize-=length;
1170           break;
1171         }
1172         try{ 
1173           c.notifyme++;
1174           c.wait(100); 
1175         }
1176         catch(java.lang.InterruptedException e){
1177         }
1178         finally{
1179           c.notifyme--;
1180         }
1181       }
1182
1183     }
1184     _write(packet);
1185   }
1186
1187   public void write(Packet packet) throws Exception{
1188     // System.err.println("in_kex="+in_kex+" "+(packet.buffer.getCommand()));
1189     long t = getTimeout();
1190     while(in_kex){
1191       if(t>0L && (System.currentTimeMillis()-kex_start_time)>t){
1192         throw new JSchException("timeout in wating for rekeying process.");
1193       }
1194       byte command=packet.buffer.getCommand();
1195       //System.err.println("command: "+command);
1196       if(command==SSH_MSG_KEXINIT ||
1197          command==SSH_MSG_NEWKEYS ||
1198          command==SSH_MSG_KEXDH_INIT ||
1199          command==SSH_MSG_KEXDH_REPLY ||
1200          command==SSH_MSG_KEX_DH_GEX_GROUP ||
1201          command==SSH_MSG_KEX_DH_GEX_INIT ||
1202          command==SSH_MSG_KEX_DH_GEX_REPLY ||
1203          command==SSH_MSG_KEX_DH_GEX_REQUEST ||
1204          command==SSH_MSG_DISCONNECT){
1205         break;
1206       }
1207       try{Thread.sleep(10);}
1208       catch(java.lang.InterruptedException e){};
1209     }
1210     _write(packet);
1211   }
1212
1213   private void _write(Packet packet) throws Exception{
1214     synchronized(lock){
1215       encode(packet);
1216       if(io!=null){
1217         io.put(packet);
1218         seqo++;
1219       }
1220     }
1221   }
1222
1223   Runnable thread;
1224   public void run(){
1225     thread=this;
1226
1227     byte[] foo;
1228     Buffer buf=new Buffer();
1229     Packet packet=new Packet(buf);
1230     int i=0;
1231     Channel channel;
1232     int[] start=new int[1];
1233     int[] length=new int[1];
1234     KeyExchange kex=null;
1235
1236     int stimeout=0;
1237     try{
1238       while(isConnected &&
1239             thread!=null){
1240         try{
1241           buf=read(buf);
1242           stimeout=0;
1243         }
1244         catch(InterruptedIOException/*SocketTimeoutException*/ ee){
1245           if(!in_kex && stimeout<serverAliveCountMax){
1246             sendKeepAliveMsg();
1247             stimeout++;
1248             continue;
1249           }
1250           throw ee;
1251         }
1252
1253         int msgType=buf.getCommand()&0xff;
1254
1255         if(kex!=null && kex.getState()==msgType){
1256           kex_start_time=System.currentTimeMillis();
1257           boolean result=kex.next(buf);
1258           if(!result){
1259             throw new JSchException("verify: "+result);
1260           }
1261           continue;
1262         }
1263
1264         switch(msgType){
1265         case SSH_MSG_KEXINIT:
1266 //System.err.println("KEXINIT");
1267           kex=receive_kexinit(buf);
1268           break;
1269
1270         case SSH_MSG_NEWKEYS:
1271 //System.err.println("NEWKEYS");
1272           send_newkeys();
1273           receive_newkeys(buf, kex);
1274           kex=null;
1275           break;
1276
1277         case SSH_MSG_CHANNEL_DATA:
1278           buf.getInt(); 
1279           buf.getByte(); 
1280           buf.getByte(); 
1281           i=buf.getInt(); 
1282           channel=Channel.getChannel(i, this);
1283           foo=buf.getString(start, length);
1284           if(channel==null){
1285             break;
1286           }
1287
1288           if(length[0]==0){
1289             break;
1290           }
1291
1292 try{
1293           channel.write(foo, start[0], length[0]);
1294 }
1295 catch(Exception e){
1296 //System.err.println(e);
1297   try{channel.disconnect();}catch(Exception ee){}
1298 break;
1299 }
1300           int len=length[0];
1301           channel.setLocalWindowSize(channel.lwsize-len);
1302           if(channel.lwsize<channel.lwsize_max/2){
1303             packet.reset();
1304             buf.putByte((byte)SSH_MSG_CHANNEL_WINDOW_ADJUST);
1305             buf.putInt(channel.getRecipient());
1306             buf.putInt(channel.lwsize_max-channel.lwsize);
1307             write(packet);
1308             channel.setLocalWindowSize(channel.lwsize_max);
1309           }
1310           break;
1311
1312         case SSH_MSG_CHANNEL_EXTENDED_DATA:
1313           buf.getInt();
1314           buf.getShort();
1315           i=buf.getInt();
1316           channel=Channel.getChannel(i, this);
1317           buf.getInt();                   // data_type_code == 1
1318           foo=buf.getString(start, length);
1319           //System.err.println("stderr: "+new String(foo,start[0],length[0]));
1320           if(channel==null){
1321             break;
1322           }
1323
1324           if(length[0]==0){
1325             break;
1326           }
1327
1328           channel.write_ext(foo, start[0], length[0]);
1329
1330           len=length[0];
1331           channel.setLocalWindowSize(channel.lwsize-len);
1332           if(channel.lwsize<channel.lwsize_max/2){
1333             packet.reset();
1334             buf.putByte((byte)SSH_MSG_CHANNEL_WINDOW_ADJUST);
1335             buf.putInt(channel.getRecipient());
1336             buf.putInt(channel.lwsize_max-channel.lwsize);
1337             write(packet);
1338             channel.setLocalWindowSize(channel.lwsize_max);
1339           }
1340           break;
1341
1342         case SSH_MSG_CHANNEL_WINDOW_ADJUST:
1343           buf.getInt(); 
1344           buf.getShort(); 
1345           i=buf.getInt(); 
1346           channel=Channel.getChannel(i, this);
1347           if(channel==null){
1348             break;
1349           }
1350           channel.addRemoteWindowSize(buf.getInt()); 
1351           break;
1352
1353         case SSH_MSG_CHANNEL_EOF:
1354           buf.getInt(); 
1355           buf.getShort(); 
1356           i=buf.getInt(); 
1357           channel=Channel.getChannel(i, this);
1358           if(channel!=null){
1359             //channel.eof_remote=true;
1360             //channel.eof();
1361             channel.eof_remote();
1362           }
1363           /*
1364           packet.reset();
1365           buf.putByte((byte)SSH_MSG_CHANNEL_EOF);
1366           buf.putInt(channel.getRecipient());
1367           write(packet);
1368           */
1369           break;
1370         case SSH_MSG_CHANNEL_CLOSE:
1371           buf.getInt(); 
1372           buf.getShort(); 
1373           i=buf.getInt(); 
1374           channel=Channel.getChannel(i, this);
1375           if(channel!=null){
1376 //            channel.close();
1377             channel.disconnect();
1378           }
1379           /*
1380           if(Channel.pool.size()==0){
1381             thread=null;
1382           }
1383           */
1384           break;
1385         case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
1386           buf.getInt(); 
1387           buf.getShort(); 
1388           i=buf.getInt(); 
1389           channel=Channel.getChannel(i, this);
1390           if(channel==null){
1391             //break;
1392           }
1393           int r=buf.getInt();
1394           long rws=buf.getUInt();
1395           int rps=buf.getInt();
1396
1397           channel.setRemoteWindowSize(rws);
1398           channel.setRemotePacketSize(rps);
1399           channel.setRecipient(r);
1400           break;
1401         case SSH_MSG_CHANNEL_OPEN_FAILURE:
1402           buf.getInt(); 
1403           buf.getShort(); 
1404           i=buf.getInt(); 
1405           channel=Channel.getChannel(i, this);
1406           if(channel==null){
1407             //break;
1408           }
1409           int reason_code=buf.getInt(); 
1410           //foo=buf.getString();  // additional textual information
1411           //foo=buf.getString();  // language tag 
1412           channel.exitstatus=reason_code;
1413           channel.close=true;
1414           channel.eof_remote=true;
1415           channel.setRecipient(0);
1416           break;
1417         case SSH_MSG_CHANNEL_REQUEST:
1418           buf.getInt(); 
1419           buf.getShort(); 
1420           i=buf.getInt(); 
1421           foo=buf.getString(); 
1422           boolean reply=(buf.getByte()!=0);
1423           channel=Channel.getChannel(i, this);
1424           if(channel!=null){
1425             byte reply_type=(byte)SSH_MSG_CHANNEL_FAILURE;
1426             if((Util.byte2str(foo)).equals("exit-status")){
1427               i=buf.getInt();             // exit-status
1428               channel.setExitStatus(i);
1429               reply_type=(byte)SSH_MSG_CHANNEL_SUCCESS;
1430             }
1431             if(reply){
1432               packet.reset();
1433               buf.putByte(reply_type);
1434               buf.putInt(channel.getRecipient());
1435               write(packet);
1436             }
1437           }
1438           else{
1439           }
1440           break;
1441         case SSH_MSG_CHANNEL_OPEN:
1442           buf.getInt(); 
1443           buf.getShort(); 
1444           foo=buf.getString(); 
1445           String ctyp=Util.byte2str(foo);
1446           if(!"forwarded-tcpip".equals(ctyp) &&
1447              !("x11".equals(ctyp) && x11_forwarding) &&
1448              !("auth-agent@openssh.com".equals(ctyp) && agent_forwarding)){
1449             //System.err.println("Session.run: CHANNEL OPEN "+ctyp); 
1450             //throw new IOException("Session.run: CHANNEL OPEN "+ctyp);
1451             packet.reset();
1452             buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_FAILURE);
1453             buf.putInt(buf.getInt());
1454             buf.putInt(Channel.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
1455             buf.putString(Util.empty);
1456             buf.putString(Util.empty);
1457             write(packet);
1458           }
1459           else{
1460             channel=Channel.getChannel(ctyp);
1461             addChannel(channel);
1462             channel.getData(buf);
1463             channel.init();
1464
1465             Thread tmp=new Thread(channel);
1466             tmp.setName("Channel "+ctyp+" "+host);
1467             if(daemon_thread){
1468               tmp.setDaemon(daemon_thread);
1469             }
1470             tmp.start();
1471             break;
1472           }
1473         case SSH_MSG_CHANNEL_SUCCESS:
1474           buf.getInt(); 
1475           buf.getShort(); 
1476           i=buf.getInt(); 
1477           channel=Channel.getChannel(i, this);
1478           if(channel==null){
1479             break;
1480           }
1481           channel.reply=1;
1482           break;
1483         case SSH_MSG_CHANNEL_FAILURE:
1484           buf.getInt(); 
1485           buf.getShort(); 
1486           i=buf.getInt(); 
1487           channel=Channel.getChannel(i, this);
1488           if(channel==null){
1489             break;
1490           }
1491           channel.reply=0;
1492           break;
1493         case SSH_MSG_GLOBAL_REQUEST:
1494           buf.getInt(); 
1495           buf.getShort(); 
1496           foo=buf.getString();       // request name
1497           reply=(buf.getByte()!=0);
1498           if(reply){
1499             packet.reset();
1500             buf.putByte((byte)SSH_MSG_REQUEST_FAILURE);
1501             write(packet);
1502           }
1503           break;
1504         case SSH_MSG_REQUEST_FAILURE:
1505         case SSH_MSG_REQUEST_SUCCESS:
1506           Thread t=grr.getThread();
1507           if(t!=null){
1508             grr.setReply(msgType==SSH_MSG_REQUEST_SUCCESS? 1 : 0);
1509             t.interrupt();
1510           }
1511           break;
1512         default:
1513           //System.err.println("Session.run: unsupported type "+msgType); 
1514           throw new IOException("Unknown SSH message type "+msgType);
1515         }
1516       }
1517     }
1518     catch(Exception e){
1519       in_kex=false;
1520       if(JSch.getLogger().isEnabled(Logger.INFO)){
1521         JSch.getLogger().log(Logger.INFO,
1522                              "Caught an exception, leaving main loop due to " + e.getMessage());
1523       }
1524       //System.err.println("# Session.run");
1525       //e.printStackTrace();
1526     }
1527     try{
1528       disconnect();
1529     }
1530     catch(NullPointerException e){
1531       //System.err.println("@1");
1532       //e.printStackTrace();
1533     }
1534     catch(Exception e){
1535       //System.err.println("@2");
1536       //e.printStackTrace();
1537     }
1538     isConnected=false;
1539   }
1540
1541   public void disconnect(){
1542     if(!isConnected) return;
1543     //System.err.println(this+": disconnect");
1544     //Thread.dumpStack();
1545     if(JSch.getLogger().isEnabled(Logger.INFO)){
1546       JSch.getLogger().log(Logger.INFO,
1547                            "Disconnecting from "+host+" port "+port);
1548     }
1549     /*
1550     for(int i=0; i<Channel.pool.size(); i++){
1551       try{
1552         Channel c=((Channel)(Channel.pool.elementAt(i)));
1553         if(c.session==this) c.eof();
1554       }
1555       catch(Exception e){
1556       }
1557     } 
1558     */
1559
1560     Channel.disconnect(this);
1561
1562     isConnected=false;
1563
1564     PortWatcher.delPort(this);
1565     ChannelForwardedTCPIP.delPort(this);
1566
1567     synchronized(lock){
1568       if(connectThread!=null){
1569         Thread.yield();
1570         connectThread.interrupt();
1571         connectThread=null;
1572       }
1573     }
1574     thread=null;
1575     try{
1576       if(io!=null){
1577         if(io.in!=null) io.in.close();
1578         if(io.out!=null) io.out.close();
1579         if(io.out_ext!=null) io.out_ext.close();
1580       }
1581       if(proxy==null){
1582         if(socket!=null)
1583           socket.close();
1584       }
1585       else{
1586         synchronized(proxy){
1587           proxy.close();          
1588         }
1589         proxy=null;
1590       }
1591     }
1592     catch(Exception e){
1593 //      e.printStackTrace();
1594     }
1595     io=null;
1596     socket=null;
1597 //    synchronized(jsch.pool){
1598 //      jsch.pool.removeElement(this);
1599 //    }
1600
1601     jsch.removeSession(this);
1602
1603     //System.gc();
1604   }
1605
1606   public int setPortForwardingL(int lport, String host, int rport) throws JSchException{
1607     return setPortForwardingL("127.0.0.1", lport, host, rport);
1608   }
1609   public int setPortForwardingL(String boundaddress, int lport, String host, int rport) throws JSchException{
1610     return setPortForwardingL(boundaddress, lport, host, rport, null);
1611   }
1612   public int setPortForwardingL(String boundaddress, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{
1613     PortWatcher pw=PortWatcher.addPort(this, boundaddress, lport, host, rport, ssf);
1614     Thread tmp=new Thread(pw);
1615     tmp.setName("PortWatcher Thread for "+host);
1616     if(daemon_thread){
1617       tmp.setDaemon(daemon_thread);
1618     }
1619     tmp.start();
1620     return pw.lport;
1621   }
1622   public void delPortForwardingL(int lport) throws JSchException{
1623     delPortForwardingL("127.0.0.1", lport);
1624   }
1625   public void delPortForwardingL(String boundaddress, int lport) throws JSchException{
1626     PortWatcher.delPort(this, boundaddress, lport);
1627   }
1628   public String[] getPortForwardingL() throws JSchException{
1629     return PortWatcher.getPortForwarding(this);
1630   }
1631
1632   public void setPortForwardingR(int rport, String host, int lport) throws JSchException{
1633     setPortForwardingR(null, rport, host, lport, (SocketFactory)null);
1634   }
1635   public void setPortForwardingR(String bind_address, int rport, String host, int lport) throws JSchException{
1636     setPortForwardingR(bind_address, rport, host, lport, (SocketFactory)null);
1637   }
1638   public void setPortForwardingR(int rport, String host, int lport, SocketFactory sf) throws JSchException{
1639     setPortForwardingR(null, rport, host, lport, sf);
1640   }
1641   public void setPortForwardingR(String bind_address, int rport, String host, int lport, SocketFactory sf) throws JSchException{
1642     ChannelForwardedTCPIP.addPort(this, bind_address, rport, host, lport, sf);
1643     setPortForwarding(bind_address, rport);
1644   }
1645
1646   public void setPortForwardingR(int rport, String daemon) throws JSchException{
1647     setPortForwardingR(null, rport, daemon, null);
1648   }
1649   public void setPortForwardingR(int rport, String daemon, Object[] arg) throws JSchException{
1650     setPortForwardingR(null, rport, daemon, arg);
1651   }
1652   public void setPortForwardingR(String bind_address, int rport, String daemon, Object[] arg) throws JSchException{
1653     ChannelForwardedTCPIP.addPort(this, bind_address, rport, daemon, arg);
1654     setPortForwarding(bind_address, rport);
1655   }
1656
1657   private class GlobalRequestReply{
1658     private Thread thread=null;
1659     private int reply=-1;
1660     void setThread(Thread thread){
1661       this.thread=thread;
1662       this.reply=-1;
1663     }
1664     Thread getThread(){ return thread; }
1665     void setReply(int reply){ this.reply=reply; }
1666     int getReply(){ return this.reply; }
1667   }
1668   private GlobalRequestReply grr=new GlobalRequestReply();
1669   private void setPortForwarding(String bind_address, int rport) throws JSchException{
1670     synchronized(grr){
1671     Buffer buf=new Buffer(100); // ??
1672     Packet packet=new Packet(buf);
1673
1674     String address_to_bind=ChannelForwardedTCPIP.normalize(bind_address);
1675
1676     try{
1677       // byte SSH_MSG_GLOBAL_REQUEST 80
1678       // string "tcpip-forward"
1679       // boolean want_reply
1680       // string  address_to_bind
1681       // uint32  port number to bind
1682       packet.reset();
1683       buf.putByte((byte) SSH_MSG_GLOBAL_REQUEST);
1684       buf.putString(Util.str2byte("tcpip-forward"));
1685 //      buf.putByte((byte)0);
1686       buf.putByte((byte)1);
1687       buf.putString(Util.str2byte(address_to_bind));
1688       buf.putInt(rport);
1689       write(packet);
1690     }
1691     catch(Exception e){
1692       if(e instanceof Throwable)
1693         throw new JSchException(e.toString(), (Throwable)e);
1694       throw new JSchException(e.toString());
1695     }
1696
1697     grr.setThread(Thread.currentThread());
1698     try{ Thread.sleep(10000);}
1699     catch(Exception e){
1700     }
1701     int reply=grr.getReply();
1702     grr.setThread(null);
1703     if(reply==0){
1704       throw new JSchException("remote port forwarding failed for listen port "+rport);
1705     }
1706     }
1707   }
1708   public void delPortForwardingR(int rport) throws JSchException{
1709     ChannelForwardedTCPIP.delPort(this, rport);
1710   }
1711
1712   private void initDeflater(String method) throws JSchException{
1713     if(method.equals("none")){
1714       deflater=null;
1715       return;
1716     }
1717     String foo=getConfig(method);
1718     if(foo!=null){
1719       if(method.equals("zlib") ||
1720          (isAuthed && method.equals("zlib@openssh.com"))){
1721         try{
1722           Class c=Class.forName(foo);
1723           deflater=(Compression)(c.newInstance());
1724           int level=6;
1725           try{ level=Integer.parseInt(getConfig("compression_level"));}
1726           catch(Exception ee){ }
1727           deflater.init(Compression.DEFLATER, level);
1728         }
1729         catch(Exception ee){
1730           throw new JSchException(ee.toString(), ee);
1731           //System.err.println(foo+" isn't accessible.");
1732         }
1733       }
1734     }
1735   }
1736   private void initInflater(String method) throws JSchException{
1737     if(method.equals("none")){
1738       inflater=null;
1739       return;
1740     }
1741     String foo=getConfig(method);
1742     if(foo!=null){
1743       if(method.equals("zlib") ||
1744          (isAuthed && method.equals("zlib@openssh.com"))){
1745         try{
1746           Class c=Class.forName(foo);
1747           inflater=(Compression)(c.newInstance());
1748           inflater.init(Compression.INFLATER, 0);
1749         }
1750         catch(Exception ee){
1751           throw new JSchException(ee.toString(), ee);
1752             //System.err.println(foo+" isn't accessible.");
1753         }
1754       }
1755     }
1756   }
1757
1758   void addChannel(Channel channel){
1759     channel.setSession(this);
1760   }
1761
1762   public void setProxy(Proxy proxy){ this.proxy=proxy; }
1763   public void setHost(String host){ this.host=host; }
1764   public void setPort(int port){ this.port=port; }
1765   void setUserName(String username){ this.username=username; }
1766   public void setUserInfo(UserInfo userinfo){ this.userinfo=userinfo; }
1767   public UserInfo getUserInfo(){ return userinfo; }
1768   public void setInputStream(InputStream in){ this.in=in; }
1769   public void setOutputStream(OutputStream out){ this.out=out; }
1770   public void setX11Host(String host){ ChannelX11.setHost(host); }
1771   public void setX11Port(int port){ ChannelX11.setPort(port); }
1772   public void setX11Cookie(String cookie){ ChannelX11.setCookie(cookie); }
1773   public void setPassword(String password){
1774     if(password!=null)
1775       this.password=Util.str2byte(password);
1776   }
1777   public void setPassword(byte[] password){ 
1778     if(password!=null){
1779       this.password=new byte[password.length];
1780       System.arraycopy(password, 0, this.password, 0, password.length);
1781     }
1782   }
1783
1784   public void setConfig(java.util.Properties newconf){
1785     setConfig((java.util.Hashtable)newconf);
1786   }
1787  
1788   public void setConfig(java.util.Hashtable newconf){
1789     synchronized(lock){
1790       if(config==null) 
1791         config=new java.util.Hashtable();
1792       for(java.util.Enumeration e=newconf.keys() ; e.hasMoreElements() ;) {
1793         String key=(String)(e.nextElement());
1794         config.put(key, (String)(newconf.get(key)));
1795       }
1796     }
1797   }
1798
1799   public void setConfig(String key, String value){
1800     synchronized(lock){ 
1801       if(config==null){
1802         config=new java.util.Hashtable();
1803       }
1804       config.put(key, value);
1805     }
1806   }
1807
1808   public String getConfig(String key){
1809     Object foo=null;
1810     if(config!=null){
1811       foo=config.get(key);
1812       if(foo instanceof String) return (String)foo;
1813     }
1814     foo=jsch.getConfig(key);
1815     if(foo instanceof String) return (String)foo;
1816     return null;
1817   }
1818
1819   public void setSocketFactory(SocketFactory sfactory){ 
1820     socket_factory=sfactory;
1821   }
1822   public boolean isConnected(){ return isConnected; }
1823   public int getTimeout(){ return timeout; }
1824   public void setTimeout(int timeout) throws JSchException {
1825     if(socket==null){
1826       if(timeout<0){
1827         throw new JSchException("invalid timeout value");
1828       }
1829       this.timeout=timeout;
1830       return;
1831     }
1832     try{
1833       socket.setSoTimeout(timeout);
1834       this.timeout=timeout;
1835     }
1836     catch(Exception e){
1837       if(e instanceof Throwable)
1838         throw new JSchException(e.toString(), (Throwable)e);
1839       throw new JSchException(e.toString());
1840     }
1841   }
1842   public String getServerVersion(){
1843     return Util.byte2str(V_S);
1844   }
1845   public String getClientVersion(){
1846     return Util.byte2str(V_C);
1847   }
1848   public void setClientVersion(String cv){
1849     V_C=Util.str2byte(cv);
1850   }
1851
1852   public void sendIgnore() throws Exception{
1853     Buffer buf=new Buffer();
1854     Packet packet=new Packet(buf);
1855     packet.reset();
1856     buf.putByte((byte)SSH_MSG_IGNORE);
1857     write(packet);
1858   }
1859
1860   private static final byte[] keepalivemsg=Util.str2byte("keepalive@jcraft.com");
1861   public void sendKeepAliveMsg() throws Exception{
1862     Buffer buf=new Buffer();
1863     Packet packet=new Packet(buf);
1864     packet.reset();
1865     buf.putByte((byte)SSH_MSG_GLOBAL_REQUEST);
1866     buf.putString(keepalivemsg);
1867     buf.putByte((byte)1);
1868     write(packet);
1869   }
1870   
1871   private HostKey hostkey=null;
1872   public HostKey getHostKey(){ return hostkey; }
1873   public String getHost(){return host;}
1874   public String getUserName(){return username;}
1875   public int getPort(){return port;}
1876   public void setHostKeyAlias(String hostKeyAlias){
1877     this.hostKeyAlias=hostKeyAlias;
1878   }
1879   public String getHostKeyAlias(){
1880     return hostKeyAlias;
1881   }
1882
1883   public void setServerAliveInterval(int interval) throws JSchException {
1884     setTimeout(interval);
1885     this.serverAliveInterval=interval;
1886   }
1887   public void setServerAliveCountMax(int count){
1888     this.serverAliveCountMax=count;
1889   }
1890
1891   public int getServerAliveInterval(){
1892     return this.serverAliveInterval;
1893   }
1894   public int getServerAliveCountMax(){
1895     return this.serverAliveCountMax;
1896   }
1897
1898   public void setDaemonThread(boolean enable){
1899     this.daemon_thread=enable;
1900   }
1901
1902   private String[] checkCiphers(String ciphers){
1903     if(ciphers==null || ciphers.length()==0)
1904       return null;
1905
1906     if(JSch.getLogger().isEnabled(Logger.INFO)){
1907       JSch.getLogger().log(Logger.INFO, 
1908                            "CheckCiphers: "+ciphers);
1909     }
1910
1911     java.util.Vector result=new java.util.Vector();
1912     String[] _ciphers=Util.split(ciphers, ",");
1913     for(int i=0; i<_ciphers.length; i++){
1914       if(!checkCipher(getConfig(_ciphers[i]))){
1915         result.addElement(_ciphers[i]);
1916       }
1917     }
1918     if(result.size()==0)
1919       return null;
1920     String[] foo=new String[result.size()];
1921     System.arraycopy(result.toArray(), 0, foo, 0, result.size());
1922
1923     if(JSch.getLogger().isEnabled(Logger.INFO)){
1924       for(int i=0; i<foo.length; i++){
1925         JSch.getLogger().log(Logger.INFO, 
1926                              foo[i]+" is not available.");
1927       }
1928     }
1929
1930     return foo;
1931   }
1932
1933   static boolean checkCipher(String cipher){
1934     try{
1935       Class c=Class.forName(cipher);
1936       Cipher _c=(Cipher)(c.newInstance());
1937       _c.init(Cipher.ENCRYPT_MODE,
1938               new byte[_c.getBlockSize()],
1939               new byte[_c.getIVSize()]);
1940       return true;
1941     }
1942     catch(Exception e){
1943       return false;
1944     }
1945   }
1946 }
This page took 0.259158 seconds and 4 git commands to generate.