From f7f7be8e03d0f2272ee4fca6a216631fe07aa2dd Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 19:16:35 +0100 Subject: [PATCH 01/16] allow the setting of a logger to the JSch instance to allow instance-specific logging. The static methods are kept untouched to keep backward compatibility --- src/main/java/com/jcraft/jsch/Channel.java | 31 ++- .../jcraft/jsch/ChannelDirectStreamLocal.java | 2 +- .../jcraft/jsch/ChannelForwardedTCPIP.java | 4 +- .../java/com/jcraft/jsch/Compression.java | 2 +- src/main/java/com/jcraft/jsch/DHECN.java | 7 +- src/main/java/com/jcraft/jsch/DHGEX.java | 13 +- src/main/java/com/jcraft/jsch/DHGN.java | 7 +- src/main/java/com/jcraft/jsch/DHXEC.java | 7 +- src/main/java/com/jcraft/jsch/JSch.java | 20 +- .../java/com/jcraft/jsch/KeyExchange.java | 37 +-- src/main/java/com/jcraft/jsch/KeyPair.java | 9 + .../java/com/jcraft/jsch/KeyPairDeferred.java | 2 +- .../java/com/jcraft/jsch/KeyPairPKCS8.java | 4 +- .../java/com/jcraft/jsch/PortWatcher.java | 3 + src/main/java/com/jcraft/jsch/Session.java | 223 +++++++++--------- .../java/com/jcraft/jsch/UserAuthNone.java | 8 +- .../com/jcraft/jsch/UserAuthPublicKey.java | 60 ++--- src/main/java/com/jcraft/jsch/UserInfo.java | 1 + .../java/com/jcraft/jsch/juz/Compression.java | 12 +- .../com/jcraft/jsch/jzlib/Compression.java | 16 +- src/test/java/com/jcraft/jsch/JSchTest.java | 45 ++++ 21 files changed, 300 insertions(+), 213 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/Channel.java b/src/main/java/com/jcraft/jsch/Channel.java index 479bf74a..0e6da7c2 100644 --- a/src/main/java/com/jcraft/jsch/Channel.java +++ b/src/main/java/com/jcraft/jsch/Channel.java @@ -45,38 +45,43 @@ public abstract class Channel implements Runnable{ static int index=0; private static Vector pool=new Vector<>(); - static Channel getChannel(String type){ + static Channel getChannel(String type, Session session){ + Channel ret = null; if(type.equals("session")){ - return new ChannelSession(); + ret = new ChannelSession(); } if(type.equals("shell")){ - return new ChannelShell(); + ret = new ChannelShell(); } if(type.equals("exec")){ - return new ChannelExec(); + ret = new ChannelExec(); } if(type.equals("x11")){ - return new ChannelX11(); + ret = new ChannelX11(); } if(type.equals("auth-agent@openssh.com")){ - return new ChannelAgentForwarding(); + ret = new ChannelAgentForwarding(); } if(type.equals("direct-tcpip")){ - return new ChannelDirectTCPIP(); + ret = new ChannelDirectTCPIP(); } if(type.equals("forwarded-tcpip")){ - return new ChannelForwardedTCPIP(); + ret = new ChannelForwardedTCPIP(); } if(type.equals("sftp")){ - return new ChannelSftp(); + ret = new ChannelSftp(); } if(type.equals("subsystem")){ - return new ChannelSubsystem(); + ret = new ChannelSubsystem(); } if(type.equals("direct-streamlocal@openssh.com")){ - return new ChannelDirectStreamLocal(); + ret = new ChannelDirectStreamLocal(); } - return null; + if (ret == null) { + return null; + } + ret.setSession(session); + return ret; } static Channel getChannel(int id, Session session){ synchronized(pool){ @@ -118,7 +123,7 @@ static void del(Channel c){ volatile int reply=0; volatile int connectTimeout=0; - private Session session; + protected Session session; int notifyme=0; diff --git a/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java b/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java index 351ab7d9..7ace8095 100644 --- a/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java +++ b/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java @@ -27,7 +27,7 @@ public class ChannelDirectStreamLocal extends ChannelDirectTCPIP { protected Packet genChannelOpenPacket() { if (socketPath == null) { - JSch.getLogger().log(Logger.FATAL, "socketPath must be set"); + session.getLogger().log(Logger.FATAL, "socketPath must be set"); throw new RuntimeException("socketPath must be set"); } diff --git a/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java b/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java index 396b0265..0210e059 100644 --- a/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java +++ b/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java @@ -159,8 +159,8 @@ void getData(Buffer buf){ this.config = getPort(_session, null, port); if(this.config == null){ - if(JSch.getLogger().isEnabled(Logger.ERROR)){ - JSch.getLogger().log(Logger.ERROR, + if(_session.getLogger().isEnabled(Logger.ERROR)){ + _session.getLogger().log(Logger.ERROR, "ChannelForwardedTCPIP: "+Util.byte2str(addr)+":"+port+" is not registered."); } } diff --git a/src/main/java/com/jcraft/jsch/Compression.java b/src/main/java/com/jcraft/jsch/Compression.java index 30598e9e..317a9228 100644 --- a/src/main/java/com/jcraft/jsch/Compression.java +++ b/src/main/java/com/jcraft/jsch/Compression.java @@ -32,7 +32,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public interface Compression{ static public final int INFLATER=0; static public final int DEFLATER=1; - void init(int type, int level) throws Exception; + void init(Session session, int type, int level) throws Exception; byte[] compress(byte[] buf, int start, int[] len); byte[] uncompress(byte[] buf, int start, int[] len); } diff --git a/src/main/java/com/jcraft/jsch/DHECN.java b/src/main/java/com/jcraft/jsch/DHECN.java index d7aa59d2..4bc00237 100644 --- a/src/main/java/com/jcraft/jsch/DHECN.java +++ b/src/main/java/com/jcraft/jsch/DHECN.java @@ -55,7 +55,6 @@ public abstract class DHECN extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -94,10 +93,10 @@ public void init(Session session, session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_ECDH_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_ECDH_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/DHGEX.java b/src/main/java/com/jcraft/jsch/DHGEX.java index 7f6ce943..96b02b18 100644 --- a/src/main/java/com/jcraft/jsch/DHGEX.java +++ b/src/main/java/com/jcraft/jsch/DHGEX.java @@ -61,7 +61,6 @@ public class DHGEX extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -101,10 +100,10 @@ public void init(Session session, buf.putInt(max); session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_DH_GEX_REQUEST("+min+"<"+preferred+"<"+max+") sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_DH_GEX_GROUP"); } @@ -144,10 +143,10 @@ public boolean next(Buffer _buf) throws Exception{ buf.putMPInt(e); session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_DH_GEX_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_DH_GEX_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/DHGN.java b/src/main/java/com/jcraft/jsch/DHGN.java index 4e7e7cc7..8953705d 100644 --- a/src/main/java/com/jcraft/jsch/DHGN.java +++ b/src/main/java/com/jcraft/jsch/DHGN.java @@ -55,7 +55,6 @@ public abstract class DHGN extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -101,10 +100,10 @@ public void init(Session session, session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEXDH_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEXDH_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/DHXEC.java b/src/main/java/com/jcraft/jsch/DHXEC.java index c64911a1..4f838f49 100644 --- a/src/main/java/com/jcraft/jsch/DHXEC.java +++ b/src/main/java/com/jcraft/jsch/DHXEC.java @@ -60,7 +60,6 @@ public abstract class DHXEC extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -99,10 +98,10 @@ public void init(Session session, session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_ECDH_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_ECDH_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/JSch.java b/src/main/java/com/jcraft/jsch/JSch.java index cd619f75..6ed5e73b 100644 --- a/src/main/java/com/jcraft/jsch/JSch.java +++ b/src/main/java/com/jcraft/jsch/JSch.java @@ -38,7 +38,7 @@ public class JSch{ /** * The version number. */ - public static final String VERSION = Version.getVersion(); + public static final String VERSION = "0.2.0"; //Version.getVersion(); static Hashtable config=new Hashtable<>(); static{ @@ -280,13 +280,14 @@ public void setConfigRepository(ConfigRepository configRepository) { private HostKeyRepository known_hosts=null; - private static final Logger DEVNULL=new Logger(){ + static final Logger DEVNULL=new Logger(){ @Override public boolean isEnabled(int level){return false;} @Override public void log(int level, String message){} }; static Logger logger=DEVNULL; + private Logger instLogger; public JSch(){ } @@ -682,7 +683,18 @@ public static void setLogger(Logger logger){ JSch.logger=logger; } - public static Logger getLogger(){ - return logger; + public Logger getInstanceLogger() { + if (this.instLogger == null) { + return logger; + } + return instLogger; + } + + public void setInstanceLogger(Logger logger) { + this.instLogger = logger; } + +// public static Logger getLogger(){ +// return logger; +// } } diff --git a/src/main/java/com/jcraft/jsch/KeyExchange.java b/src/main/java/com/jcraft/jsch/KeyExchange.java index efc8f2bf..a8f7686c 100644 --- a/src/main/java/com/jcraft/jsch/KeyExchange.java +++ b/src/main/java/com/jcraft/jsch/KeyExchange.java @@ -69,6 +69,11 @@ public abstract class KeyExchange{ public abstract void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception; + public void doInit(Session session, + byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception { + this.session = session; + init(session, V_S, V_C, I_S, I_C); + } public abstract boolean next(Buffer buf) throws Exception; public abstract int getState(); @@ -96,13 +101,13 @@ protected static String[] guess(Session session, byte[]I_S, byte[]I_C) throws Ex Buffer sb=new Buffer(I_S); sb.setOffSet(17); Buffer cb=new Buffer(I_C); cb.setOffSet(17); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(session.getLogger().isEnabled(Logger.INFO)){ for(int i=0; iclient"+ " cipher: "+guess[PROPOSAL_ENC_ALGS_STOC]+ " MAC: "+(_s2cAEAD?(""):(guess[PROPOSAL_MAC_ALGS_STOC]))+ " compression: "+guess[PROPOSAL_COMP_ALGS_STOC]); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "kex: client->server"+ " cipher: "+guess[PROPOSAL_ENC_ALGS_CTOS]+ " MAC: "+(_c2sAEAD?(""):(guess[PROPOSAL_MAC_ALGS_CTOS]))+ @@ -255,8 +260,8 @@ protected boolean verify(String alg, byte[] K_S, int index, sig.update(H); result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_rsa_verify: "+foo+" signature "+result); } } @@ -300,8 +305,8 @@ else if(alg.equals("ssh-dss")){ sig.update(H); result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_dss_verify: signature "+result); } } @@ -345,8 +350,8 @@ else if(alg.equals("ecdsa-sha2-nistp256") || result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_ecdsa_verify: "+alg+" signature "+result); } } @@ -378,8 +383,8 @@ else if(alg.equals("ssh-ed25519") || result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_eddsa_verify: "+alg+" signature "+result); } } diff --git a/src/main/java/com/jcraft/jsch/KeyPair.java b/src/main/java/com/jcraft/jsch/KeyPair.java index 889d4dd1..a3b1b8eb 100644 --- a/src/main/java/com/jcraft/jsch/KeyPair.java +++ b/src/main/java/com/jcraft/jsch/KeyPair.java @@ -175,6 +175,15 @@ public void writePrivateKey(OutputStream out, byte[] passphrase){ abstract byte[] getKeyTypeName(); public abstract int getKeyType(); + + public String getKeyTypeName(String encoding) { + try { + return new String(getKeyTypeName(), encoding); + } + catch(UnsupportedEncodingException uee) { + return null; + } + } /** * Returns the blob of the public key. diff --git a/src/main/java/com/jcraft/jsch/KeyPairDeferred.java b/src/main/java/com/jcraft/jsch/KeyPairDeferred.java index 2f8c7d1b..0c52be60 100644 --- a/src/main/java/com/jcraft/jsch/KeyPairDeferred.java +++ b/src/main/java/com/jcraft/jsch/KeyPairDeferred.java @@ -28,7 +28,7 @@ public boolean decrypt(byte[] _passphrase) { return true; } if (_passphrase == null) { - JSch.getLogger().log(Logger.ERROR, "no passphrase set."); + jsch.getInstanceLogger().log(Logger.ERROR, "no passphrase set."); return false; } diff --git a/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java b/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java index 9ad72401..4e51a88e 100644 --- a/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java +++ b/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java @@ -370,7 +370,7 @@ else if(Util.array_equals(id, aes256cbc)){ cipher=c.getDeclaredConstructor().newInstance(); } catch(Exception e){ - if(JSch.getLogger().isEnabled(Logger.FATAL)){ + if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ String message=""; if(name==null){ message="unknown oid: "+Util.toHex(id); @@ -378,7 +378,7 @@ else if(Util.array_equals(id, aes256cbc)){ else { message="function "+name+" is not supported"; } - JSch.getLogger().log(Logger.FATAL, "PKCS8: "+message); + jsch.getInstanceLogger().log(Logger.FATAL, "PKCS8: "+message); } } return cipher; diff --git a/src/main/java/com/jcraft/jsch/PortWatcher.java b/src/main/java/com/jcraft/jsch/PortWatcher.java index fc244341..fc3dd90b 100644 --- a/src/main/java/com/jcraft/jsch/PortWatcher.java +++ b/src/main/java/com/jcraft/jsch/PortWatcher.java @@ -201,6 +201,7 @@ public void run(){ OutputStream out=socket.getOutputStream(); if(socketPath!=null && socketPath.length()>0){ ChannelDirectStreamLocal channel = new ChannelDirectStreamLocal(); + channel.setSession(session); channel.init(); channel.setInputStream(in); channel.setOutputStream(out); @@ -211,7 +212,9 @@ public void run(){ channel.connect(connectTimeout); } else { ChannelDirectTCPIP channel = new ChannelDirectTCPIP(); + channel.setSession(session); channel.init(); + channel.setSession(session); channel.setInputStream(in); channel.setOutputStream(out); session.addChannel(channel); diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 0e295517..3dbd854c 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -73,7 +73,7 @@ public class Session implements Runnable{ private static final int PACKET_MAX_SIZE = 256 * 1024; private byte[] V_S; // server version - private byte[] V_C=Util.str2byte("SSH-2.0-JSCH_"+Version.getVersion()); // client version + private byte[] V_C=Util.str2byte("SSH-2.0-JSCH_"+JSch.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 @@ -202,8 +202,8 @@ public void connect(int connectTimeout) throws JSchException{ } Packet.setRandom(random); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Connecting to "+host+" port "+port); } @@ -243,8 +243,8 @@ public void connect(int connectTimeout) throws JSchException{ isConnected=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Connection established"); } @@ -302,10 +302,10 @@ public void connect(int connectTimeout) throws JSchException{ String _v_s=Util.byte2str(V_S); sshBugSigType74=_v_s.startsWith("SSH-2.0-OpenSSH_7.4"); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Remote version string: "+_v_s); - JSch.getLogger().log(Logger.INFO, + jsch.getInstanceLogger().log(Logger.INFO, "Local version string: "+Util.byte2str(V_C)); } @@ -317,8 +317,8 @@ public void connect(int connectTimeout) throws JSchException{ throw new JSchException("invalid protocol: "+buf.getCommand()); } - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "SSH_MSG_KEXINIT received"); } @@ -364,8 +364,8 @@ public void connect(int connectTimeout) throws JSchException{ //System.err.println("read: 21 ? "+buf.getCommand()); if(buf.getCommand()==SSH_MSG_NEWKEYS){ - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS received"); } @@ -441,16 +441,16 @@ public void connect(int connectTimeout) throws JSchException{ //System.err.println(" method: "+method); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ String str="Authentications that can continue: "; for(int k=methodi-1; k= max_auth_tries){ - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Login trials exceeds "+max_auth_tries); } } - if(auth_cancel) - throw new JSchException("Auth cancel"); - throw new JSchException("Auth fail"); + throw new JSchException((auth_cancel ? "Auth cancel" + : "Auth fail") + + " for methods '" + smethods + "'"); +// if(auth_cancel) +// throw new JSchException("Auth cancel"); +// throw new JSchException("Auth fail"); } if(socket!=null && (connectTimeout>0 || timeout>0)){ @@ -615,7 +618,7 @@ private KeyExchange receive_kexinit(Buffer buf) throws Exception { throw new JSchException(e.toString(), e); } - kex.init(this, V_S, V_C, I_S, I_C); + kex.doInit(this, V_S, V_C, I_S, I_C); return kex; } @@ -636,10 +639,10 @@ private void send_kexinit() throws Exception { String ciphers2c=getConfig("cipher.s2c"); String[] not_available_ciphers=checkCiphers(getConfig("CheckCiphers")); if(not_available_ciphers!=null && not_available_ciphers.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "cipher.c2s proposal before removing unavailable algos is: " + cipherc2s); - JSch.getLogger().log(Logger.DEBUG, + jsch.getInstanceLogger().log(Logger.DEBUG, "cipher.s2c proposal before removing unavailable algos is: " + ciphers2c); } @@ -649,10 +652,10 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available ciphers."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "cipher.c2s proposal after removing unavailable algos is: " + cipherc2s); - JSch.getLogger().log(Logger.DEBUG, + jsch.getInstanceLogger().log(Logger.DEBUG, "cipher.s2c proposal after removing unavailable algos is: " + ciphers2c); } } @@ -661,10 +664,10 @@ private void send_kexinit() throws Exception { String macs2c=getConfig("mac.s2c"); String[] not_available_macs=checkMacs(getConfig("CheckMacs")); if(not_available_macs!=null && not_available_macs.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "mac.c2s proposal before removing unavailable algos is: " + macc2s); - JSch.getLogger().log(Logger.DEBUG, + jsch.getInstanceLogger().log(Logger.DEBUG, "mac.s2c proposal before removing unavailable algos is: " + macs2c); } @@ -674,10 +677,10 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available macs."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "mac.c2s proposal after removing unavailable algos is: " + macc2s); - JSch.getLogger().log(Logger.DEBUG, + jsch.getInstanceLogger().log(Logger.DEBUG, "mac.s2c proposal after removing unavailable algos is: " + macs2c); } } @@ -685,8 +688,8 @@ private void send_kexinit() throws Exception { String kex=getConfig("kex"); String[] not_available_kexes=checkKexes(getConfig("CheckKexes")); if(not_available_kexes!=null && not_available_kexes.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "kex proposal before removing unavailable algos is: " + kex); } @@ -695,8 +698,8 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available kexes."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "kex proposal after removing unavailable algos is: " + kex); } } @@ -712,8 +715,8 @@ private void send_kexinit() throws Exception { // Cache for UserAuthPublicKey this.not_available_shks = not_available_shks; if(not_available_shks!=null && not_available_shks.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "server_host_key proposal before removing unavailable algos is: " + server_host_key); } @@ -722,16 +725,16 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available sig algorithm."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "server_host_key proposal after removing unavailable algos is: " + server_host_key); } } String prefer_hkr=getConfig("prefer_known_host_key_types"); if(prefer_hkr.equals("yes")){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "server_host_key proposal before known_host reordering is: " + server_host_key); } @@ -770,8 +773,8 @@ private void send_kexinit() throws Exception { } } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ + jsch.getInstanceLogger().log(Logger.DEBUG, "server_host_key proposal after known_host reordering is: " + server_host_key); } } @@ -817,8 +820,8 @@ private void send_kexinit() throws Exception { write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "SSH_MSG_KEXINIT sent"); } } @@ -829,8 +832,8 @@ private void send_newkeys() throws Exception { buf.putByte((byte)SSH_MSG_NEWKEYS); write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS sent"); } } @@ -953,8 +956,8 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep "This could mean that a stolen key is being used to "+ "impersonate this host."); } - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Host '"+host+"' has provided revoked key."); } throw new JSchException("revoked HostKey: "+host); @@ -963,14 +966,14 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep } if(i==HostKeyRepository.OK && - JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Host '"+host+"' is known and matches the "+key_type+" host key"); } if(insert && - JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, + jsch.getInstanceLogger().isEnabled(Logger.WARN)){ + jsch.getInstanceLogger().log(Logger.WARN, "Permanently added '"+host+"' ("+key_type+") to the list of known hosts."); } @@ -988,7 +991,7 @@ public Channel openChannel(String type) throws JSchException{ throw new JSchException("session is down"); } try{ - Channel channel=Channel.getChannel(type); + Channel channel=Channel.getChannel(type, this); addChannel(channel); channel.init(); if(channel instanceof ChannelSession){ @@ -1100,8 +1103,8 @@ public Buffer read(Buffer buf) throws Exception{ if((j%s2ccipher_size)!=0){ String message="Bad packet length "+j; - if(JSch.getLogger().isEnabled(Logger.FATAL)){ - JSch.getLogger().log(Logger.FATAL, message); + if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ + jsch.getInstanceLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1140,8 +1143,8 @@ else if(isAEAD || isEtM){ if((j%s2ccipher_size)!=0){ String message="Bad packet length "+j; - if(JSch.getLogger().isEnabled(Logger.FATAL)){ - JSch.getLogger().log(Logger.FATAL, message); + if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ + jsch.getInstanceLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1197,8 +1200,8 @@ else if(isAEAD || isEtM){ if((need%s2ccipher_size)!=0){ String message="Bad packet length "+need; - if(JSch.getLogger().isEnabled(Logger.FATAL)){ - JSch.getLogger().log(Logger.FATAL, message); + if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ + jsch.getInstanceLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1263,8 +1266,8 @@ else if(type==SSH_MSG_UNIMPLEMENTED){ buf.rewind(); buf.getInt();buf.getShort(); int reason_id=buf.getInt(); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Received SSH_MSG_UNIMPLEMENTED for "+reason_id); } } @@ -1297,25 +1300,25 @@ else if(type==SSH_MSG_EXT_INFO){ String enable_server_sig_algs=getConfig("enable_server_sig_algs"); if(!enable_server_sig_algs.equals("yes")){ ignore=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO while enable_server_sig_algs != yes"); + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO while enable_server_sig_algs != yes"); } } else if(isAuthed){ ignore=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received after SSH_MSG_USERAUTH_SUCCESS"); + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received after SSH_MSG_USERAUTH_SUCCESS"); } } else if(in_kex){ ignore=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received before SSH_MSG_NEWKEYS"); + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received before SSH_MSG_NEWKEYS"); } } else{ - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "SSH_MSG_EXT_INFO received"); + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "SSH_MSG_EXT_INFO received"); } } long num_extensions=buf.getUInt(); @@ -1324,8 +1327,8 @@ else if(in_kex){ byte[] ext_value=buf.getString(); if(!ignore && Util.byte2str(ext_name).equals("server-sig-algs")){ String foo=Util.byte2str(ext_value); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "server-sig-algs=<" + foo + ">"); + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "server-sig-algs=<" + foo + ">"); } if(sshBugSigType74){ if(!foo.isEmpty()){ @@ -1334,8 +1337,8 @@ else if(in_kex){ else{ foo="rsa-sha2-256,rsa-sha2-512"; } - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "OpenSSH 7.4 detected: adding rsa-sha2-256 & rsa-sha2-512 to server-sig-algs"); + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "OpenSSH 7.4 detected: adding rsa-sha2-256 & rsa-sha2-512 to server-sig-algs"); } } serverSigAlgs=Util.split(foo, ","); @@ -1386,8 +1389,8 @@ private void start_discard(Buffer buf, Cipher cipher, MAC mac, } catch(IOException e){ ioe = e; - if(JSch.getLogger().isEnabled(Logger.ERROR)){ - JSch.getLogger().log(Logger.ERROR, + if(jsch.getInstanceLogger().isEnabled(Logger.ERROR)){ + jsch.getInstanceLogger().log(Logger.ERROR, "start_discard finished early due to " + e.getMessage()); } } @@ -1946,7 +1949,7 @@ else if(in_kex && stimeout c=Class.forName(foo).asSubclass(Compression.class); inflater=c.getDeclaredConstructor().newInstance(); - inflater.init(Compression.INFLATER, 0); + inflater.init(this, Compression.INFLATER, 0); } catch(Exception ee){ throw new JSchException(ee.toString(), ee); @@ -2808,8 +2811,8 @@ private String[] checkCiphers(String ciphers){ if(ciphers==null || ciphers.length()==0) return null; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "CheckCiphers: "+ciphers); } @@ -2831,9 +2834,9 @@ private String[] checkCiphers(String ciphers){ String[] foo=new String[result.size()]; System.arraycopy(result.toArray(), 0, foo, 0, result.size()); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ for(int i=0; i c=Class.forName(kex).asSubclass(KeyExchange.class); KeyExchange _c=c.getDeclaredConstructor().newInstance(); - _c.init(s ,null, null, null, null); + _c.doInit(s ,null, null, null, null); return true; } catch(Exception | NoClassDefFoundError e){ return false; } @@ -2949,8 +2952,8 @@ private String[] checkSignatures(String sigs){ if(sigs==null || sigs.length()==0) return null; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + jsch.getInstanceLogger().log(Logger.INFO, "CheckSignatures: "+sigs); } @@ -2970,9 +2973,9 @@ private String[] checkSignatures(String sigs){ return null; String[] foo=new String[result.size()]; System.arraycopy(result.toArray(), 0, foo, 0, result.size()); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ for(int i=0; i0); } catch(java.util.zip.DataFormatException e){ - if(JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, + if(session.getLogger().isEnabled(Logger.WARN)){ + session.getLogger().log(Logger.WARN, "an exception during uncompress\n"+e.toString()); } } diff --git a/src/main/java/com/jcraft/jsch/jzlib/Compression.java b/src/main/java/com/jcraft/jsch/jzlib/Compression.java index a50794e4..b8545569 100644 --- a/src/main/java/com/jcraft/jsch/jzlib/Compression.java +++ b/src/main/java/com/jcraft/jsch/jzlib/Compression.java @@ -37,12 +37,14 @@ public class Compression implements com.jcraft.jsch.Compression { private Inflater inflater; private byte[] tmpbuf=new byte[BUF_SIZE]; private byte[] inflated_buf; + private Session session; public Compression(){ } @Override - public void init(int type, int level) throws Exception{ + public void init(Session session, int type, int level) throws Exception{ + this.session = session; if(type==DEFLATER){ deflater=new Deflater(level); } @@ -50,8 +52,8 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, "zlib using "+this.getClass().getCanonicalName()); } } @@ -83,8 +85,8 @@ public byte[] compress(byte[] buf, int start, int[] len){ outputlen+=tmp; break; default: - if(JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, + if(session.getLogger().isEnabled(Logger.WARN)){ + session.getLogger().log(Logger.WARN, "compress: deflate returnd "+status); } @@ -138,8 +140,8 @@ public byte[] uncompress(byte[] buffer, int start, int[] length){ length[0]=inflated_end; return buffer; default: - if(JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, + if(session.getLogger().isEnabled(Logger.WARN)){ + session.getLogger().log(Logger.WARN, "uncompress: inflate returnd "+status); } return null; diff --git a/src/test/java/com/jcraft/jsch/JSchTest.java b/src/test/java/com/jcraft/jsch/JSchTest.java index 8293b0f7..80c2f0b8 100644 --- a/src/test/java/com/jcraft/jsch/JSchTest.java +++ b/src/test/java/com/jcraft/jsch/JSchTest.java @@ -1,5 +1,6 @@ package com.jcraft.jsch; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Hashtable; @@ -8,6 +9,11 @@ class JSchTest { + @BeforeEach + void resetJsch() { + JSch.setLogger(null); + } + @Test void getPubkeyAcceptedKeyTypes() throws JSchException { JSch.setConfig("PubkeyAcceptedAlgorithms", "JSchTest111"); @@ -30,4 +36,43 @@ void setPubkeyAcceptedKeyTypesHashtable() throws JSchException { assertEquals("JSchTest333", JSch.getConfig("PubkeyAcceptedKeyTypes")); assertEquals("JSchTest333", JSch.getConfig("PubkeyAcceptedAlgorithms")); } + + @Test + void checkLoggerBehavior() throws Exception { + assertSame(JSch.DEVNULL, JSch.logger, "initial static value of logger should be DEVNULL"); + + JSch jsch = new JSch(); + assertSame(JSch.DEVNULL, jsch.getInstanceLogger(), "instance logger should be DEVNULL"); + + TestLogger staticLogger = new TestLogger(); + TestLogger instanceLogger = new TestLogger(); + + JSch.setLogger(staticLogger); + assertSame(staticLogger, JSch.logger, "mismatch with static logger"); + assertSame(staticLogger, jsch.getInstanceLogger(), "instance should return static logger"); + + jsch.setInstanceLogger(instanceLogger); + assertSame(staticLogger, JSch.logger, "mismatch with static logger"); + assertSame(instanceLogger, jsch.getInstanceLogger(), "instance should return static logger"); + + jsch.setInstanceLogger(null); + assertSame(staticLogger, JSch.logger, "mismatch with static logger"); + assertSame(staticLogger, jsch.getInstanceLogger(), "instance should return static logger"); + + JSch.setLogger(null); + assertSame(JSch.DEVNULL, JSch.logger, "static logger should be DEVNULL"); + assertSame(JSch.DEVNULL, jsch.getInstanceLogger(), "instance logger should be DEVNULL"); + } + + private final static class TestLogger implements Logger { + @Override + public boolean isEnabled(int level) { + return true; + } + + @Override + public void log(int level, String message) { + // empty + } + } } From fee4dd793042e8995857c0ac7c0b225efc148e0c Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 19:25:06 +0100 Subject: [PATCH 02/16] reenabled message --- src/main/java/com/jcraft/jsch/JSch.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/JSch.java b/src/main/java/com/jcraft/jsch/JSch.java index 6ed5e73b..7f0dc497 100644 --- a/src/main/java/com/jcraft/jsch/JSch.java +++ b/src/main/java/com/jcraft/jsch/JSch.java @@ -694,7 +694,7 @@ public void setInstanceLogger(Logger logger) { this.instLogger = logger; } -// public static Logger getLogger(){ -// return logger; -// } + public static Logger getLogger(){ + return logger; + } } From f8220b3caec50a178a55567aac046454441ef2a4 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 20:53:31 +0100 Subject: [PATCH 03/16] changes according to the feedback in the pull request --- .../java/com/jcraft/jsch/Compression.java | 5 +++- src/main/java/com/jcraft/jsch/JSch.java | 2 +- .../java/com/jcraft/jsch/KeyExchange.java | 2 +- .../java/com/jcraft/jsch/PortWatcher.java | 1 - src/main/java/com/jcraft/jsch/Session.java | 19 +++++++++++-- .../java/com/jcraft/jsch/juz/Compression.java | 13 ++------- .../com/jcraft/jsch/jzlib/Compression.java | 28 ++++++------------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/Compression.java b/src/main/java/com/jcraft/jsch/Compression.java index 317a9228..b482253d 100644 --- a/src/main/java/com/jcraft/jsch/Compression.java +++ b/src/main/java/com/jcraft/jsch/Compression.java @@ -32,7 +32,10 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public interface Compression{ static public final int INFLATER=0; static public final int DEFLATER=1; - void init(Session session, int type, int level) throws Exception; + default void setSession(Session session) { + // nothing + } + void init(int type, int level) throws Exception; byte[] compress(byte[] buf, int start, int[] len); byte[] uncompress(byte[] buf, int start, int[] len); } diff --git a/src/main/java/com/jcraft/jsch/JSch.java b/src/main/java/com/jcraft/jsch/JSch.java index 7f0dc497..70986369 100644 --- a/src/main/java/com/jcraft/jsch/JSch.java +++ b/src/main/java/com/jcraft/jsch/JSch.java @@ -38,7 +38,7 @@ public class JSch{ /** * The version number. */ - public static final String VERSION = "0.2.0"; //Version.getVersion(); + public static final String VERSION = Version.getVersion(); static Hashtable config=new Hashtable<>(); static{ diff --git a/src/main/java/com/jcraft/jsch/KeyExchange.java b/src/main/java/com/jcraft/jsch/KeyExchange.java index a8f7686c..6e1c0eac 100644 --- a/src/main/java/com/jcraft/jsch/KeyExchange.java +++ b/src/main/java/com/jcraft/jsch/KeyExchange.java @@ -69,7 +69,7 @@ public abstract class KeyExchange{ public abstract void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception; - public void doInit(Session session, + void doInit(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception { this.session = session; init(session, V_S, V_C, I_S, I_C); diff --git a/src/main/java/com/jcraft/jsch/PortWatcher.java b/src/main/java/com/jcraft/jsch/PortWatcher.java index fc3dd90b..81632df6 100644 --- a/src/main/java/com/jcraft/jsch/PortWatcher.java +++ b/src/main/java/com/jcraft/jsch/PortWatcher.java @@ -214,7 +214,6 @@ public void run(){ ChannelDirectTCPIP channel = new ChannelDirectTCPIP(); channel.setSession(session); channel.init(); - channel.setSession(session); channel.setInputStream(in); channel.setOutputStream(out); session.addChannel(channel); diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 3dbd854c..3879dd6e 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -35,6 +35,8 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.io.OutputStream; import java.net.Socket; import java.util.*; +import java.util.function.Supplier; + import javax.crypto.AEADBadTagException; public class Session implements Runnable{ @@ -2573,7 +2575,8 @@ private void initDeflater(String method) throws JSchException{ int level=6; try{ level=Integer.parseInt(getConfig("compression_level"));} catch(Exception ee){ } - deflater.init(this, Compression.DEFLATER, level); + deflater.setSession(this); + deflater.init(Compression.DEFLATER, level); } catch(Exception ee){ throw new JSchException(ee.toString(), ee); @@ -2594,7 +2597,8 @@ private void initInflater(String method) throws JSchException{ try{ Class c=Class.forName(foo).asSubclass(Compression.class); inflater=c.getDeclaredConstructor().newInstance(); - inflater.init(this, Compression.INFLATER, 0); + inflater.setSession(this); + inflater.init(Compression.INFLATER, 0); } catch(Exception ee){ throw new JSchException(ee.toString(), ee); @@ -3246,6 +3250,17 @@ private void checkConfig(ConfigRepository.Config config, String key){ this.setConfig(key, value); } + public static void logMessage(Session session, int level, Supplier message) { + Logger logger = JSch.getLogger(); + if (session != null) { + logger = session.getLogger(); + } + if (!logger.isEnabled(level)) { + return; + } + logger.log(level, message.get()); + } + public Logger getLogger() { return jsch.getInstanceLogger(); } diff --git a/src/main/java/com/jcraft/jsch/juz/Compression.java b/src/main/java/com/jcraft/jsch/juz/Compression.java index 07edb24f..017d12ae 100644 --- a/src/main/java/com/jcraft/jsch/juz/Compression.java +++ b/src/main/java/com/jcraft/jsch/juz/Compression.java @@ -35,8 +35,7 @@ public Compression(){ } @Override - public void init(Session session, int type, int level) throws Exception{ - this.session = session; + public void init(int type, int level) throws Exception{ if(type==DEFLATER){ deflater=new Deflater(level); } @@ -44,10 +43,7 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - if(session.getLogger().isEnabled(Logger.DEBUG)){ - session.getLogger().log(Logger.DEBUG, - "zlib using "+this.getClass().getCanonicalName()); - } + Session.logMessage(session, Logger.DEBUG, () -> "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -101,10 +97,7 @@ public byte[] uncompress(byte[] buf, int start, int[] len){ while(inflater.getRemaining()>0); } catch(java.util.zip.DataFormatException e){ - if(session.getLogger().isEnabled(Logger.WARN)){ - session.getLogger().log(Logger.WARN, - "an exception during uncompress\n"+e.toString()); - } + Session.logMessage(session, Logger.WARN, () -> "an exception during uncompress\n"+e.toString()); } if(buf.length "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -63,7 +61,6 @@ public byte[] compress(byte[] buf, int start, int[] len){ deflater.next_in=buf; deflater.next_in_index=start; deflater.avail_in=len[0]-start; - int status; int outputlen=start; byte[] outputbuf=buf; int tmp=0; @@ -72,7 +69,7 @@ public byte[] compress(byte[] buf, int start, int[] len){ deflater.next_out=tmpbuf; deflater.next_out_index=0; deflater.avail_out=BUF_SIZE; - status=deflater.deflate(JZlib.Z_PARTIAL_FLUSH); + int status=deflater.deflate(JZlib.Z_PARTIAL_FLUSH); switch(status){ case JZlib.Z_OK: tmp=BUF_SIZE-deflater.avail_out; @@ -85,11 +82,7 @@ public byte[] compress(byte[] buf, int start, int[] len){ outputlen+=tmp; break; default: - if(session.getLogger().isEnabled(Logger.WARN)){ - session.getLogger().log(Logger.WARN, - "compress: deflate returnd "+status); - } - + Session.logMessage(session, Logger.WARN, () -> "compress: deflate returnd "+status); } } while(deflater.avail_out==0); @@ -140,11 +133,8 @@ public byte[] uncompress(byte[] buffer, int start, int[] length){ length[0]=inflated_end; return buffer; default: - if(session.getLogger().isEnabled(Logger.WARN)){ - session.getLogger().log(Logger.WARN, - "uncompress: inflate returnd "+status); - } - return null; + Session.logMessage(session, Logger.WARN, () -> "compress: deflate returnd "+status); + return null; } } } From f71753ea2a8d4b5c36ac80619739e532deeb7a97 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 20:57:53 +0100 Subject: [PATCH 04/16] removed commented out code containing the original exception without "for methods" information --- src/main/java/com/jcraft/jsch/Session.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 3879dd6e..bbd5fbf8 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -524,10 +524,6 @@ public void connect(int connectTimeout) throws JSchException{ throw new JSchException((auth_cancel ? "Auth cancel" : "Auth fail") + " for methods '" + smethods + "'"); -// if(auth_cancel) -// throw new JSchException("Auth cancel"); -// throw new JSchException("Auth fail"); - } if(socket!=null && (connectTimeout>0 || timeout>0)){ socket.setSoTimeout(timeout); From 7c2f3e17c575c57b3009a979b56546bb406f9d04 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 21:00:51 +0100 Subject: [PATCH 05/16] removed method unrelated to this issue --- src/main/java/com/jcraft/jsch/KeyPair.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/KeyPair.java b/src/main/java/com/jcraft/jsch/KeyPair.java index a3b1b8eb..889d4dd1 100644 --- a/src/main/java/com/jcraft/jsch/KeyPair.java +++ b/src/main/java/com/jcraft/jsch/KeyPair.java @@ -175,15 +175,6 @@ public void writePrivateKey(OutputStream out, byte[] passphrase){ abstract byte[] getKeyTypeName(); public abstract int getKeyType(); - - public String getKeyTypeName(String encoding) { - try { - return new String(getKeyTypeName(), encoding); - } - catch(UnsupportedEncodingException uee) { - return null; - } - } /** * Returns the blob of the public key. From ffe145d98e7f535b55870b8f6bd0f79e56438a97 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 21:04:38 +0100 Subject: [PATCH 06/16] added missing bracket --- src/main/java/com/jcraft/jsch/Session.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index bbd5fbf8..0ee70fe7 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -524,6 +524,7 @@ public void connect(int connectTimeout) throws JSchException{ throw new JSchException((auth_cancel ? "Auth cancel" : "Auth fail") + " for methods '" + smethods + "'"); + } if(socket!=null && (connectTimeout>0 || timeout>0)){ socket.setSoTimeout(timeout); From c156b66c21d73334165c0bbc6885e3b95cddbebc Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 23:24:59 +0100 Subject: [PATCH 07/16] changed logging in compression classes to use own methods --- .../java/com/jcraft/jsch/Compression.java | 6 ++--- src/main/java/com/jcraft/jsch/Session.java | 17 ++----------- .../java/com/jcraft/jsch/juz/Compression.java | 15 ++++++++++-- .../com/jcraft/jsch/jzlib/Compression.java | 24 +++++++++++++------ 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/Compression.java b/src/main/java/com/jcraft/jsch/Compression.java index b482253d..3cefd238 100644 --- a/src/main/java/com/jcraft/jsch/Compression.java +++ b/src/main/java/com/jcraft/jsch/Compression.java @@ -32,10 +32,10 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING public interface Compression{ static public final int INFLATER=0; static public final int DEFLATER=1; - default void setSession(Session session) { - // nothing - } void init(int type, int level) throws Exception; + default void init(int type, int level, Session session) throws Exception { + init(type, level); + } byte[] compress(byte[] buf, int start, int[] len); byte[] uncompress(byte[] buf, int start, int[] len); } diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 0ee70fe7..6bbae7da 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -2572,8 +2572,7 @@ private void initDeflater(String method) throws JSchException{ int level=6; try{ level=Integer.parseInt(getConfig("compression_level"));} catch(Exception ee){ } - deflater.setSession(this); - deflater.init(Compression.DEFLATER, level); + deflater.init(Compression.DEFLATER, level, this); } catch(Exception ee){ throw new JSchException(ee.toString(), ee); @@ -2594,8 +2593,7 @@ private void initInflater(String method) throws JSchException{ try{ Class c=Class.forName(foo).asSubclass(Compression.class); inflater=c.getDeclaredConstructor().newInstance(); - inflater.setSession(this); - inflater.init(Compression.INFLATER, 0); + inflater.init(Compression.INFLATER, 0, this); } catch(Exception ee){ throw new JSchException(ee.toString(), ee); @@ -3246,17 +3244,6 @@ private void checkConfig(ConfigRepository.Config config, String key){ if(value != null) this.setConfig(key, value); } - - public static void logMessage(Session session, int level, Supplier message) { - Logger logger = JSch.getLogger(); - if (session != null) { - logger = session.getLogger(); - } - if (!logger.isEnabled(level)) { - return; - } - logger.log(level, message.get()); - } public Logger getLogger() { return jsch.getInstanceLogger(); diff --git a/src/main/java/com/jcraft/jsch/juz/Compression.java b/src/main/java/com/jcraft/jsch/juz/Compression.java index 017d12ae..dcdebb68 100644 --- a/src/main/java/com/jcraft/jsch/juz/Compression.java +++ b/src/main/java/com/jcraft/jsch/juz/Compression.java @@ -34,6 +34,17 @@ public class Compression implements com.jcraft.jsch.Compression { public Compression(){ } + private void logMessage(int level, String message) { + Logger logger = session == null ? JSch.getLogger() : session.getLogger(); + logger.log(level, message); + } + + @Override + public void init(int type, int level, Session session) throws Exception{ + this.session = session; + init(type, level); + } + @Override public void init(int type, int level) throws Exception{ if(type==DEFLATER){ @@ -43,7 +54,7 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - Session.logMessage(session, Logger.DEBUG, () -> "zlib using "+this.getClass().getCanonicalName()); + logMessage(Logger.DEBUG, "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -97,7 +108,7 @@ public byte[] uncompress(byte[] buf, int start, int[] len){ while(inflater.getRemaining()>0); } catch(java.util.zip.DataFormatException e){ - Session.logMessage(session, Logger.WARN, () -> "an exception during uncompress\n"+e.toString()); + logMessage(Logger.WARN, "an exception during uncompress\n"+e.toString()); } if(buf.length "zlib using "+this.getClass().getCanonicalName()); + logMessage(Logger.DEBUG, "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -82,7 +92,7 @@ public byte[] compress(byte[] buf, int start, int[] len){ outputlen+=tmp; break; default: - Session.logMessage(session, Logger.WARN, () -> "compress: deflate returnd "+status); + logMessage(Logger.WARN, "compress: deflate returnd "+status); } } while(deflater.avail_out==0); @@ -133,7 +143,7 @@ public byte[] uncompress(byte[] buffer, int start, int[] length){ length[0]=inflated_end; return buffer; default: - Session.logMessage(session, Logger.WARN, () -> "compress: deflate returnd "+status); + logMessage(Logger.WARN, "compress: deflate returnd "+status); return null; } } From 8de3843d9c7f148f49418c41a9797f03607986ac Mon Sep 17 00:00:00 2001 From: kimmerin Date: Fri, 18 Feb 2022 08:00:27 +0100 Subject: [PATCH 08/16] removed whitespaces --- src/main/java/com/jcraft/jsch/UserInfo.java | 1 - src/main/java/com/jcraft/jsch/jzlib/Compression.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/UserInfo.java b/src/main/java/com/jcraft/jsch/UserInfo.java index 5304487a..73fe5612 100644 --- a/src/main/java/com/jcraft/jsch/UserInfo.java +++ b/src/main/java/com/jcraft/jsch/UserInfo.java @@ -36,5 +36,4 @@ public interface UserInfo{ boolean promptPassphrase(String message); boolean promptYesNo(String message); void showMessage(String message); - } diff --git a/src/main/java/com/jcraft/jsch/jzlib/Compression.java b/src/main/java/com/jcraft/jsch/jzlib/Compression.java index 285e8965..80299cec 100644 --- a/src/main/java/com/jcraft/jsch/jzlib/Compression.java +++ b/src/main/java/com/jcraft/jsch/jzlib/Compression.java @@ -41,7 +41,7 @@ public class Compression implements com.jcraft.jsch.Compression { private byte[] inflated_buf; private Session session; - public Compression() { + public Compression(){ } private void logMessage(int level, String message) { From 6431bcfd62b5b176cde549418cd23f723d8f189f Mon Sep 17 00:00:00 2001 From: kimmerin Date: Fri, 18 Feb 2022 08:11:40 +0100 Subject: [PATCH 09/16] get logger from jsch on instantiation and allow to set a different one by setLogger --- src/main/java/com/jcraft/jsch/Session.java | 202 +++++++++++---------- 1 file changed, 104 insertions(+), 98 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 6bbae7da..155e8e83 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -162,10 +162,12 @@ public class Session implements Runnable{ byte[] password=null; JSch jsch; + Logger logger; Session(JSch jsch, String username, String host, int port) throws JSchException{ super(); this.jsch=jsch; + logger = getLogger(); buf=new Buffer(); packet=new Packet(buf); this.username = username; @@ -204,8 +206,8 @@ public void connect(int connectTimeout) throws JSchException{ } Packet.setRandom(random); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Connecting to "+host+" port "+port); } @@ -245,8 +247,8 @@ public void connect(int connectTimeout) throws JSchException{ isConnected=true; - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Connection established"); } @@ -304,10 +306,10 @@ public void connect(int connectTimeout) throws JSchException{ String _v_s=Util.byte2str(V_S); sshBugSigType74=_v_s.startsWith("SSH-2.0-OpenSSH_7.4"); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Remote version string: "+_v_s); - jsch.getInstanceLogger().log(Logger.INFO, + getLogger().log(Logger.INFO, "Local version string: "+Util.byte2str(V_C)); } @@ -319,8 +321,8 @@ public void connect(int connectTimeout) throws JSchException{ throw new JSchException("invalid protocol: "+buf.getCommand()); } - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_KEXINIT received"); } @@ -366,8 +368,8 @@ public void connect(int connectTimeout) throws JSchException{ //System.err.println("read: 21 ? "+buf.getCommand()); if(buf.getCommand()==SSH_MSG_NEWKEYS){ - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS received"); } @@ -443,16 +445,16 @@ public void connect(int connectTimeout) throws JSchException{ //System.err.println(" method: "+method); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ + if(getLogger().isEnabled(Logger.INFO)){ String str="Authentications that can continue: "; for(int k=methodi-1; k= max_auth_tries){ - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Login trials exceeds "+max_auth_tries); } } @@ -638,10 +640,10 @@ private void send_kexinit() throws Exception { String ciphers2c=getConfig("cipher.s2c"); String[] not_available_ciphers=checkCiphers(getConfig("CheckCiphers")); if(not_available_ciphers!=null && not_available_ciphers.length>0){ - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "cipher.c2s proposal before removing unavailable algos is: " + cipherc2s); - jsch.getInstanceLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "cipher.s2c proposal before removing unavailable algos is: " + ciphers2c); } @@ -651,10 +653,10 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available ciphers."); } - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "cipher.c2s proposal after removing unavailable algos is: " + cipherc2s); - jsch.getInstanceLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "cipher.s2c proposal after removing unavailable algos is: " + ciphers2c); } } @@ -663,10 +665,10 @@ private void send_kexinit() throws Exception { String macs2c=getConfig("mac.s2c"); String[] not_available_macs=checkMacs(getConfig("CheckMacs")); if(not_available_macs!=null && not_available_macs.length>0){ - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "mac.c2s proposal before removing unavailable algos is: " + macc2s); - jsch.getInstanceLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "mac.s2c proposal before removing unavailable algos is: " + macs2c); } @@ -676,10 +678,10 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available macs."); } - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "mac.c2s proposal after removing unavailable algos is: " + macc2s); - jsch.getInstanceLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "mac.s2c proposal after removing unavailable algos is: " + macs2c); } } @@ -687,8 +689,8 @@ private void send_kexinit() throws Exception { String kex=getConfig("kex"); String[] not_available_kexes=checkKexes(getConfig("CheckKexes")); if(not_available_kexes!=null && not_available_kexes.length>0){ - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "kex proposal before removing unavailable algos is: " + kex); } @@ -697,8 +699,8 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available kexes."); } - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "kex proposal after removing unavailable algos is: " + kex); } } @@ -714,8 +716,8 @@ private void send_kexinit() throws Exception { // Cache for UserAuthPublicKey this.not_available_shks = not_available_shks; if(not_available_shks!=null && not_available_shks.length>0){ - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal before removing unavailable algos is: " + server_host_key); } @@ -724,16 +726,16 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available sig algorithm."); } - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal after removing unavailable algos is: " + server_host_key); } } String prefer_hkr=getConfig("prefer_known_host_key_types"); if(prefer_hkr.equals("yes")){ - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal before known_host reordering is: " + server_host_key); } @@ -772,8 +774,8 @@ private void send_kexinit() throws Exception { } } - if(jsch.getInstanceLogger().isEnabled(Logger.DEBUG)){ - jsch.getInstanceLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal after known_host reordering is: " + server_host_key); } } @@ -819,8 +821,8 @@ private void send_kexinit() throws Exception { write(packet); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_KEXINIT sent"); } } @@ -831,8 +833,8 @@ private void send_newkeys() throws Exception { buf.putByte((byte)SSH_MSG_NEWKEYS); write(packet); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS sent"); } } @@ -955,8 +957,8 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep "This could mean that a stolen key is being used to "+ "impersonate this host."); } - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Host '"+host+"' has provided revoked key."); } throw new JSchException("revoked HostKey: "+host); @@ -965,14 +967,14 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep } if(i==HostKeyRepository.OK && - jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Host '"+host+"' is known and matches the "+key_type+" host key"); } if(insert && - jsch.getInstanceLogger().isEnabled(Logger.WARN)){ - jsch.getInstanceLogger().log(Logger.WARN, + getLogger().isEnabled(Logger.WARN)){ + getLogger().log(Logger.WARN, "Permanently added '"+host+"' ("+key_type+") to the list of known hosts."); } @@ -1102,8 +1104,8 @@ public Buffer read(Buffer buf) throws Exception{ if((j%s2ccipher_size)!=0){ String message="Bad packet length "+j; - if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ - jsch.getInstanceLogger().log(Logger.FATAL, message); + if(getLogger().isEnabled(Logger.FATAL)){ + getLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1142,8 +1144,8 @@ else if(isAEAD || isEtM){ if((j%s2ccipher_size)!=0){ String message="Bad packet length "+j; - if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ - jsch.getInstanceLogger().log(Logger.FATAL, message); + if(getLogger().isEnabled(Logger.FATAL)){ + getLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1199,8 +1201,8 @@ else if(isAEAD || isEtM){ if((need%s2ccipher_size)!=0){ String message="Bad packet length "+need; - if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ - jsch.getInstanceLogger().log(Logger.FATAL, message); + if(getLogger().isEnabled(Logger.FATAL)){ + getLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1265,8 +1267,8 @@ else if(type==SSH_MSG_UNIMPLEMENTED){ buf.rewind(); buf.getInt();buf.getShort(); int reason_id=buf.getInt(); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Received SSH_MSG_UNIMPLEMENTED for "+reason_id); } } @@ -1299,25 +1301,25 @@ else if(type==SSH_MSG_EXT_INFO){ String enable_server_sig_algs=getConfig("enable_server_sig_algs"); if(!enable_server_sig_algs.equals("yes")){ ignore=true; - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO while enable_server_sig_algs != yes"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO while enable_server_sig_algs != yes"); } } else if(isAuthed){ ignore=true; - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received after SSH_MSG_USERAUTH_SUCCESS"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received after SSH_MSG_USERAUTH_SUCCESS"); } } else if(in_kex){ ignore=true; - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received before SSH_MSG_NEWKEYS"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received before SSH_MSG_NEWKEYS"); } } else{ - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, "SSH_MSG_EXT_INFO received"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_EXT_INFO received"); } } long num_extensions=buf.getUInt(); @@ -1326,8 +1328,8 @@ else if(in_kex){ byte[] ext_value=buf.getString(); if(!ignore && Util.byte2str(ext_name).equals("server-sig-algs")){ String foo=Util.byte2str(ext_value); - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, "server-sig-algs=<" + foo + ">"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "server-sig-algs=<" + foo + ">"); } if(sshBugSigType74){ if(!foo.isEmpty()){ @@ -1336,8 +1338,8 @@ else if(in_kex){ else{ foo="rsa-sha2-256,rsa-sha2-512"; } - if(jsch.getInstanceLogger().isEnabled(Logger.INFO)){ - jsch.getInstanceLogger().log(Logger.INFO, "OpenSSH 7.4 detected: adding rsa-sha2-256 & rsa-sha2-512 to server-sig-algs"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "OpenSSH 7.4 detected: adding rsa-sha2-256 & rsa-sha2-512 to server-sig-algs"); } } serverSigAlgs=Util.split(foo, ","); @@ -1388,8 +1390,8 @@ private void start_discard(Buffer buf, Cipher cipher, MAC mac, } catch(IOException e){ ioe = e; - if(jsch.getInstanceLogger().isEnabled(Logger.ERROR)){ - jsch.getInstanceLogger().log(Logger.ERROR, + if(getLogger().isEnabled(Logger.ERROR)){ + getLogger().log(Logger.ERROR, "start_discard finished early due to " + e.getMessage()); } } @@ -2013,8 +2015,8 @@ else if(in_kex && stimeout Date: Fri, 18 Feb 2022 11:43:59 +0100 Subject: [PATCH 10/16] changed logger setting to fall back to JSch-logger retrieval if no specific logger has been set by setLogger. --- src/main/java/com/jcraft/jsch/Session.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 155e8e83..219d7dd2 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -167,7 +167,6 @@ public class Session implements Runnable{ Session(JSch jsch, String username, String host, int port) throws JSchException{ super(); this.jsch=jsch; - logger = getLogger(); buf=new Buffer(); packet=new Packet(buf); this.username = username; @@ -3248,6 +3247,9 @@ private void checkConfig(ConfigRepository.Config config, String key){ } public Logger getLogger() { + if (logger != null) { + return logger; + } return jsch.getInstanceLogger(); } From 1cc013c8cd237104237f3b8e61a9e4676d33ed07 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Fri, 18 Feb 2022 11:54:21 +0100 Subject: [PATCH 11/16] added test for logger handling --- src/test/java/com/jcraft/jsch/JSchTest.java | 2 +- .../java/com/jcraft/jsch/SessionTest.java | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/jcraft/jsch/JSchTest.java b/src/test/java/com/jcraft/jsch/JSchTest.java index 80c2f0b8..a2d7ea96 100644 --- a/src/test/java/com/jcraft/jsch/JSchTest.java +++ b/src/test/java/com/jcraft/jsch/JSchTest.java @@ -64,7 +64,7 @@ void checkLoggerBehavior() throws Exception { assertSame(JSch.DEVNULL, jsch.getInstanceLogger(), "instance logger should be DEVNULL"); } - private final static class TestLogger implements Logger { + final static class TestLogger implements Logger { @Override public boolean isEnabled(int level) { return true; diff --git a/src/test/java/com/jcraft/jsch/SessionTest.java b/src/test/java/com/jcraft/jsch/SessionTest.java index 541018e9..aa727fca 100644 --- a/src/test/java/com/jcraft/jsch/SessionTest.java +++ b/src/test/java/com/jcraft/jsch/SessionTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import com.jcraft.jsch.JSchTest.TestLogger; + import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -54,4 +56,24 @@ void setPubkeyAcceptedKeyTypes() throws JSchException { assertEquals("SessionTest222", session.getConfig("PubkeyAcceptedKeyTypes")); assertEquals("SessionTest222", session.getConfig("PubkeyAcceptedAlgorithms")); } + + @Test + void checkLoggerFunctionality() throws Exception { + TestLogger staticLogger = new TestLogger(); + TestLogger jschInstanceLogger = new TestLogger(); + TestLogger sessionLogger = new TestLogger(); + + Session session = new Session(jsch, null, null, 0); + + assertSame(JSch.DEVNULL, session.getLogger(), "DEVNULL logger expected after creation"); + + JSch.setLogger(staticLogger); + assertSame(staticLogger, session.getLogger(), "static logger expected after setting static logger"); + + jsch.setInstanceLogger(jschInstanceLogger); + assertSame(jschInstanceLogger, session.getLogger(), "static logger expected after setting instance logger"); + + session.setLogger(sessionLogger); + assertSame(sessionLogger, session.getLogger(), "static logger expected after setting session logger"); + } } From af03841556b21ef32a916d6799cdd4edd3913798 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Fri, 18 Feb 2022 17:36:16 +0100 Subject: [PATCH 12/16] added javadoc --- src/main/java/com/jcraft/jsch/JSch.java | 20 ++++++++++++++++++-- src/main/java/com/jcraft/jsch/Session.java | 21 +++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/JSch.java b/src/main/java/com/jcraft/jsch/JSch.java index 70986369..de926479 100644 --- a/src/main/java/com/jcraft/jsch/JSch.java +++ b/src/main/java/com/jcraft/jsch/JSch.java @@ -674,7 +674,8 @@ public static void setConfig(String key, String value){ /** * Sets the logger * - * @param logger logger + * @param logger logger or null if no logging + * should take place * * @see com.jcraft.jsch.Logger */ @@ -682,7 +683,12 @@ public static void setLogger(Logger logger){ if(logger==null) logger=DEVNULL; JSch.logger=logger; } - + + /** + * Returns a logger to be used for this particular instance of JSch + * @return The logger that is used by this instance. If no particular + * logger has been set, the statically set logger is returned. + */ public Logger getInstanceLogger() { if (this.instLogger == null) { return logger; @@ -690,10 +696,20 @@ public Logger getInstanceLogger() { return instLogger; } + /** + * Sets a logger to be used for this particular instance of JSch + * @param logger The logger to be used or null if + * the statically set logger should be used + */ public void setInstanceLogger(Logger logger) { this.instLogger = logger; } + /** + * Returns the statically set logger, i.e. the logger being + * used by all JSch instances without explicitly set logger. + * @return The logger + */ public static Logger getLogger(){ return logger; } diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 219d7dd2..3ee69c4d 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -34,8 +34,14 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Socket; -import java.util.*; -import java.util.function.Supplier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Vector; import javax.crypto.AEADBadTagException; @@ -3246,6 +3252,12 @@ private void checkConfig(ConfigRepository.Config config, String key){ this.setConfig(key, value); } + /** + * Returns the logger being used by this instance of Session. If no + * particular logger has been set, the instance logger of the + * jsch instance is returned this session belongs to. + * @return The logger + */ public Logger getLogger() { if (logger != null) { return logger; @@ -3253,6 +3265,11 @@ public Logger getLogger() { return jsch.getInstanceLogger(); } + /** + * Sets the logger being used by this instance of Session + * @param logger The logger or null if the instance logger + * of this instance's jsch instance should be used + */ public void setLogger(Logger logger) { this.logger = logger; } From b127caf881c67d90a3317a8924125d1e75eb06de Mon Sep 17 00:00:00 2001 From: kimmerin Date: Tue, 22 Feb 2022 15:51:31 +0100 Subject: [PATCH 13/16] check if logging is necessary before calling --- src/main/java/com/jcraft/jsch/juz/Compression.java | 12 ++++++++---- .../java/com/jcraft/jsch/jzlib/Compression.java | 14 +++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/juz/Compression.java b/src/main/java/com/jcraft/jsch/juz/Compression.java index dcdebb68..7ffd6304 100644 --- a/src/main/java/com/jcraft/jsch/juz/Compression.java +++ b/src/main/java/com/jcraft/jsch/juz/Compression.java @@ -2,6 +2,7 @@ package com.jcraft.jsch.juz; import com.jcraft.jsch.*; +import java.util.function.Supplier; import java.util.zip.Deflater; import java.util.zip.Inflater; @@ -34,9 +35,12 @@ public class Compression implements com.jcraft.jsch.Compression { public Compression(){ } - private void logMessage(int level, String message) { + private void logMessage(int level, Supplier message) { Logger logger = session == null ? JSch.getLogger() : session.getLogger(); - logger.log(level, message); + if (!logger.isEnabled(level)) { + return; + } + logger.log(level, message.get()); } @Override @@ -54,7 +58,7 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - logMessage(Logger.DEBUG, "zlib using "+this.getClass().getCanonicalName()); + logMessage(Logger.DEBUG, () -> "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -108,7 +112,7 @@ public byte[] uncompress(byte[] buf, int start, int[] len){ while(inflater.getRemaining()>0); } catch(java.util.zip.DataFormatException e){ - logMessage(Logger.WARN, "an exception during uncompress\n"+e.toString()); + logMessage(Logger.WARN, () -> "an exception during uncompress\n"+e.toString()); } if(buf.length message) { Logger logger = session == null ? JSch.getLogger() : session.getLogger(); - logger.log(level, message); + if (!logger.isEnabled(level)) { + return; + } + logger.log(level, message.get()); } @Override @@ -63,7 +67,7 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - logMessage(Logger.DEBUG, "zlib using "+this.getClass().getCanonicalName()); + logMessage(Logger.DEBUG, () -> "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -92,7 +96,7 @@ public byte[] compress(byte[] buf, int start, int[] len){ outputlen+=tmp; break; default: - logMessage(Logger.WARN, "compress: deflate returnd "+status); + logMessage(Logger.WARN, () -> "compress: deflate returnd "+status); } } while(deflater.avail_out==0); @@ -143,7 +147,7 @@ public byte[] uncompress(byte[] buffer, int start, int[] length){ length[0]=inflated_end; return buffer; default: - logMessage(Logger.WARN, "compress: deflate returnd "+status); + logMessage(Logger.WARN, () -> "compress: deflate returnd "+status); return null; } } From 55e3ef390e5e4ca87c366899a728531dc5ffe1a9 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Thu, 17 Feb 2022 19:16:35 +0100 Subject: [PATCH 14/16] Implementation of Issue 127: Allow the setting of a logger on the instance level. allow the setting of a logger to the JSch instance to allow instance-specific logging. The static methods are kept untouched to keep backward compatibility reenabled message changes according to the feedback in the pull request removed commented out code containing the original exception without "for methods" information removed method unrelated to this issue added missing bracket changed logging in compression classes to use own methods removed whitespaces get logger from jsch on instantiation and allow to set a different one by setLogger changed logger setting to fall back to JSch-logger retrieval if no specific logger has been set by setLogger. added test for logger handling added javadoc check if logging is necessary before calling --- src/main/java/com/jcraft/jsch/Channel.java | 31 ++- .../jcraft/jsch/ChannelDirectStreamLocal.java | 2 +- .../jcraft/jsch/ChannelForwardedTCPIP.java | 4 +- .../java/com/jcraft/jsch/Compression.java | 3 + src/main/java/com/jcraft/jsch/DHECN.java | 7 +- src/main/java/com/jcraft/jsch/DHGEX.java | 13 +- src/main/java/com/jcraft/jsch/DHGN.java | 7 +- src/main/java/com/jcraft/jsch/DHXEC.java | 7 +- src/main/java/com/jcraft/jsch/JSch.java | 34 ++- .../java/com/jcraft/jsch/KeyExchange.java | 37 +-- .../java/com/jcraft/jsch/KeyPairDeferred.java | 2 +- .../java/com/jcraft/jsch/KeyPairPKCS8.java | 4 +- .../java/com/jcraft/jsch/PortWatcher.java | 2 + src/main/java/com/jcraft/jsch/Session.java | 249 ++++++++++-------- .../java/com/jcraft/jsch/UserAuthNone.java | 8 +- .../com/jcraft/jsch/UserAuthPublicKey.java | 60 ++--- .../java/com/jcraft/jsch/juz/Compression.java | 26 +- .../com/jcraft/jsch/jzlib/Compression.java | 42 +-- src/test/java/com/jcraft/jsch/JSchTest.java | 45 ++++ .../java/com/jcraft/jsch/SessionTest.java | 22 ++ 20 files changed, 379 insertions(+), 226 deletions(-) diff --git a/src/main/java/com/jcraft/jsch/Channel.java b/src/main/java/com/jcraft/jsch/Channel.java index 479bf74a..0e6da7c2 100644 --- a/src/main/java/com/jcraft/jsch/Channel.java +++ b/src/main/java/com/jcraft/jsch/Channel.java @@ -45,38 +45,43 @@ public abstract class Channel implements Runnable{ static int index=0; private static Vector pool=new Vector<>(); - static Channel getChannel(String type){ + static Channel getChannel(String type, Session session){ + Channel ret = null; if(type.equals("session")){ - return new ChannelSession(); + ret = new ChannelSession(); } if(type.equals("shell")){ - return new ChannelShell(); + ret = new ChannelShell(); } if(type.equals("exec")){ - return new ChannelExec(); + ret = new ChannelExec(); } if(type.equals("x11")){ - return new ChannelX11(); + ret = new ChannelX11(); } if(type.equals("auth-agent@openssh.com")){ - return new ChannelAgentForwarding(); + ret = new ChannelAgentForwarding(); } if(type.equals("direct-tcpip")){ - return new ChannelDirectTCPIP(); + ret = new ChannelDirectTCPIP(); } if(type.equals("forwarded-tcpip")){ - return new ChannelForwardedTCPIP(); + ret = new ChannelForwardedTCPIP(); } if(type.equals("sftp")){ - return new ChannelSftp(); + ret = new ChannelSftp(); } if(type.equals("subsystem")){ - return new ChannelSubsystem(); + ret = new ChannelSubsystem(); } if(type.equals("direct-streamlocal@openssh.com")){ - return new ChannelDirectStreamLocal(); + ret = new ChannelDirectStreamLocal(); } - return null; + if (ret == null) { + return null; + } + ret.setSession(session); + return ret; } static Channel getChannel(int id, Session session){ synchronized(pool){ @@ -118,7 +123,7 @@ static void del(Channel c){ volatile int reply=0; volatile int connectTimeout=0; - private Session session; + protected Session session; int notifyme=0; diff --git a/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java b/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java index 351ab7d9..7ace8095 100644 --- a/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java +++ b/src/main/java/com/jcraft/jsch/ChannelDirectStreamLocal.java @@ -27,7 +27,7 @@ public class ChannelDirectStreamLocal extends ChannelDirectTCPIP { protected Packet genChannelOpenPacket() { if (socketPath == null) { - JSch.getLogger().log(Logger.FATAL, "socketPath must be set"); + session.getLogger().log(Logger.FATAL, "socketPath must be set"); throw new RuntimeException("socketPath must be set"); } diff --git a/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java b/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java index 396b0265..0210e059 100644 --- a/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java +++ b/src/main/java/com/jcraft/jsch/ChannelForwardedTCPIP.java @@ -159,8 +159,8 @@ void getData(Buffer buf){ this.config = getPort(_session, null, port); if(this.config == null){ - if(JSch.getLogger().isEnabled(Logger.ERROR)){ - JSch.getLogger().log(Logger.ERROR, + if(_session.getLogger().isEnabled(Logger.ERROR)){ + _session.getLogger().log(Logger.ERROR, "ChannelForwardedTCPIP: "+Util.byte2str(addr)+":"+port+" is not registered."); } } diff --git a/src/main/java/com/jcraft/jsch/Compression.java b/src/main/java/com/jcraft/jsch/Compression.java index 30598e9e..3cefd238 100644 --- a/src/main/java/com/jcraft/jsch/Compression.java +++ b/src/main/java/com/jcraft/jsch/Compression.java @@ -33,6 +33,9 @@ public interface Compression{ static public final int INFLATER=0; static public final int DEFLATER=1; void init(int type, int level) throws Exception; + default void init(int type, int level, Session session) throws Exception { + init(type, level); + } byte[] compress(byte[] buf, int start, int[] len); byte[] uncompress(byte[] buf, int start, int[] len); } diff --git a/src/main/java/com/jcraft/jsch/DHECN.java b/src/main/java/com/jcraft/jsch/DHECN.java index d7aa59d2..4bc00237 100644 --- a/src/main/java/com/jcraft/jsch/DHECN.java +++ b/src/main/java/com/jcraft/jsch/DHECN.java @@ -55,7 +55,6 @@ public abstract class DHECN extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -94,10 +93,10 @@ public void init(Session session, session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_ECDH_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_ECDH_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/DHGEX.java b/src/main/java/com/jcraft/jsch/DHGEX.java index 7f6ce943..96b02b18 100644 --- a/src/main/java/com/jcraft/jsch/DHGEX.java +++ b/src/main/java/com/jcraft/jsch/DHGEX.java @@ -61,7 +61,6 @@ public class DHGEX extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -101,10 +100,10 @@ public void init(Session session, buf.putInt(max); session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_DH_GEX_REQUEST("+min+"<"+preferred+"<"+max+") sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_DH_GEX_GROUP"); } @@ -144,10 +143,10 @@ public boolean next(Buffer _buf) throws Exception{ buf.putMPInt(e); session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_DH_GEX_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_DH_GEX_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/DHGN.java b/src/main/java/com/jcraft/jsch/DHGN.java index 4e7e7cc7..8953705d 100644 --- a/src/main/java/com/jcraft/jsch/DHGN.java +++ b/src/main/java/com/jcraft/jsch/DHGN.java @@ -55,7 +55,6 @@ public abstract class DHGN extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -101,10 +100,10 @@ public void init(Session session, session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEXDH_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEXDH_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/DHXEC.java b/src/main/java/com/jcraft/jsch/DHXEC.java index c64911a1..4f838f49 100644 --- a/src/main/java/com/jcraft/jsch/DHXEC.java +++ b/src/main/java/com/jcraft/jsch/DHXEC.java @@ -60,7 +60,6 @@ public abstract class DHXEC extends KeyExchange{ @Override public void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{ - this.session=session; this.V_S=V_S; this.V_C=V_C; this.I_S=I_S; @@ -99,10 +98,10 @@ public void init(Session session, session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_KEX_ECDH_INIT sent"); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "expecting SSH_MSG_KEX_ECDH_REPLY"); } diff --git a/src/main/java/com/jcraft/jsch/JSch.java b/src/main/java/com/jcraft/jsch/JSch.java index cd619f75..de926479 100644 --- a/src/main/java/com/jcraft/jsch/JSch.java +++ b/src/main/java/com/jcraft/jsch/JSch.java @@ -280,13 +280,14 @@ public void setConfigRepository(ConfigRepository configRepository) { private HostKeyRepository known_hosts=null; - private static final Logger DEVNULL=new Logger(){ + static final Logger DEVNULL=new Logger(){ @Override public boolean isEnabled(int level){return false;} @Override public void log(int level, String message){} }; static Logger logger=DEVNULL; + private Logger instLogger; public JSch(){ } @@ -673,7 +674,8 @@ public static void setConfig(String key, String value){ /** * Sets the logger * - * @param logger logger + * @param logger logger or null if no logging + * should take place * * @see com.jcraft.jsch.Logger */ @@ -681,7 +683,33 @@ public static void setLogger(Logger logger){ if(logger==null) logger=DEVNULL; JSch.logger=logger; } - + + /** + * Returns a logger to be used for this particular instance of JSch + * @return The logger that is used by this instance. If no particular + * logger has been set, the statically set logger is returned. + */ + public Logger getInstanceLogger() { + if (this.instLogger == null) { + return logger; + } + return instLogger; + } + + /** + * Sets a logger to be used for this particular instance of JSch + * @param logger The logger to be used or null if + * the statically set logger should be used + */ + public void setInstanceLogger(Logger logger) { + this.instLogger = logger; + } + + /** + * Returns the statically set logger, i.e. the logger being + * used by all JSch instances without explicitly set logger. + * @return The logger + */ public static Logger getLogger(){ return logger; } diff --git a/src/main/java/com/jcraft/jsch/KeyExchange.java b/src/main/java/com/jcraft/jsch/KeyExchange.java index efc8f2bf..6e1c0eac 100644 --- a/src/main/java/com/jcraft/jsch/KeyExchange.java +++ b/src/main/java/com/jcraft/jsch/KeyExchange.java @@ -69,6 +69,11 @@ public abstract class KeyExchange{ public abstract void init(Session session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception; + void doInit(Session session, + byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception { + this.session = session; + init(session, V_S, V_C, I_S, I_C); + } public abstract boolean next(Buffer buf) throws Exception; public abstract int getState(); @@ -96,13 +101,13 @@ protected static String[] guess(Session session, byte[]I_S, byte[]I_C) throws Ex Buffer sb=new Buffer(I_S); sb.setOffSet(17); Buffer cb=new Buffer(I_C); cb.setOffSet(17); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(session.getLogger().isEnabled(Logger.INFO)){ for(int i=0; iclient"+ " cipher: "+guess[PROPOSAL_ENC_ALGS_STOC]+ " MAC: "+(_s2cAEAD?(""):(guess[PROPOSAL_MAC_ALGS_STOC]))+ " compression: "+guess[PROPOSAL_COMP_ALGS_STOC]); - JSch.getLogger().log(Logger.INFO, + session.getLogger().log(Logger.INFO, "kex: client->server"+ " cipher: "+guess[PROPOSAL_ENC_ALGS_CTOS]+ " MAC: "+(_c2sAEAD?(""):(guess[PROPOSAL_MAC_ALGS_CTOS]))+ @@ -255,8 +260,8 @@ protected boolean verify(String alg, byte[] K_S, int index, sig.update(H); result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_rsa_verify: "+foo+" signature "+result); } } @@ -300,8 +305,8 @@ else if(alg.equals("ssh-dss")){ sig.update(H); result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_dss_verify: signature "+result); } } @@ -345,8 +350,8 @@ else if(alg.equals("ecdsa-sha2-nistp256") || result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_ecdsa_verify: "+alg+" signature "+result); } } @@ -378,8 +383,8 @@ else if(alg.equals("ssh-ed25519") || result=sig.verify(sig_of_H); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "ssh_eddsa_verify: "+alg+" signature "+result); } } diff --git a/src/main/java/com/jcraft/jsch/KeyPairDeferred.java b/src/main/java/com/jcraft/jsch/KeyPairDeferred.java index 2f8c7d1b..0c52be60 100644 --- a/src/main/java/com/jcraft/jsch/KeyPairDeferred.java +++ b/src/main/java/com/jcraft/jsch/KeyPairDeferred.java @@ -28,7 +28,7 @@ public boolean decrypt(byte[] _passphrase) { return true; } if (_passphrase == null) { - JSch.getLogger().log(Logger.ERROR, "no passphrase set."); + jsch.getInstanceLogger().log(Logger.ERROR, "no passphrase set."); return false; } diff --git a/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java b/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java index 9ad72401..4e51a88e 100644 --- a/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java +++ b/src/main/java/com/jcraft/jsch/KeyPairPKCS8.java @@ -370,7 +370,7 @@ else if(Util.array_equals(id, aes256cbc)){ cipher=c.getDeclaredConstructor().newInstance(); } catch(Exception e){ - if(JSch.getLogger().isEnabled(Logger.FATAL)){ + if(jsch.getInstanceLogger().isEnabled(Logger.FATAL)){ String message=""; if(name==null){ message="unknown oid: "+Util.toHex(id); @@ -378,7 +378,7 @@ else if(Util.array_equals(id, aes256cbc)){ else { message="function "+name+" is not supported"; } - JSch.getLogger().log(Logger.FATAL, "PKCS8: "+message); + jsch.getInstanceLogger().log(Logger.FATAL, "PKCS8: "+message); } } return cipher; diff --git a/src/main/java/com/jcraft/jsch/PortWatcher.java b/src/main/java/com/jcraft/jsch/PortWatcher.java index fc244341..81632df6 100644 --- a/src/main/java/com/jcraft/jsch/PortWatcher.java +++ b/src/main/java/com/jcraft/jsch/PortWatcher.java @@ -201,6 +201,7 @@ public void run(){ OutputStream out=socket.getOutputStream(); if(socketPath!=null && socketPath.length()>0){ ChannelDirectStreamLocal channel = new ChannelDirectStreamLocal(); + channel.setSession(session); channel.init(); channel.setInputStream(in); channel.setOutputStream(out); @@ -211,6 +212,7 @@ public void run(){ channel.connect(connectTimeout); } else { ChannelDirectTCPIP channel = new ChannelDirectTCPIP(); + channel.setSession(session); channel.init(); channel.setInputStream(in); channel.setOutputStream(out); diff --git a/src/main/java/com/jcraft/jsch/Session.java b/src/main/java/com/jcraft/jsch/Session.java index 0e295517..3ee69c4d 100644 --- a/src/main/java/com/jcraft/jsch/Session.java +++ b/src/main/java/com/jcraft/jsch/Session.java @@ -34,7 +34,15 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Socket; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Vector; + import javax.crypto.AEADBadTagException; public class Session implements Runnable{ @@ -73,7 +81,7 @@ public class Session implements Runnable{ private static final int PACKET_MAX_SIZE = 256 * 1024; private byte[] V_S; // server version - private byte[] V_C=Util.str2byte("SSH-2.0-JSCH_"+Version.getVersion()); // client version + private byte[] V_C=Util.str2byte("SSH-2.0-JSCH_"+JSch.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 @@ -160,6 +168,7 @@ public class Session implements Runnable{ byte[] password=null; JSch jsch; + Logger logger; Session(JSch jsch, String username, String host, int port) throws JSchException{ super(); @@ -202,8 +211,8 @@ public void connect(int connectTimeout) throws JSchException{ } Packet.setRandom(random); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Connecting to "+host+" port "+port); } @@ -243,8 +252,8 @@ public void connect(int connectTimeout) throws JSchException{ isConnected=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Connection established"); } @@ -302,10 +311,10 @@ public void connect(int connectTimeout) throws JSchException{ String _v_s=Util.byte2str(V_S); sshBugSigType74=_v_s.startsWith("SSH-2.0-OpenSSH_7.4"); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Remote version string: "+_v_s); - JSch.getLogger().log(Logger.INFO, + getLogger().log(Logger.INFO, "Local version string: "+Util.byte2str(V_C)); } @@ -317,8 +326,8 @@ public void connect(int connectTimeout) throws JSchException{ throw new JSchException("invalid protocol: "+buf.getCommand()); } - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_KEXINIT received"); } @@ -364,8 +373,8 @@ public void connect(int connectTimeout) throws JSchException{ //System.err.println("read: 21 ? "+buf.getCommand()); if(buf.getCommand()==SSH_MSG_NEWKEYS){ - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS received"); } @@ -441,16 +450,16 @@ public void connect(int connectTimeout) throws JSchException{ //System.err.println(" method: "+method); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(getLogger().isEnabled(Logger.INFO)){ String str="Authentications that can continue: "; for(int k=methodi-1; k= max_auth_tries){ - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Login trials exceeds "+max_auth_tries); } } - if(auth_cancel) - throw new JSchException("Auth cancel"); - throw new JSchException("Auth fail"); + throw new JSchException((auth_cancel ? "Auth cancel" + : "Auth fail") + + " for methods '" + smethods + "'"); } if(socket!=null && (connectTimeout>0 || timeout>0)){ @@ -615,7 +624,7 @@ private KeyExchange receive_kexinit(Buffer buf) throws Exception { throw new JSchException(e.toString(), e); } - kex.init(this, V_S, V_C, I_S, I_C); + kex.doInit(this, V_S, V_C, I_S, I_C); return kex; } @@ -636,10 +645,10 @@ private void send_kexinit() throws Exception { String ciphers2c=getConfig("cipher.s2c"); String[] not_available_ciphers=checkCiphers(getConfig("CheckCiphers")); if(not_available_ciphers!=null && not_available_ciphers.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "cipher.c2s proposal before removing unavailable algos is: " + cipherc2s); - JSch.getLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "cipher.s2c proposal before removing unavailable algos is: " + ciphers2c); } @@ -649,10 +658,10 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available ciphers."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "cipher.c2s proposal after removing unavailable algos is: " + cipherc2s); - JSch.getLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "cipher.s2c proposal after removing unavailable algos is: " + ciphers2c); } } @@ -661,10 +670,10 @@ private void send_kexinit() throws Exception { String macs2c=getConfig("mac.s2c"); String[] not_available_macs=checkMacs(getConfig("CheckMacs")); if(not_available_macs!=null && not_available_macs.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "mac.c2s proposal before removing unavailable algos is: " + macc2s); - JSch.getLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "mac.s2c proposal before removing unavailable algos is: " + macs2c); } @@ -674,10 +683,10 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available macs."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "mac.c2s proposal after removing unavailable algos is: " + macc2s); - JSch.getLogger().log(Logger.DEBUG, + getLogger().log(Logger.DEBUG, "mac.s2c proposal after removing unavailable algos is: " + macs2c); } } @@ -685,8 +694,8 @@ private void send_kexinit() throws Exception { String kex=getConfig("kex"); String[] not_available_kexes=checkKexes(getConfig("CheckKexes")); if(not_available_kexes!=null && not_available_kexes.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "kex proposal before removing unavailable algos is: " + kex); } @@ -695,8 +704,8 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available kexes."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "kex proposal after removing unavailable algos is: " + kex); } } @@ -712,8 +721,8 @@ private void send_kexinit() throws Exception { // Cache for UserAuthPublicKey this.not_available_shks = not_available_shks; if(not_available_shks!=null && not_available_shks.length>0){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal before removing unavailable algos is: " + server_host_key); } @@ -722,16 +731,16 @@ private void send_kexinit() throws Exception { throw new JSchException("There are not any available sig algorithm."); } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal after removing unavailable algos is: " + server_host_key); } } String prefer_hkr=getConfig("prefer_known_host_key_types"); if(prefer_hkr.equals("yes")){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal before known_host reordering is: " + server_host_key); } @@ -770,8 +779,8 @@ private void send_kexinit() throws Exception { } } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(getLogger().isEnabled(Logger.DEBUG)){ + getLogger().log(Logger.DEBUG, "server_host_key proposal after known_host reordering is: " + server_host_key); } } @@ -817,8 +826,8 @@ private void send_kexinit() throws Exception { write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_KEXINIT sent"); } } @@ -829,8 +838,8 @@ private void send_newkeys() throws Exception { buf.putByte((byte)SSH_MSG_NEWKEYS); write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_NEWKEYS sent"); } } @@ -953,8 +962,8 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep "This could mean that a stolen key is being used to "+ "impersonate this host."); } - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Host '"+host+"' has provided revoked key."); } throw new JSchException("revoked HostKey: "+host); @@ -963,14 +972,14 @@ private void checkHost(String chost, int port, KeyExchange kex) throws JSchExcep } if(i==HostKeyRepository.OK && - JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Host '"+host+"' is known and matches the "+key_type+" host key"); } if(insert && - JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, + getLogger().isEnabled(Logger.WARN)){ + getLogger().log(Logger.WARN, "Permanently added '"+host+"' ("+key_type+") to the list of known hosts."); } @@ -988,7 +997,7 @@ public Channel openChannel(String type) throws JSchException{ throw new JSchException("session is down"); } try{ - Channel channel=Channel.getChannel(type); + Channel channel=Channel.getChannel(type, this); addChannel(channel); channel.init(); if(channel instanceof ChannelSession){ @@ -1100,8 +1109,8 @@ public Buffer read(Buffer buf) throws Exception{ if((j%s2ccipher_size)!=0){ String message="Bad packet length "+j; - if(JSch.getLogger().isEnabled(Logger.FATAL)){ - JSch.getLogger().log(Logger.FATAL, message); + if(getLogger().isEnabled(Logger.FATAL)){ + getLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1140,8 +1149,8 @@ else if(isAEAD || isEtM){ if((j%s2ccipher_size)!=0){ String message="Bad packet length "+j; - if(JSch.getLogger().isEnabled(Logger.FATAL)){ - JSch.getLogger().log(Logger.FATAL, message); + if(getLogger().isEnabled(Logger.FATAL)){ + getLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1197,8 +1206,8 @@ else if(isAEAD || isEtM){ if((need%s2ccipher_size)!=0){ String message="Bad packet length "+need; - if(JSch.getLogger().isEnabled(Logger.FATAL)){ - JSch.getLogger().log(Logger.FATAL, message); + if(getLogger().isEnabled(Logger.FATAL)){ + getLogger().log(Logger.FATAL, message); } start_discard(buf, s2ccipher, s2cmac, 0, PACKET_MAX_SIZE-s2ccipher_size); } @@ -1263,8 +1272,8 @@ else if(type==SSH_MSG_UNIMPLEMENTED){ buf.rewind(); buf.getInt();buf.getShort(); int reason_id=buf.getInt(); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Received SSH_MSG_UNIMPLEMENTED for "+reason_id); } } @@ -1297,25 +1306,25 @@ else if(type==SSH_MSG_EXT_INFO){ String enable_server_sig_algs=getConfig("enable_server_sig_algs"); if(!enable_server_sig_algs.equals("yes")){ ignore=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO while enable_server_sig_algs != yes"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO while enable_server_sig_algs != yes"); } } else if(isAuthed){ ignore=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received after SSH_MSG_USERAUTH_SUCCESS"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received after SSH_MSG_USERAUTH_SUCCESS"); } } else if(in_kex){ ignore=true; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received before SSH_MSG_NEWKEYS"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "Ignoring SSH_MSG_EXT_INFO received before SSH_MSG_NEWKEYS"); } } else{ - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "SSH_MSG_EXT_INFO received"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "SSH_MSG_EXT_INFO received"); } } long num_extensions=buf.getUInt(); @@ -1324,8 +1333,8 @@ else if(in_kex){ byte[] ext_value=buf.getString(); if(!ignore && Util.byte2str(ext_name).equals("server-sig-algs")){ String foo=Util.byte2str(ext_value); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "server-sig-algs=<" + foo + ">"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "server-sig-algs=<" + foo + ">"); } if(sshBugSigType74){ if(!foo.isEmpty()){ @@ -1334,8 +1343,8 @@ else if(in_kex){ else{ foo="rsa-sha2-256,rsa-sha2-512"; } - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, "OpenSSH 7.4 detected: adding rsa-sha2-256 & rsa-sha2-512 to server-sig-algs"); + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "OpenSSH 7.4 detected: adding rsa-sha2-256 & rsa-sha2-512 to server-sig-algs"); } } serverSigAlgs=Util.split(foo, ","); @@ -1386,8 +1395,8 @@ private void start_discard(Buffer buf, Cipher cipher, MAC mac, } catch(IOException e){ ioe = e; - if(JSch.getLogger().isEnabled(Logger.ERROR)){ - JSch.getLogger().log(Logger.ERROR, + if(getLogger().isEnabled(Logger.ERROR)){ + getLogger().log(Logger.ERROR, "start_discard finished early due to " + e.getMessage()); } } @@ -1946,7 +1955,7 @@ else if(in_kex && stimeout c=Class.forName(foo).asSubclass(Compression.class); inflater=c.getDeclaredConstructor().newInstance(); - inflater.init(Compression.INFLATER, 0); + inflater.init(Compression.INFLATER, 0, this); } catch(Exception ee){ throw new JSchException(ee.toString(), ee); @@ -2808,8 +2817,8 @@ private String[] checkCiphers(String ciphers){ if(ciphers==null || ciphers.length()==0) return null; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "CheckCiphers: "+ciphers); } @@ -2831,9 +2840,9 @@ private String[] checkCiphers(String ciphers){ String[] foo=new String[result.size()]; System.arraycopy(result.toArray(), 0, foo, 0, result.size()); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(getLogger().isEnabled(Logger.INFO)){ for(int i=0; i c=Class.forName(kex).asSubclass(KeyExchange.class); KeyExchange _c=c.getDeclaredConstructor().newInstance(); - _c.init(s ,null, null, null, null); + _c.doInit(s ,null, null, null, null); return true; } catch(Exception | NoClassDefFoundError e){ return false; } @@ -2949,8 +2958,8 @@ private String[] checkSignatures(String sigs){ if(sigs==null || sigs.length()==0) return null; - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(getLogger().isEnabled(Logger.INFO)){ + getLogger().log(Logger.INFO, "CheckSignatures: "+sigs); } @@ -2970,9 +2979,9 @@ private String[] checkSignatures(String sigs){ return null; String[] foo=new String[result.size()]; System.arraycopy(result.toArray(), 0, foo, 0, result.size()); - if(JSch.getLogger().isEnabled(Logger.INFO)){ + if(getLogger().isEnabled(Logger.INFO)){ for(int i=0; inull if the instance logger + * of this instance's jsch instance should be used + */ + public void setLogger(Logger logger) { + this.logger = logger; + } } diff --git a/src/main/java/com/jcraft/jsch/UserAuthNone.java b/src/main/java/com/jcraft/jsch/UserAuthNone.java index 1b8b9375..8eef355b 100644 --- a/src/main/java/com/jcraft/jsch/UserAuthNone.java +++ b/src/main/java/com/jcraft/jsch/UserAuthNone.java @@ -46,8 +46,8 @@ public boolean start(Session session) throws Exception{ buf.putString(Util.str2byte("ssh-userauth")); session.write(packet); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_SERVICE_REQUEST sent"); } @@ -59,8 +59,8 @@ public boolean start(Session session) throws Exception{ boolean result=(command==SSH_MSG_SERVICE_ACCEPT); - if(JSch.getLogger().isEnabled(Logger.INFO)){ - JSch.getLogger().log(Logger.INFO, + if(session.getLogger().isEnabled(Logger.INFO)){ + session.getLogger().log(Logger.INFO, "SSH_MSG_SERVICE_ACCEPT received"); } if(!result) diff --git a/src/main/java/com/jcraft/jsch/UserAuthPublicKey.java b/src/main/java/com/jcraft/jsch/UserAuthPublicKey.java index 05282730..fb19c478 100644 --- a/src/main/java/com/jcraft/jsch/UserAuthPublicKey.java +++ b/src/main/java/com/jcraft/jsch/UserAuthPublicKey.java @@ -45,8 +45,8 @@ public boolean start(Session session) throws Exception{ } String pkmethodstr=session.getConfig("PubkeyAcceptedAlgorithms"); - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, "PubkeyAcceptedAlgorithms = " + pkmethodstr); } @@ -55,8 +55,8 @@ public boolean start(Session session) throws Exception{ Arrays.asList(not_available_pka) : Collections.emptyList()); if(!not_available_pks.isEmpty()){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, "Signature algorithms unavailable for non-agent identities = " + not_available_pks); } } @@ -88,15 +88,15 @@ public boolean start(Session session) throws Exception{ } if(!_known.isEmpty()){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, "PubkeyAcceptedAlgorithms in server-sig-algs = " + _known); } } if(!_unknown.isEmpty()){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, "PubkeyAcceptedAlgorithms not in server-sig-algs = " + _unknown); } } @@ -111,8 +111,8 @@ public boolean start(Session session) throws Exception{ } } else{ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, "No server-sig-algs found, using PubkeyAcceptedAlgorithms = " + pkmethods); + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, "No server-sig-algs found, using PubkeyAcceptedAlgorithms = " + pkmethods); } } @@ -162,8 +162,8 @@ else if(nonrsamethods.contains(_ipkmethod)){ ipkmethods=Collections.singletonList(_ipkmethod); } if(ipkmethods==null) { - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, _ipkmethod+" cannot be used as public key type for identity "+identity.getName()); } continue; @@ -177,8 +177,8 @@ else if(nonrsamethods.contains(_ipkmethod)){ loop3: for(String ipkmethod : ipkmethods){ if(not_available_pks.contains(ipkmethod) && !(identity instanceof AgentIdentity)){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, ipkmethod+" not available for identity "+identity.getName()); } continue loop3; @@ -208,16 +208,16 @@ else if(nonrsamethods.contains(_ipkmethod)){ command=buf.getCommand()&0xff; if(command==SSH_MSG_USERAUTH_PK_OK){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, ipkmethod + " preauth success"); } pkmethodsuccesses=Collections.singletonList(ipkmethod); break loop3; } else if(command==SSH_MSG_USERAUTH_FAILURE){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, ipkmethod + " preauth failure"); } continue loop3; @@ -235,8 +235,8 @@ else if(command==SSH_MSG_USERAUTH_BANNER){ else{ //System.err.println("USERAUTH fail ("+command+")"); //throw new JSchException("USERAUTH fail ("+command+")"); - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, ipkmethod + " preauth failure command (" + command + ")"); } continue loop3; @@ -262,8 +262,8 @@ else if(command==SSH_MSG_USERAUTH_BANNER){ loop4: for(String pkmethodsuccess : pkmethodsuccesses){ if(not_available_pks.contains(pkmethodsuccess) && !(identity instanceof AgentIdentity)){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, pkmethodsuccess+" not available for identity "+identity.getName()); } continue loop4; @@ -302,8 +302,8 @@ else if(command==SSH_MSG_USERAUTH_BANNER){ System.arraycopy(buf.buffer, 5, tmp, 4+sidlen, buf.index-5); byte[] signature=identity.getSignature(tmp, pkmethodsuccess); if(signature==null){ // for example, too long key length. - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, pkmethodsuccess + " signature failure"); } continue loop4; @@ -317,8 +317,8 @@ else if(command==SSH_MSG_USERAUTH_BANNER){ command=buf.getCommand()&0xff; if(command==SSH_MSG_USERAUTH_SUCCESS){ - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, pkmethodsuccess + " auth success"); } return true; @@ -343,16 +343,16 @@ else if(command==SSH_MSG_USERAUTH_FAILURE){ throw new JSchPartialAuthException(Util.byte2str(foo)); } session.auth_failures++; - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, pkmethodsuccess + " auth failure"); } break loop2; } //System.err.println("USERAUTH fail ("+command+")"); //throw new JSchException("USERAUTH fail ("+command+")"); - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, + if(session.getLogger().isEnabled(Logger.DEBUG)){ + session.getLogger().log(Logger.DEBUG, pkmethodsuccess + " auth failure command (" + command +")"); } break loop2; diff --git a/src/main/java/com/jcraft/jsch/juz/Compression.java b/src/main/java/com/jcraft/jsch/juz/Compression.java index d2d67d35..7ffd6304 100644 --- a/src/main/java/com/jcraft/jsch/juz/Compression.java +++ b/src/main/java/com/jcraft/jsch/juz/Compression.java @@ -2,6 +2,7 @@ package com.jcraft.jsch.juz; import com.jcraft.jsch.*; +import java.util.function.Supplier; import java.util.zip.Deflater; import java.util.zip.Inflater; @@ -29,10 +30,25 @@ public class Compression implements com.jcraft.jsch.Compression { private Inflater inflater; private byte[] tmpbuf=new byte[BUF_SIZE]; private byte[] inflated_buf; + private Session session; public Compression(){ } + private void logMessage(int level, Supplier message) { + Logger logger = session == null ? JSch.getLogger() : session.getLogger(); + if (!logger.isEnabled(level)) { + return; + } + logger.log(level, message.get()); + } + + @Override + public void init(int type, int level, Session session) throws Exception{ + this.session = session; + init(type, level); + } + @Override public void init(int type, int level) throws Exception{ if(type==DEFLATER){ @@ -42,10 +58,7 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, - "zlib using "+this.getClass().getCanonicalName()); - } + logMessage(Logger.DEBUG, () -> "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -99,10 +112,7 @@ public byte[] uncompress(byte[] buf, int start, int[] len){ while(inflater.getRemaining()>0); } catch(java.util.zip.DataFormatException e){ - if(JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, - "an exception during uncompress\n"+e.toString()); - } + logMessage(Logger.WARN, () -> "an exception during uncompress\n"+e.toString()); } if(buf.length message) { + Logger logger = session == null ? JSch.getLogger() : session.getLogger(); + if (!logger.isEnabled(level)) { + return; + } + logger.log(level, message.get()); + } + @Override - public void init(int type, int level) throws Exception{ + public void init(int type, int level, Session session) throws Exception{ + this.session = session; + init(type, level); + } + + public void init(int type, int level) throws GZIPException { if(type==DEFLATER){ deflater=new Deflater(level); } @@ -50,10 +67,7 @@ else if(type==INFLATER){ inflater=new Inflater(); inflated_buf=new byte[BUF_SIZE]; } - if(JSch.getLogger().isEnabled(Logger.DEBUG)){ - JSch.getLogger().log(Logger.DEBUG, - "zlib using "+this.getClass().getCanonicalName()); - } + logMessage(Logger.DEBUG, () -> "zlib using "+this.getClass().getCanonicalName()); } @Override @@ -61,7 +75,6 @@ public byte[] compress(byte[] buf, int start, int[] len){ deflater.next_in=buf; deflater.next_in_index=start; deflater.avail_in=len[0]-start; - int status; int outputlen=start; byte[] outputbuf=buf; int tmp=0; @@ -70,7 +83,7 @@ public byte[] compress(byte[] buf, int start, int[] len){ deflater.next_out=tmpbuf; deflater.next_out_index=0; deflater.avail_out=BUF_SIZE; - status=deflater.deflate(JZlib.Z_PARTIAL_FLUSH); + int status=deflater.deflate(JZlib.Z_PARTIAL_FLUSH); switch(status){ case JZlib.Z_OK: tmp=BUF_SIZE-deflater.avail_out; @@ -83,11 +96,7 @@ public byte[] compress(byte[] buf, int start, int[] len){ outputlen+=tmp; break; default: - if(JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, - "compress: deflate returnd "+status); - } - + logMessage(Logger.WARN, () -> "compress: deflate returnd "+status); } } while(deflater.avail_out==0); @@ -138,11 +147,8 @@ public byte[] uncompress(byte[] buffer, int start, int[] length){ length[0]=inflated_end; return buffer; default: - if(JSch.getLogger().isEnabled(Logger.WARN)){ - JSch.getLogger().log(Logger.WARN, - "uncompress: inflate returnd "+status); - } - return null; + logMessage(Logger.WARN, () -> "compress: deflate returnd "+status); + return null; } } } diff --git a/src/test/java/com/jcraft/jsch/JSchTest.java b/src/test/java/com/jcraft/jsch/JSchTest.java index 8293b0f7..a2d7ea96 100644 --- a/src/test/java/com/jcraft/jsch/JSchTest.java +++ b/src/test/java/com/jcraft/jsch/JSchTest.java @@ -1,5 +1,6 @@ package com.jcraft.jsch; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Hashtable; @@ -8,6 +9,11 @@ class JSchTest { + @BeforeEach + void resetJsch() { + JSch.setLogger(null); + } + @Test void getPubkeyAcceptedKeyTypes() throws JSchException { JSch.setConfig("PubkeyAcceptedAlgorithms", "JSchTest111"); @@ -30,4 +36,43 @@ void setPubkeyAcceptedKeyTypesHashtable() throws JSchException { assertEquals("JSchTest333", JSch.getConfig("PubkeyAcceptedKeyTypes")); assertEquals("JSchTest333", JSch.getConfig("PubkeyAcceptedAlgorithms")); } + + @Test + void checkLoggerBehavior() throws Exception { + assertSame(JSch.DEVNULL, JSch.logger, "initial static value of logger should be DEVNULL"); + + JSch jsch = new JSch(); + assertSame(JSch.DEVNULL, jsch.getInstanceLogger(), "instance logger should be DEVNULL"); + + TestLogger staticLogger = new TestLogger(); + TestLogger instanceLogger = new TestLogger(); + + JSch.setLogger(staticLogger); + assertSame(staticLogger, JSch.logger, "mismatch with static logger"); + assertSame(staticLogger, jsch.getInstanceLogger(), "instance should return static logger"); + + jsch.setInstanceLogger(instanceLogger); + assertSame(staticLogger, JSch.logger, "mismatch with static logger"); + assertSame(instanceLogger, jsch.getInstanceLogger(), "instance should return static logger"); + + jsch.setInstanceLogger(null); + assertSame(staticLogger, JSch.logger, "mismatch with static logger"); + assertSame(staticLogger, jsch.getInstanceLogger(), "instance should return static logger"); + + JSch.setLogger(null); + assertSame(JSch.DEVNULL, JSch.logger, "static logger should be DEVNULL"); + assertSame(JSch.DEVNULL, jsch.getInstanceLogger(), "instance logger should be DEVNULL"); + } + + final static class TestLogger implements Logger { + @Override + public boolean isEnabled(int level) { + return true; + } + + @Override + public void log(int level, String message) { + // empty + } + } } diff --git a/src/test/java/com/jcraft/jsch/SessionTest.java b/src/test/java/com/jcraft/jsch/SessionTest.java index 541018e9..aa727fca 100644 --- a/src/test/java/com/jcraft/jsch/SessionTest.java +++ b/src/test/java/com/jcraft/jsch/SessionTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import com.jcraft.jsch.JSchTest.TestLogger; + import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -54,4 +56,24 @@ void setPubkeyAcceptedKeyTypes() throws JSchException { assertEquals("SessionTest222", session.getConfig("PubkeyAcceptedKeyTypes")); assertEquals("SessionTest222", session.getConfig("PubkeyAcceptedAlgorithms")); } + + @Test + void checkLoggerFunctionality() throws Exception { + TestLogger staticLogger = new TestLogger(); + TestLogger jschInstanceLogger = new TestLogger(); + TestLogger sessionLogger = new TestLogger(); + + Session session = new Session(jsch, null, null, 0); + + assertSame(JSch.DEVNULL, session.getLogger(), "DEVNULL logger expected after creation"); + + JSch.setLogger(staticLogger); + assertSame(staticLogger, session.getLogger(), "static logger expected after setting static logger"); + + jsch.setInstanceLogger(jschInstanceLogger); + assertSame(jschInstanceLogger, session.getLogger(), "static logger expected after setting instance logger"); + + session.setLogger(sessionLogger); + assertSame(sessionLogger, session.getLogger(), "static logger expected after setting session logger"); + } } From 77a878e5e66a1d208cebd2ec17bb83d592ccdece Mon Sep 17 00:00:00 2001 From: kimmerin Date: Sun, 6 Mar 2022 19:38:26 +0100 Subject: [PATCH 15/16] set JSch static logger to null to make sure that we start at a known state --- src/test/java/com/jcraft/jsch/SessionTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/jcraft/jsch/SessionTest.java b/src/test/java/com/jcraft/jsch/SessionTest.java index aa727fca..83b4307c 100644 --- a/src/test/java/com/jcraft/jsch/SessionTest.java +++ b/src/test/java/com/jcraft/jsch/SessionTest.java @@ -59,6 +59,7 @@ void setPubkeyAcceptedKeyTypes() throws JSchException { @Test void checkLoggerFunctionality() throws Exception { + JSch.setLogger(null); TestLogger staticLogger = new TestLogger(); TestLogger jschInstanceLogger = new TestLogger(); TestLogger sessionLogger = new TestLogger(); From c7d1466a135e8ac3224656a0900cb2817f375c47 Mon Sep 17 00:00:00 2001 From: kimmerin Date: Sun, 6 Mar 2022 20:16:15 +0100 Subject: [PATCH 16/16] Keep the logger we find at the beginning of the test and reset it in finally --- src/test/java/com/jcraft/jsch/SessionTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/com/jcraft/jsch/SessionTest.java b/src/test/java/com/jcraft/jsch/SessionTest.java index 83b4307c..cc7b66e8 100644 --- a/src/test/java/com/jcraft/jsch/SessionTest.java +++ b/src/test/java/com/jcraft/jsch/SessionTest.java @@ -59,6 +59,8 @@ void setPubkeyAcceptedKeyTypes() throws JSchException { @Test void checkLoggerFunctionality() throws Exception { + Logger orgLogger = JSch.getLogger(); + try { JSch.setLogger(null); TestLogger staticLogger = new TestLogger(); TestLogger jschInstanceLogger = new TestLogger(); @@ -76,5 +78,9 @@ void checkLoggerFunctionality() throws Exception { session.setLogger(sessionLogger); assertSame(sessionLogger, session.getLogger(), "static logger expected after setting session logger"); + } + finally { + JSch.setLogger(orgLogger); + } } }