From 2f5f3754dce85212a71138fd80c2300b73461908 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Sat, 18 Jul 2015 11:30:18 -0700 Subject: Rename project to sshlib --- .../ssh2/channel/AuthAgentForwardThread.java | 579 ------- .../java/com/trilead/ssh2/channel/Channel.java | 207 --- .../trilead/ssh2/channel/ChannelInputStream.java | 86 - .../com/trilead/ssh2/channel/ChannelManager.java | 1757 -------------------- .../trilead/ssh2/channel/ChannelOutputStream.java | 71 - .../trilead/ssh2/channel/DynamicAcceptThread.java | 284 ---- .../trilead/ssh2/channel/IChannelWorkerThread.java | 13 - .../trilead/ssh2/channel/LocalAcceptThread.java | 135 -- .../trilead/ssh2/channel/RemoteAcceptThread.java | 103 -- .../trilead/ssh2/channel/RemoteForwardingData.java | 17 - .../ssh2/channel/RemoteX11AcceptThread.java | 240 --- .../com/trilead/ssh2/channel/StreamForwarder.java | 113 -- .../com/trilead/ssh2/channel/X11ServerData.java | 16 - 13 files changed, 3621 deletions(-) delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/Channel.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/ChannelInputStream.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/ChannelOutputStream.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/DynamicAcceptThread.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/IChannelWorkerThread.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/LocalAcceptThread.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/RemoteAcceptThread.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/RemoteForwardingData.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/RemoteX11AcceptThread.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/StreamForwarder.java delete mode 100644 lib/src/main/java/com/trilead/ssh2/channel/X11ServerData.java (limited to 'lib/src/main/java/com/trilead/ssh2/channel') diff --git a/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java b/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java deleted file mode 100644 index c6831e6..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Map; -import java.util.Map.Entry; - -import com.trilead.ssh2.AuthAgentCallback; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.packets.TypesWriter; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.ECDSASHA2Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; - -/** - * AuthAgentForwardThread. - * - * @author Kenny Root - * @version $Id$ - */ -public class AuthAgentForwardThread extends Thread implements IChannelWorkerThread -{ - private static final byte[] SSH_AGENT_FAILURE = {0, 0, 0, 1, 5}; // 5 - private static final byte[] SSH_AGENT_SUCCESS = {0, 0, 0, 1, 6}; // 6 - - private static final int SSH2_AGENTC_REQUEST_IDENTITIES = 11; - private static final int SSH2_AGENT_IDENTITIES_ANSWER = 12; - - private static final int SSH2_AGENTC_SIGN_REQUEST = 13; - private static final int SSH2_AGENT_SIGN_RESPONSE = 14; - - private static final int SSH2_AGENTC_ADD_IDENTITY = 17; - private static final int SSH2_AGENTC_REMOVE_IDENTITY = 18; - private static final int SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19; - -// private static final int SSH_AGENTC_ADD_SMARTCARD_KEY = 20; -// private static final int SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21; - - private static final int SSH_AGENTC_LOCK = 22; - private static final int SSH_AGENTC_UNLOCK = 23; - - private static final int SSH2_AGENTC_ADD_ID_CONSTRAINED = 25; -// private static final int SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26; - - // Constraints for adding keys - private static final int SSH_AGENT_CONSTRAIN_LIFETIME = 1; - private static final int SSH_AGENT_CONSTRAIN_CONFIRM = 2; - - // Flags for signature requests -// private static final int SSH_AGENT_OLD_SIGNATURE = 1; - - private static final Logger log = Logger.getLogger(RemoteAcceptThread.class); - - AuthAgentCallback authAgent; - OutputStream os; - InputStream is; - Channel c; - - byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE]; - - public AuthAgentForwardThread(Channel c, AuthAgentCallback authAgent) - { - this.c = c; - this.authAgent = authAgent; - - if (log.isEnabled()) - log.log(20, "AuthAgentForwardThread started"); - } - - @Override - public void run() - { - try - { - c.cm.registerThread(this); - } - catch (IOException e) - { - stopWorking(); - return; - } - - try - { - c.cm.sendOpenConfirmation(c); - - is = c.getStdoutStream(); - os = c.getStdinStream(); - - int totalSize = 4; - int readSoFar = 0; - - while (true) { - int len; - - try - { - len = is.read(buffer, readSoFar, buffer.length - readSoFar); - } - catch (IOException e) - { - stopWorking(); - return; - } - - if (len <= 0) - break; - - readSoFar += len; - - if (readSoFar >= 4) { - TypesReader tr = new TypesReader(buffer, 0, 4); - totalSize = tr.readUINT32() + 4; - } - - if (totalSize == readSoFar) { - TypesReader tr = new TypesReader(buffer, 4, readSoFar - 4); - int messageType = tr.readByte(); - - switch (messageType) { - case SSH2_AGENTC_REQUEST_IDENTITIES: - sendIdentities(); - break; - case SSH2_AGENTC_ADD_IDENTITY: - addIdentity(tr, false); - break; - case SSH2_AGENTC_ADD_ID_CONSTRAINED: - addIdentity(tr, true); - break; - case SSH2_AGENTC_REMOVE_IDENTITY: - removeIdentity(tr); - break; - case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: - removeAllIdentities(tr); - break; - case SSH2_AGENTC_SIGN_REQUEST: - processSignRequest(tr); - break; - case SSH_AGENTC_LOCK: - processLockRequest(tr); - break; - case SSH_AGENTC_UNLOCK: - processUnlockRequest(tr); - break; - default: - os.write(SSH_AGENT_FAILURE); - break; - } - - readSoFar = 0; - } - } - - c.cm.closeChannel(c, "EOF on both streams reached.", true); - } - catch (IOException e) - { - log.log(50, "IOException in agent forwarder: " + e.getMessage()); - - try - { - is.close(); - } - catch (IOException e1) - { - } - - try - { - os.close(); - } - catch (IOException e2) - { - } - - try - { - c.cm.closeChannel(c, "IOException in agent forwarder (" + e.getMessage() + ")", true); - } - catch (IOException e3) - { - } - } - } - - public void stopWorking() { - try - { - /* This will lead to an IOException in the is.read() call */ - is.close(); - } - catch (IOException e) - { - } - } - - /** - * @return whether the agent is locked - */ - private boolean failWhenLocked() throws IOException - { - if (authAgent.isAgentLocked()) { - os.write(SSH_AGENT_FAILURE); - return true; - } else - return false; - } - - private void sendIdentities() throws IOException - { - Map keys = null; - - TypesWriter tw = new TypesWriter(); - tw.writeByte(SSH2_AGENT_IDENTITIES_ANSWER); - int numKeys = 0; - - if (!authAgent.isAgentLocked()) - keys = authAgent.retrieveIdentities(); - - if (keys != null) - numKeys = keys.size(); - - tw.writeUINT32(numKeys); - - if (keys != null) { - for (Entry entry : keys.entrySet()) { - byte[] keyBytes = entry.getValue(); - tw.writeString(keyBytes, 0, keyBytes.length); - tw.writeString(entry.getKey()); - } - } - - sendPacket(tw.getBytes()); - } - - /** - * @param tr - */ - private void addIdentity(TypesReader tr, boolean checkConstraints) { - try - { - if (failWhenLocked()) - return; - - String type = tr.readString(); - - String comment; - String keyType; - KeySpec pubSpec; - KeySpec privSpec; - - if (type.equals("ssh-rsa")) { - keyType = "RSA"; - - BigInteger n = tr.readMPINT(); - BigInteger e = tr.readMPINT(); - BigInteger d = tr.readMPINT(); - BigInteger iqmp = tr.readMPINT(); - BigInteger p = tr.readMPINT(); - BigInteger q = tr.readMPINT(); - comment = tr.readString(); - - // Derive the extra values Java needs. - BigInteger dmp1 = d.mod(p.subtract(BigInteger.ONE)); - BigInteger dmq1 = d.mod(q.subtract(BigInteger.ONE)); - - pubSpec = new RSAPublicKeySpec(n, e); - privSpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, dmp1, dmq1, iqmp); - } else if (type.equals("ssh-dss")) { - keyType = "DSA"; - - BigInteger p = tr.readMPINT(); - BigInteger q = tr.readMPINT(); - BigInteger g = tr.readMPINT(); - BigInteger y = tr.readMPINT(); - BigInteger x = tr.readMPINT(); - comment = tr.readString(); - - pubSpec = new DSAPublicKeySpec(y, p, q, g); - privSpec = new DSAPrivateKeySpec(x, p, q, g); - } else if (type.equals("ecdsa-sha2-nistp256")) { - keyType = "EC"; - - String curveName = tr.readString(); - byte[] groupBytes = tr.readByteString(); - BigInteger exponent = tr.readMPINT(); - comment = tr.readString(); - - if (!"nistp256".equals(curveName)) { - log.log(2, "Invalid curve name for ecdsa-sha2-nistp256: " + curveName); - os.write(SSH_AGENT_FAILURE); - return; - } - - ECParameterSpec nistp256 = ECDSASHA2Verify.EllipticCurves.nistp256; - ECPoint group = ECDSASHA2Verify.decodeECPoint(groupBytes, nistp256.getCurve()); - if (group == null) { - // TODO log error - os.write(SSH_AGENT_FAILURE); - return; - } - - pubSpec = new ECPublicKeySpec(group, nistp256); - privSpec = new ECPrivateKeySpec(exponent, nistp256); - } else { - log.log(2, "Unknown key type: " + type); - os.write(SSH_AGENT_FAILURE); - return; - } - - PublicKey pubKey; - PrivateKey privKey; - try { - KeyFactory kf = KeyFactory.getInstance(keyType); - pubKey = kf.generatePublic(pubSpec); - privKey = kf.generatePrivate(privSpec); - } catch (NoSuchAlgorithmException ex) { - // TODO: log error - os.write(SSH_AGENT_FAILURE); - return; - } catch (InvalidKeySpecException ex) { - // TODO: log error - os.write(SSH_AGENT_FAILURE); - return; - } - - KeyPair pair = new KeyPair(pubKey, privKey); - - boolean confirmUse = false; - int lifetime = 0; - - if (checkConstraints) { - while (tr.remain() > 0) { - int constraint = tr.readByte(); - if (constraint == SSH_AGENT_CONSTRAIN_CONFIRM) - confirmUse = true; - else if (constraint == SSH_AGENT_CONSTRAIN_LIFETIME) - lifetime = tr.readUINT32(); - else { - // Unknown constraint. Bail. - os.write(SSH_AGENT_FAILURE); - return; - } - } - } - - if (authAgent.addIdentity(pair, comment, confirmUse, lifetime)) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void removeIdentity(TypesReader tr) { - try - { - if (failWhenLocked()) - return; - - byte[] publicKey = tr.readByteString(); - if (authAgent.removeIdentity(publicKey)) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void removeAllIdentities(TypesReader tr) { - try - { - if (failWhenLocked()) - return; - - if (authAgent.removeAllIdentities()) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - private void processSignRequest(TypesReader tr) - { - try - { - if (failWhenLocked()) - return; - - byte[] publicKeyBytes = tr.readByteString(); - byte[] challenge = tr.readByteString(); - - int flags = tr.readUINT32(); - - if (flags != 0) { - // We don't understand any flags; abort! - os.write(SSH_AGENT_FAILURE); - return; - } - - KeyPair pair = authAgent.getKeyPair(publicKeyBytes); - - if (pair == null) { - os.write(SSH_AGENT_FAILURE); - return; - } - - byte[] response; - - PrivateKey privKey = pair.getPrivate(); - if (privKey instanceof RSAPrivateKey) { - byte[] signature = RSASHA1Verify.generateSignature(challenge, - (RSAPrivateKey) privKey); - response = RSASHA1Verify.encodeSSHRSASignature(signature); - } else if (privKey instanceof DSAPrivateKey) { - byte[] signature = DSASHA1Verify.generateSignature(challenge, - (DSAPrivateKey) privKey, new SecureRandom()); - response = DSASHA1Verify.encodeSSHDSASignature(signature); - } else { - os.write(SSH_AGENT_FAILURE); - return; - } - - TypesWriter tw = new TypesWriter(); - tw.writeByte(SSH2_AGENT_SIGN_RESPONSE); - tw.writeString(response, 0, response.length); - - sendPacket(tw.getBytes()); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void processLockRequest(TypesReader tr) { - try - { - if (failWhenLocked()) - return; - - String lockPassphrase = tr.readString(); - if (!authAgent.setAgentLock(lockPassphrase)) { - os.write(SSH_AGENT_FAILURE); - return; - } else - os.write(SSH_AGENT_SUCCESS); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void processUnlockRequest(TypesReader tr) - { - try - { - String unlockPassphrase = tr.readString(); - - if (authAgent.requestAgentUnlock(unlockPassphrase)) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tw - * @throws IOException - */ - private void sendPacket(byte[] message) throws IOException - { - TypesWriter packet = new TypesWriter(); - packet.writeUINT32(message.length); - packet.writeBytes(message); - os.write(packet.getBytes()); - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/Channel.java b/lib/src/main/java/com/trilead/ssh2/channel/Channel.java deleted file mode 100644 index 8365f12..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/Channel.java +++ /dev/null @@ -1,207 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * Channel. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Channel.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class Channel -{ - /* - * OK. Here is an important part of the JVM Specification: - * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214) - * - * Any association between locks and variables is purely conventional. - * Locking any lock conceptually flushes all variables from a thread's - * working memory, and unlocking any lock forces the writing out to main - * memory of all variables that the thread has assigned. That a lock may be - * associated with a particular object or a class is purely a convention. - * (...) - * - * If a thread uses a particular shared variable only after locking a - * particular lock and before the corresponding unlocking of that same lock, - * then the thread will read the shared value of that variable from main - * memory after the lock operation, if necessary, and will copy back to main - * memory the value most recently assigned to that variable before the - * unlock operation. - * - * This, in conjunction with the mutual exclusion rules for locks, suffices - * to guarantee that values are correctly transmitted from one thread to - * another through shared variables. - * - * ====> Always keep that in mind when modifying the Channel/ChannelManger - * code. - * - */ - - static final int STATE_OPENING = 1; - static final int STATE_OPEN = 2; - static final int STATE_CLOSED = 4; - - static final int CHANNEL_BUFFER_SIZE = 30000; - - /* - * To achieve correctness, the following rules have to be respected when - * accessing this object: - */ - - // These fields can always be read - final ChannelManager cm; - final ChannelOutputStream stdinStream; - final ChannelInputStream stdoutStream; - final ChannelInputStream stderrStream; - - // These two fields will only be written while the Channel is in state - // STATE_OPENING. - // The code makes sure that the two fields are written out when the state is - // changing to STATE_OPEN. - // Therefore, if you know that the Channel is in state STATE_OPEN, then you - // can read these two fields without synchronizing on the Channel. However, make - // sure that you get the latest values (e.g., flush caches by synchronizing on any - // object). However, to be on the safe side, you can lock the channel. - - int localID = -1; - int remoteID = -1; - - /* - * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE - * msg. - * - * This is a little bit complicated, but we have to do it in that way, since - * we cannot keep a lock on the Channel during the send operation (this - * would block sometimes the receiver thread, and, in extreme cases, can - * lead to a deadlock on both sides of the connection (senders are blocked - * since the receive buffers on the other side are full, and receiver - * threads wait for the senders to finish). It all depends on the - * implementation on the other side. But we cannot make any assumptions, we - * have to assume the worst case. Confused? Just believe me. - */ - - /* - * If you send a message on a channel, then you have to aquire the - * "channelSendLock" and check the "closeMessageSent" flag (this variable - * may only be accessed while holding the "channelSendLock" !!! - * - * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation - * above. - */ - - final Object channelSendLock = new Object(); - boolean closeMessageSent = false; - - /* - * Stop memory fragmentation by allocating this often used buffer. - * May only be used while holding the channelSendLock - */ - - final byte[] msgWindowAdjust = new byte[9]; - - // If you access (read or write) any of the following fields, then you have - // to synchronize on the channel. - - int state = STATE_OPENING; - - boolean closeMessageRecv = false; - - /* This is a stupid implementation. At the moment we can only wait - * for one pending request per channel. - */ - int successCounter = 0; - int failedCounter = 0; - - int localWindow = 0; /* locally, we use a small window, < 2^31 */ - long remoteWindow = 0; /* long for readable 2^32 - 1 window support */ - - int localMaxPacketSize = -1; - int remoteMaxPacketSize = -1; - - final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE]; - final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE]; - - int stdoutReadpos = 0; - int stdoutWritepos = 0; - int stderrReadpos = 0; - int stderrWritepos = 0; - - boolean EOF = false; - - Integer exit_status; - - String exit_signal; - - // we keep the x11 cookie so that this channel can be closed when this - // specific x11 forwarding gets stopped - - String hexX11FakeCookie; - - // reasonClosed is special, since we sometimes need to access it - // while holding the channelSendLock. - // We protect it with a private short term lock. - - private final Object reasonClosedLock = new Object(); - private String reasonClosed = null; - - public Channel(ChannelManager cm) - { - this.cm = cm; - - this.localWindow = CHANNEL_BUFFER_SIZE; - this.localMaxPacketSize = 35000 - 1024; // leave enough slack - - this.stdinStream = new ChannelOutputStream(this); - this.stdoutStream = new ChannelInputStream(this, false); - this.stderrStream = new ChannelInputStream(this, true); - } - - /* Methods to allow access from classes outside of this package */ - - public ChannelInputStream getStderrStream() - { - return stderrStream; - } - - public ChannelOutputStream getStdinStream() - { - return stdinStream; - } - - public ChannelInputStream getStdoutStream() - { - return stdoutStream; - } - - public String getExitSignal() - { - synchronized (this) - { - return exit_signal; - } - } - - public Integer getExitStatus() - { - synchronized (this) - { - return exit_status; - } - } - - public String getReasonClosed() - { - synchronized (reasonClosedLock) - { - return reasonClosed; - } - } - - public void setReasonClosed(String reasonClosed) - { - synchronized (reasonClosedLock) - { - if (this.reasonClosed == null) - this.reasonClosed = reasonClosed; - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/ChannelInputStream.java b/lib/src/main/java/com/trilead/ssh2/channel/ChannelInputStream.java deleted file mode 100644 index f88522c..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/ChannelInputStream.java +++ /dev/null @@ -1,86 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; - -/** - * ChannelInputStream. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelInputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public final class ChannelInputStream extends InputStream -{ - Channel c; - - boolean isClosed = false; - boolean isEOF = false; - boolean extendedFlag = false; - - ChannelInputStream(Channel c, boolean isExtended) - { - this.c = c; - this.extendedFlag = isExtended; - } - - public int available() throws IOException - { - if (isEOF) - return 0; - - int avail = c.cm.getAvailable(c, extendedFlag); - - /* We must not return -1 on EOF */ - - return (avail > 0) ? avail : 0; - } - - public void close() throws IOException - { - isClosed = true; - } - - public int read(byte[] b, int off, int len) throws IOException - { - if (b == null) - throw new NullPointerException(); - - if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) - throw new IndexOutOfBoundsException(); - - if (len == 0) - return 0; - - if (isEOF) - return -1; - - int ret = c.cm.getChannelData(c, extendedFlag, b, off, len); - - if (ret == -1) - { - isEOF = true; - } - - return ret; - } - - public int read(byte[] b) throws IOException - { - return read(b, 0, b.length); - } - - public int read() throws IOException - { - /* Yes, this stream is pure and unbuffered, a single byte read() is slow */ - - final byte b[] = new byte[1]; - - int ret = read(b, 0, 1); - - if (ret != 1) - return -1; - - return b[0] & 0xff; - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java b/lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java deleted file mode 100644 index 3f05468..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java +++ /dev/null @@ -1,1757 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Vector; - -import com.trilead.ssh2.AuthAgentCallback; -import com.trilead.ssh2.ChannelCondition; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.PacketChannelAuthAgentReq; -import com.trilead.ssh2.packets.PacketChannelOpenConfirmation; -import com.trilead.ssh2.packets.PacketChannelOpenFailure; -import com.trilead.ssh2.packets.PacketChannelTrileadPing; -import com.trilead.ssh2.packets.PacketGlobalCancelForwardRequest; -import com.trilead.ssh2.packets.PacketGlobalForwardRequest; -import com.trilead.ssh2.packets.PacketGlobalTrileadPing; -import com.trilead.ssh2.packets.PacketOpenDirectTCPIPChannel; -import com.trilead.ssh2.packets.PacketOpenSessionChannel; -import com.trilead.ssh2.packets.PacketSessionExecCommand; -import com.trilead.ssh2.packets.PacketSessionPtyRequest; -import com.trilead.ssh2.packets.PacketSessionPtyResize; -import com.trilead.ssh2.packets.PacketSessionStartShell; -import com.trilead.ssh2.packets.PacketSessionSubsystemRequest; -import com.trilead.ssh2.packets.PacketSessionX11Request; -import com.trilead.ssh2.packets.Packets; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.transport.MessageHandler; -import com.trilead.ssh2.transport.TransportManager; - -/** - * ChannelManager. Please read the comments in Channel.java. - *

- * Besides the crypto part, this is the core of the library. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelManager.java,v 1.2 2008/03/03 07:01:36 cplattne Exp $ - */ -public class ChannelManager implements MessageHandler -{ - private static final Logger log = Logger.getLogger(ChannelManager.class); - - private HashMap x11_magic_cookies = new HashMap(); - - private TransportManager tm; - - private Vector channels = new Vector(); - private int nextLocalChannel = 100; - private boolean shutdown = false; - private int globalSuccessCounter = 0; - private int globalFailedCounter = 0; - - private HashMap remoteForwardings = new HashMap(); - - private AuthAgentCallback authAgent; - - private Vector listenerThreads = new Vector(); - - private boolean listenerThreadsAllowed = true; - - public ChannelManager(TransportManager tm) - { - this.tm = tm; - tm.registerMessageHandler(this, 80, 100); - } - - private Channel getChannel(int id) - { - synchronized (channels) - { - for (int i = 0; i < channels.size(); i++) - { - Channel c = channels.elementAt(i); - if (c.localID == id) - return c; - } - } - return null; - } - - private void removeChannel(int id) - { - synchronized (channels) - { - for (int i = 0; i < channels.size(); i++) - { - Channel c = channels.elementAt(i); - if (c.localID == id) - { - channels.removeElementAt(i); - break; - } - } - } - } - - private int addChannel(Channel c) - { - synchronized (channels) - { - channels.addElement(c); - return nextLocalChannel++; - } - } - - private void waitUntilChannelOpen(Channel c) throws IOException - { - synchronized (c) - { - while (c.state == Channel.STATE_OPENING) - { - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - if (c.state != Channel.STATE_OPEN) - { - removeChannel(c.localID); - - String detail = c.getReasonClosed(); - - if (detail == null) - detail = "state: " + c.state; - - throw new IOException("Could not open channel (" + detail + ")"); - } - } - } - - private final boolean waitForGlobalRequestResult() throws IOException - { - synchronized (channels) - { - while ((globalSuccessCounter == 0) && (globalFailedCounter == 0)) - { - if (shutdown) - { - throw new IOException("The connection is being shutdown"); - } - - try - { - channels.wait(); - } - catch (InterruptedException ignore) - { - } - } - - if ((globalFailedCounter == 0) && (globalSuccessCounter == 1)) - return true; - - if ((globalFailedCounter == 1) && (globalSuccessCounter == 0)) - return false; - - throw new IOException("Illegal state. The server sent " + globalSuccessCounter - + " SSH_MSG_REQUEST_SUCCESS and " + globalFailedCounter + " SSH_MSG_REQUEST_FAILURE messages."); - } - } - - private final boolean waitForChannelRequestResult(Channel c) throws IOException - { - synchronized (c) - { - while ((c.successCounter == 0) && (c.failedCounter == 0)) - { - if (c.state != Channel.STATE_OPEN) - { - String detail = c.getReasonClosed(); - - if (detail == null) - detail = "state: " + c.state; - - throw new IOException("This SSH2 channel is not open (" + detail + ")"); - } - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - if ((c.failedCounter == 0) && (c.successCounter == 1)) - return true; - - if ((c.failedCounter == 1) && (c.successCounter == 0)) - return false; - - throw new IOException("Illegal state. The server sent " + c.successCounter - + " SSH_MSG_CHANNEL_SUCCESS and " + c.failedCounter + " SSH_MSG_CHANNEL_FAILURE messages."); - } - } - - public void registerX11Cookie(String hexFakeCookie, X11ServerData data) - { - synchronized (x11_magic_cookies) - { - x11_magic_cookies.put(hexFakeCookie, data); - } - } - - public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) - { - if (hexFakeCookie == null) - throw new IllegalStateException("hexFakeCookie may not be null"); - - synchronized (x11_magic_cookies) - { - x11_magic_cookies.remove(hexFakeCookie); - } - - if (killChannels == false) - return; - - if (log.isEnabled()) - log.log(50, "Closing all X11 channels for the given fake cookie"); - - Vector channel_copy; - - synchronized (channels) - { - channel_copy = (Vector) channels.clone(); - } - - for (int i = 0; i < channel_copy.size(); i++) - { - Channel c = channel_copy.elementAt(i); - - synchronized (c) - { - if (hexFakeCookie.equals(c.hexX11FakeCookie) == false) - continue; - } - - try - { - closeChannel(c, "Closing X11 channel since the corresponding session is closing", true); - } - catch (IOException e) - { - } - } - } - - public X11ServerData checkX11Cookie(String hexFakeCookie) - { - synchronized (x11_magic_cookies) - { - if (hexFakeCookie != null) - return x11_magic_cookies.get(hexFakeCookie); - } - return null; - } - - public void closeAllChannels() - { - if (log.isEnabled()) - log.log(50, "Closing all channels"); - - Vector channel_copy; - - synchronized (channels) - { - channel_copy = (Vector) channels.clone(); - } - - for (int i = 0; i < channel_copy.size(); i++) - { - Channel c = channel_copy.elementAt(i); - try - { - closeChannel(c, "Closing all channels", true); - } - catch (IOException e) - { - } - } - } - - public void closeChannel(Channel c, String reason, boolean force) throws IOException - { - byte msg[] = new byte[5]; - - synchronized (c) - { - if (force) - { - c.state = Channel.STATE_CLOSED; - c.EOF = true; - } - - c.setReasonClosed(reason); - - msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - - c.notifyAll(); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(msg); - c.closeMessageSent = true; - } - - if (log.isEnabled()) - log.log(50, "Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); - } - - public void sendEOF(Channel c) throws IOException - { - byte[] msg = new byte[5]; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - return; - - msg[0] = Packets.SSH_MSG_CHANNEL_EOF; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(msg); - } - - if (log.isEnabled()) - log.log(50, "Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")"); - } - - public void sendOpenConfirmation(Channel c) throws IOException - { - PacketChannelOpenConfirmation pcoc = null; - - synchronized (c) - { - if (c.state != Channel.STATE_OPENING) - return; - - c.state = Channel.STATE_OPEN; - - pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(pcoc.getPayload()); - } - } - - public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException - { - while (len > 0) - { - int thislen = 0; - byte[] msg; - - synchronized (c) - { - while (true) - { - if (c.state == Channel.STATE_CLOSED) - throw new IOException("SSH channel is closed. (" + c.getReasonClosed() + ")"); - - if (c.state != Channel.STATE_OPEN) - throw new IOException("SSH channel in strange state. (" + c.state + ")"); - - if (c.remoteWindow != 0) - break; - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - /* len > 0, no sign extension can happen when comparing */ - - thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; - - int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); - - /* The worst case scenario =) a true bottleneck */ - - if (estimatedMaxDataLen <= 0) - { - estimatedMaxDataLen = 1; - } - - if (thislen > estimatedMaxDataLen) - thislen = estimatedMaxDataLen; - - c.remoteWindow -= thislen; - - msg = new byte[1 + 8 + thislen]; - - msg[0] = Packets.SSH_MSG_CHANNEL_DATA; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - msg[5] = (byte) (thislen >> 24); - msg[6] = (byte) (thislen >> 16); - msg[7] = (byte) (thislen >> 8); - msg[8] = (byte) (thislen); - - System.arraycopy(buffer, pos, msg, 9, thislen); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - throw new IOException("SSH channel is closed. (" + c.getReasonClosed() + ")"); - - tm.sendMessage(msg); - } - - pos += thislen; - len -= thislen; - } - } - - public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort) - throws IOException - { - RemoteForwardingData rfd = new RemoteForwardingData(); - - rfd.bindAddress = bindAddress; - rfd.bindPort = bindPort; - rfd.targetAddress = targetAddress; - rfd.targetPort = targetPort; - - synchronized (remoteForwardings) - { - Integer key = Integer.valueOf(bindPort); - - if (remoteForwardings.get(key) != null) - { - throw new IOException("There is already a forwarding for remote port " + bindPort); - } - - remoteForwardings.put(key, rfd); - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort); - tm.sendMessage(pgf.getPayload()); - - if (log.isEnabled()) - log.log(50, "Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")"); - - try - { - if (waitForGlobalRequestResult() == false) - throw new IOException("The server denied the request (did you enable port forwarding?)"); - } - catch (IOException e) - { - synchronized (remoteForwardings) - { - remoteForwardings.remove(rfd); - } - throw e; - } - - return bindPort; - } - - public void requestCancelGlobalForward(int bindPort) throws IOException - { - RemoteForwardingData rfd = null; - - synchronized (remoteForwardings) - { - rfd = remoteForwardings.get(Integer.valueOf(bindPort)); - - if (rfd == null) - throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort); - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress, - rfd.bindPort); - tm.sendMessage(pgcf.getPayload()); - - if (log.isEnabled()) - log.log(50, "Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")"); - - try - { - if (waitForGlobalRequestResult() == false) - throw new IOException("The server denied the request."); - } - finally - { - synchronized (remoteForwardings) - { - /* Only now we are sure that no more forwarded connections will arrive */ - remoteForwardings.remove(rfd); - } - } - - } - - /** - * @param c - * @param authAgent - * @throws IOException - */ - public boolean requestChannelAgentForwarding(Channel c, AuthAgentCallback authAgent) throws IOException { - synchronized (this) - { - if (this.authAgent != null) - throw new IllegalStateException("Auth agent already exists"); - - this.authAgent = authAgent; - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - if (log.isEnabled()) - log.log(50, "Requesting agent forwarding"); - - PacketChannelAuthAgentReq aar = new PacketChannelAuthAgentReq(c.remoteID); - tm.sendMessage(aar.getPayload()); - - if (waitForChannelRequestResult(c) == false) { - authAgent = null; - return false; - } - - return true; - } - - public void registerThread(IChannelWorkerThread thr) throws IOException - { - synchronized (listenerThreads) - { - if (listenerThreadsAllowed == false) - throw new IOException("Too late, this connection is closed."); - listenerThreads.addElement(thr); - } - } - - public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address, - int originator_port) throws IOException - { - Channel c = new Channel(this); - - synchronized (c) - { - c.localID = addChannel(c); - // end of synchronized block forces writing out to main memory - } - - PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow, - c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port); - - tm.sendMessage(dtc.getPayload()); - - waitUntilChannelOpen(c); - - return c; - } - - public Channel openSessionChannel() throws IOException - { - Channel c = new Channel(this); - - synchronized (c) - { - c.localID = addChannel(c); - // end of synchronized block forces the writing out to main memory - } - - if (log.isEnabled()) - log.log(50, "Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")"); - - PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize); - tm.sendMessage(smo.getPayload()); - - waitUntilChannelOpen(c); - - return c; - } - - public void requestGlobalTrileadPing() throws IOException - { - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalTrileadPing pgtp = new PacketGlobalTrileadPing(); - - tm.sendMessage(pgtp.getPayload()); - - if (log.isEnabled()) - log.log(50, "Sending SSH_MSG_GLOBAL_REQUEST 'trilead-ping'."); - - try - { - if (waitForGlobalRequestResult() == true) - throw new IOException("Your server is alive - but buggy. " - + "It replied with SSH_MSG_REQUEST_SUCCESS when it actually should not."); - - } - catch (IOException e) - { - throw (IOException) new IOException("The ping request failed.").initCause(e); - } - } - - public void requestChannelTrileadPing(Channel c) throws IOException - { - PacketChannelTrileadPing pctp; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot ping this channel (" + c.getReasonClosed() + ")"); - - pctp = new PacketChannelTrileadPing(c.remoteID); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot ping this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(pctp.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == true) - throw new IOException("Your server is alive - but buggy. " - + "It replied with SSH_MSG_SESSION_SUCCESS when it actually should not."); - - } - catch (IOException e) - { - throw (IOException) new IOException("The ping request failed.").initCause(e); - } - } - - public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters, - int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException - { - PacketSessionPtyRequest spr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); - - spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters, - term_width_pixels, term_height_pixels, terminal_modes); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(spr.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("PTY request failed").initCause(e); - } - } - - - public void resizePTY(Channel c, int term_width_characters, int term_height_characters, - int term_width_pixels, int term_height_pixels) throws IOException { - PacketSessionPtyResize spr; - - synchronized (c) { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request PTY on this channel (" - + c.getReasonClosed() + ")"); - - spr = new PacketSessionPtyResize(c.remoteID, term_width_characters, term_height_characters, - term_width_pixels, term_height_pixels); - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) { - if (c.closeMessageSent) - throw new IOException("Cannot request PTY on this channel (" - + c.getReasonClosed() + ")"); - tm.sendMessage(spr.getPayload()); - } - } - - - public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol, - String x11AuthenticationCookie, int x11ScreenNumber) throws IOException - { - PacketSessionX11Request psr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); - - psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol, - x11AuthenticationCookie, x11ScreenNumber); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(psr.getPayload()); - } - - if (log.isEnabled()) - log.log(50, "Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")"); - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The X11 request failed.").initCause(e); - } - } - - public void requestSubSystem(Channel c, String subSystemName) throws IOException - { - PacketSessionSubsystemRequest ssr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); - - ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(ssr.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The subsystem request failed.").initCause(e); - } - } - - public void requestExecCommand(Channel c, String cmd) throws IOException - { - PacketSessionExecCommand sm; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); - - sm = new PacketSessionExecCommand(c.remoteID, true, cmd); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(sm.getPayload()); - } - - if (log.isEnabled()) - log.log(50, "Executing command (channel " + c.localID + ", '" + cmd + "')"); - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The execute request failed.").initCause(e); - } - } - - public void requestShell(Channel c) throws IOException - { - PacketSessionStartShell sm; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); - - sm = new PacketSessionStartShell(c.remoteID, true); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(sm.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The shell request failed.").initCause(e); - } - } - - public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException - { - if (msglen <= 13) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id); - - if (dataType != Packets.SSH_EXTENDED_DATA_STDERR) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")"); - - if (len != (msglen - 13)) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13) - + ", got " + len + ")"); - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")"); - - synchronized (c) - { - if (c.state == Channel.STATE_CLOSED) - return; // ignore - - if (c.state != Channel.STATE_OPEN) - throw new IOException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (" - + c.state + ")"); - - if (c.localWindow < len) - throw new IOException("Remote sent too much data, does not fit into window."); - - c.localWindow -= len; - - System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len); - c.stderrWritepos += len; - - c.notifyAll(); - } - } - - /** - * Wait until for a condition. - * - * @param c - * Channel - * @param timeout - * in ms, 0 means no timeout. - * @param condition_mask - * minimum event mask - * @return all current events - * - */ - public int waitForCondition(Channel c, long timeout, int condition_mask) - { - long end_time = 0; - boolean end_time_set = false; - - synchronized (c) - { - while (true) - { - int current_cond = 0; - - int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; - int stderrAvail = c.stderrWritepos - c.stderrReadpos; - - if (stdoutAvail > 0) - current_cond = current_cond | ChannelCondition.STDOUT_DATA; - - if (stderrAvail > 0) - current_cond = current_cond | ChannelCondition.STDERR_DATA; - - if (c.EOF) - current_cond = current_cond | ChannelCondition.EOF; - - if (c.getExitStatus() != null) - current_cond = current_cond | ChannelCondition.EXIT_STATUS; - - if (c.getExitSignal() != null) - current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; - - if (c.state == Channel.STATE_CLOSED) - return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; - - if ((current_cond & condition_mask) != 0) - return current_cond; - - if (timeout > 0) - { - if (!end_time_set) - { - end_time = System.currentTimeMillis() + timeout; - end_time_set = true; - } - else - { - timeout = end_time - System.currentTimeMillis(); - - if (timeout <= 0) - return current_cond | ChannelCondition.TIMEOUT; - } - } - - try - { - if (timeout > 0) - c.wait(timeout); - else - c.wait(); - } - catch (InterruptedException e) - { - } - } - } - } - - public int getAvailable(Channel c, boolean extended) throws IOException - { - synchronized (c) - { - int avail; - - if (extended) - avail = c.stderrWritepos - c.stderrReadpos; - else - avail = c.stdoutWritepos - c.stdoutReadpos; - - return ((avail > 0) ? avail : (c.EOF ? -1 : 0)); - } - } - - public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException - { - int copylen = 0; - int increment = 0; - int remoteID = 0; - int localID = 0; - - synchronized (c) - { - int stdoutAvail = 0; - int stderrAvail = 0; - - while (true) - { - /* - * Data available? We have to return remaining data even if the - * channel is already closed. - */ - - stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; - stderrAvail = c.stderrWritepos - c.stderrReadpos; - - if ((!extended) && (stdoutAvail != 0)) - break; - - if ((extended) && (stderrAvail != 0)) - break; - - /* Do not wait if more data will never arrive (EOF or CLOSED) */ - - if ((c.EOF) || (c.state != Channel.STATE_OPEN)) - return -1; - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - /* OK, there is some data. Return it. */ - - if (!extended) - { - copylen = (stdoutAvail > len) ? len : stdoutAvail; - System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); - c.stdoutReadpos += copylen; - - if (c.stdoutReadpos != c.stdoutWritepos) - - System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos - - c.stdoutReadpos); - - c.stdoutWritepos -= c.stdoutReadpos; - c.stdoutReadpos = 0; - } - else - { - copylen = (stderrAvail > len) ? len : stderrAvail; - System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); - c.stderrReadpos += copylen; - - if (c.stderrReadpos != c.stderrWritepos) - - System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos - - c.stderrReadpos); - - c.stderrWritepos -= c.stderrReadpos; - c.stderrReadpos = 0; - } - - if (c.state != Channel.STATE_OPEN) - return copylen; - - if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) - { - int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, Channel.CHANNEL_BUFFER_SIZE - - c.stderrWritepos); - - increment = minFreeSpace - c.localWindow; - c.localWindow = minFreeSpace; - } - - remoteID = c.remoteID; /* read while holding the lock */ - localID = c.localID; /* read while holding the lock */ - } - - /* - * If a consumer reads stdout and stdin in parallel, we may end up with - * sending two msgWindowAdjust messages. Luckily, it - * does not matter in which order they arrive at the server. - */ - - if (increment > 0) - { - if (log.isEnabled()) - log.log(80, "Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); - - synchronized (c.channelSendLock) - { - byte[] msg = c.msgWindowAdjust; - - msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; - msg[1] = (byte) (remoteID >> 24); - msg[2] = (byte) (remoteID >> 16); - msg[3] = (byte) (remoteID >> 8); - msg[4] = (byte) (remoteID); - msg[5] = (byte) (increment >> 24); - msg[6] = (byte) (increment >> 16); - msg[7] = (byte) (increment >> 8); - msg[8] = (byte) (increment); - - if (c.closeMessageSent == false) - tm.sendMessage(msg); - } - } - - return copylen; - } - - public void msgChannelData(byte[] msg, int msglen) throws IOException - { - if (msglen <= 9) - throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); - - if (len != (msglen - 9)) - throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got " - + len + ")"); - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); - - synchronized (c) - { - if (c.state == Channel.STATE_CLOSED) - return; // ignore - - if (c.state != Channel.STATE_OPEN) - throw new IOException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); - - if (c.localWindow < len) - throw new IOException("Remote sent too much data, does not fit into window."); - - c.localWindow -= len; - - System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); - c.stdoutWritepos += len; - - c.notifyAll(); - } - } - - public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException - { - if (msglen != 9) - throw new IOException("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); - - synchronized (c) - { - final long huge = 0xFFFFffffL; /* 2^32 - 1 */ - - c.remoteWindow += (windowChange & huge); /* avoid sign extension */ - - /* TODO - is this a good heuristic? */ - - if ((c.remoteWindow > huge)) - c.remoteWindow = huge; - - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); - } - - public void msgChannelOpen(byte[] msg, int msglen) throws IOException - { - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - String channelType = tr.readString(); - int remoteID = tr.readUINT32(); /* sender channel */ - int remoteWindow = tr.readUINT32(); /* initial window size */ - int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ - - if ("x11".equals(channelType)) - { - synchronized (x11_magic_cookies) - { - /* If we did not request X11 forwarding, then simply ignore this bogus request. */ - - if (x11_magic_cookies.size() == 0) - { - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, - Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); - - tm.sendAsynchronousMessage(pcof.getPayload()); - - if (log.isEnabled()) - log.log(20, "Unexpected X11 request, denying it!"); - - return; - } - } - - String remoteOriginatorAddress = tr.readString(); - int remoteOriginatorPort = tr.readUINT32(); - - Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } - - /* - * The open confirmation message will be sent from another thread - */ - - RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); - rxat.setDaemon(true); - rxat.start(); - - return; - } - - if ("forwarded-tcpip".equals(channelType)) - { - String remoteConnectedAddress = tr.readString(); /* address that was connected */ - int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ - String remoteOriginatorAddress = tr.readString(); /* originator IP address */ - int remoteOriginatorPort = tr.readUINT32(); /* originator port */ - - RemoteForwardingData rfd = null; - - synchronized (remoteForwardings) - { - rfd = remoteForwardings.get(Integer.valueOf(remoteConnectedPort)); - } - - if (rfd == null) - { - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, - Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, - "No thanks, unknown port in forwarded-tcpip request", ""); - - /* Always try to be polite. */ - - tm.sendAsynchronousMessage(pcof.getPayload()); - - if (log.isEnabled()) - log.log(20, "Unexpected forwarded-tcpip request, denying it!"); - - return; - } - - Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } - - /* - * The open confirmation message will be sent from another thread. - */ - - RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort, - remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); - - rat.setDaemon(true); - rat.start(); - - return; - } - - if ("auth-agent@openssh.com".equals(channelType)) { - Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } - - AuthAgentForwardThread aat = new AuthAgentForwardThread(c, authAgent); - - aat.setDaemon(true); - aat.start(); - - return; - } - - /* Tell the server that we have no idea what it is talking about */ - - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, - "Unknown channel type", ""); - - tm.sendAsynchronousMessage(pcof.getPayload()); - - if (log.isEnabled()) - log.log(20, "The peer tried to open an unsupported channel type (" + channelType + ")"); - } - - public void msgChannelRequest(byte[] msg, int msglen) throws IOException - { - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - int id = tr.readUINT32(); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); - - String type = tr.readString("US-ASCII"); - boolean wantReply = tr.readBoolean(); - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); - - if (type.equals("exit-status")) - { - if (wantReply != false) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true"); - - int exit_status = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - synchronized (c) - { - c.exit_status = Integer.valueOf(exit_status); - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); - - return; - } - - if (type.equals("exit-signal")) - { - if (wantReply != false) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true"); - - String signame = tr.readString("US-ASCII"); - tr.readBoolean(); - tr.readString(); - tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - synchronized (c) - { - c.exit_signal = signame; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); - - return; - } - - /* We simply ignore unknown channel requests, however, if the server wants a reply, - * then we signal that we have no idea what it is about. - */ - - if (wantReply) - { - byte[] reply = new byte[5]; - - reply[0] = Packets.SSH_MSG_CHANNEL_FAILURE; - reply[1] = (byte) (c.remoteID >> 24); - reply[2] = (byte) (c.remoteID >> 16); - reply[3] = (byte) (c.remoteID >> 8); - reply[4] = (byte) (c.remoteID); - - tm.sendAsynchronousMessage(reply); - } - - if (log.isEnabled()) - log.log(50, "Channel request '" + type + "' is not known, ignoring it"); - } - - public void msgChannelEOF(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id); - - synchronized (c) - { - c.EOF = true; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_EOF (channel " + id + ")"); - } - - public void msgChannelClose(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); - - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("Close requested by remote"); - c.closeMessageRecv = true; - - removeChannel(c.localID); - - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); - } - - public void msgChannelSuccess(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id); - - synchronized (c) - { - c.successCounter++; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")"); - } - - public void msgChannelFailure(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); - - synchronized (c) - { - c.failedCounter++; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); - } - - public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException - { - PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen); - - Channel c = getChannel(sm.recipientChannelID); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " - + sm.recipientChannelID); - - synchronized (c) - { - if (c.state != Channel.STATE_OPENING) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " - + sm.recipientChannelID); - - c.remoteID = sm.senderChannelID; - c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = sm.maxPacketSize; - c.state = Channel.STATE_OPEN; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: " - + sm.senderChannelID + ")"); - } - - public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException - { - if (msglen < 5) - throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")"); - - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - int id = tr.readUINT32(); /* sender channel */ - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); - - int reasonCode = tr.readUINT32(); - String description = tr.readString("UTF-8"); - - String reasonCodeSymbolicName = null; - - switch (reasonCode) - { - case 1: - reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; - break; - case 2: - reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; - break; - case 3: - reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; - break; - case 4: - reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; - break; - default: - reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; - } - - StringBuffer descriptionBuffer = new StringBuffer(); - descriptionBuffer.append(description); - - for (int i = 0; i < descriptionBuffer.length(); i++) - { - char cc = descriptionBuffer.charAt(i); - - if ((cc >= 32) && (cc <= 126)) - continue; - descriptionBuffer.setCharAt(i, '\uFFFD'); - } - - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '" - + descriptionBuffer.toString() + "')"); - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); - } - - public void msgGlobalRequest(byte[] msg, int msglen) throws IOException - { - /* Currently we do not support any kind of global request */ - - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - String requestName = tr.readString(); - boolean wantReply = tr.readBoolean(); - - if (wantReply) - { - byte[] reply_failure = new byte[1]; - reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; - - tm.sendAsynchronousMessage(reply_failure); - } - - /* We do not clean up the requestName String - that is OK for debug */ - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); - } - - public void msgGlobalSuccess() throws IOException - { - synchronized (channels) - { - globalSuccessCounter++; - channels.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_REQUEST_SUCCESS"); - } - - public void msgGlobalFailure() throws IOException - { - synchronized (channels) - { - globalFailedCounter++; - channels.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_REQUEST_FAILURE"); - } - - public void handleMessage(byte[] msg, int msglen) throws IOException - { - if (msg == null) - { - if (log.isEnabled()) - log.log(50, "HandleMessage: got shutdown"); - - synchronized (listenerThreads) - { - for (int i = 0; i < listenerThreads.size(); i++) - { - IChannelWorkerThread lat = listenerThreads.elementAt(i); - lat.stopWorking(); - } - listenerThreadsAllowed = false; - } - - synchronized (channels) - { - shutdown = true; - - for (int i = 0; i < channels.size(); i++) - { - Channel c = channels.elementAt(i); - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("The connection is being shutdown"); - c.closeMessageRecv = true; /* - * You never know, perhaps - * we are waiting for a - * pending close message - * from the server... - */ - c.notifyAll(); - } - } - /* Works with J2ME */ - channels.setSize(0); - channels.trimToSize(); - channels.notifyAll(); /* Notify global response waiters */ - return; - } - } - - switch (msg[0]) - { - case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: - msgChannelOpenConfirmation(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: - msgChannelWindowAdjust(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_DATA: - msgChannelData(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: - msgChannelExtendedData(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_REQUEST: - msgChannelRequest(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_EOF: - msgChannelEOF(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_OPEN: - msgChannelOpen(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_CLOSE: - msgChannelClose(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_SUCCESS: - msgChannelSuccess(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_FAILURE: - msgChannelFailure(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: - msgChannelOpenFailure(msg, msglen); - break; - case Packets.SSH_MSG_GLOBAL_REQUEST: - msgGlobalRequest(msg, msglen); - break; - case Packets.SSH_MSG_REQUEST_SUCCESS: - msgGlobalSuccess(); - break; - case Packets.SSH_MSG_REQUEST_FAILURE: - msgGlobalFailure(); - break; - default: - throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff)); - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/ChannelOutputStream.java b/lib/src/main/java/com/trilead/ssh2/channel/ChannelOutputStream.java deleted file mode 100644 index c1d56e8..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/ChannelOutputStream.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * ChannelOutputStream. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelOutputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public final class ChannelOutputStream extends OutputStream -{ - Channel c; - - private byte[] writeBuffer; - - boolean isClosed = false; - - ChannelOutputStream(Channel c) - { - this.c = c; - writeBuffer = new byte[1]; - } - - public void write(int b) throws IOException - { - writeBuffer[0] = (byte) b; - - write(writeBuffer, 0, 1); - } - - public void close() throws IOException - { - if (isClosed == false) - { - isClosed = true; - c.cm.sendEOF(c); - } - } - - public void flush() throws IOException - { - if (isClosed) - throw new IOException("This OutputStream is closed."); - - /* This is a no-op, since this stream is unbuffered */ - } - - public void write(byte[] b, int off, int len) throws IOException - { - if (isClosed) - throw new IOException("This OutputStream is closed."); - - if (b == null) - throw new NullPointerException(); - - if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) - throw new IndexOutOfBoundsException(); - - if (len == 0) - return; - - c.cm.sendData(c, b, off, len); - } - - public void write(byte[] b) throws IOException - { - write(b, 0, b.length); - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/DynamicAcceptThread.java b/lib/src/main/java/com/trilead/ssh2/channel/DynamicAcceptThread.java deleted file mode 100644 index ef3a3d0..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/DynamicAcceptThread.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.PushbackInputStream; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.NoRouteToHostException; -import java.net.ServerSocket; -import java.net.Socket; - -import net.sourceforge.jsocks.Proxy; -import net.sourceforge.jsocks.ProxyMessage; -import net.sourceforge.jsocks.Socks4Message; -import net.sourceforge.jsocks.Socks5Message; -import net.sourceforge.jsocks.SocksException; -import net.sourceforge.jsocks.server.ServerAuthenticator; -import net.sourceforge.jsocks.server.ServerAuthenticatorNone; - -/** - * DynamicAcceptThread. - * - * @author Kenny Root - * @version $Id$ - */ -public class DynamicAcceptThread extends Thread implements IChannelWorkerThread { - private ChannelManager cm; - private ServerSocket ss; - - class DynamicAcceptRunnable implements Runnable { - private static final int idleTimeout = 180000; //3 minutes - - private ServerAuthenticator auth; - private Socket sock; - private InputStream in; - private OutputStream out; - private ProxyMessage msg; - - public DynamicAcceptRunnable(ServerAuthenticator auth, Socket sock) { - this.auth = auth; - this.sock = sock; - - setName("DynamicAcceptRunnable"); - } - - public void run() { - try { - startSession(); - } catch (IOException ioe) { - int error_code = Proxy.SOCKS_FAILURE; - - if (ioe instanceof SocksException) - error_code = ((SocksException) ioe).errCode; - else if (ioe instanceof NoRouteToHostException) - error_code = Proxy.SOCKS_HOST_UNREACHABLE; - else if (ioe instanceof ConnectException) - error_code = Proxy.SOCKS_CONNECTION_REFUSED; - else if (ioe instanceof InterruptedIOException) - error_code = Proxy.SOCKS_TTL_EXPIRE; - - if (error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED - || error_code < 0) { - error_code = Proxy.SOCKS_FAILURE; - } - - sendErrorMessage(error_code); - } finally { - if (auth != null) - auth.endSession(); - } - } - - private ProxyMessage readMsg(InputStream in) throws IOException { - PushbackInputStream push_in; - if (in instanceof PushbackInputStream) - push_in = (PushbackInputStream) in; - else - push_in = new PushbackInputStream(in); - - int version = push_in.read(); - push_in.unread(version); - - ProxyMessage msg; - - if (version == 5) { - msg = new Socks5Message(push_in, false); - } else if (version == 4) { - msg = new Socks4Message(push_in, false); - } else { - throw new SocksException(Proxy.SOCKS_FAILURE); - } - return msg; - } - - private void sendErrorMessage(int error_code) { - ProxyMessage err_msg; - if (msg instanceof Socks4Message) - err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); - else - err_msg = new Socks5Message(error_code); - try { - err_msg.write(out); - } catch (IOException ioe) { - } - } - - private void handleRequest(ProxyMessage msg) throws IOException { - if (!auth.checkRequest(msg)) - throw new SocksException(Proxy.SOCKS_FAILURE); - - switch (msg.command) { - case Proxy.SOCKS_CMD_CONNECT: - onConnect(msg); - break; - default: - throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED); - } - } - - private void startSession() throws IOException { - sock.setSoTimeout(idleTimeout); - - try { - auth = auth.startSession(sock); - } catch (IOException ioe) { - System.out.println("Could not start SOCKS session"); - ioe.printStackTrace(); - auth = null; - return; - } - - if (auth == null) { // Authentication failed - System.out.println("SOCKS auth failed"); - return; - } - - in = auth.getInputStream(); - out = auth.getOutputStream(); - - msg = readMsg(in); - handleRequest(msg); - } - - private void onConnect(ProxyMessage msg) throws IOException { - ProxyMessage response = null; - Channel cn = null; - StreamForwarder r2l = null; - StreamForwarder l2r = null; - - if (msg instanceof Socks5Message) { - response = new Socks5Message(Proxy.SOCKS_SUCCESS, (InetAddress)null, 0); - } else { - response = new Socks4Message(Socks4Message.REPLY_OK, (InetAddress)null, 0); - } - response.write(out); - - String destHost = msg.host; - if (msg.ip != null) - destHost = msg.ip.getHostAddress(); - - try { - /* - * This may fail, e.g., if the remote port is closed (in - * optimistic terms: not open yet) - */ - - cn = cm.openDirectTCPIPChannel(destHost, msg.port, - "127.0.0.1", 0); - - } catch (IOException e) { - /* - * Simply close the local socket and wait for the next incoming - * connection - */ - - try { - sock.close(); - } catch (IOException ignore) { - } - - return; - } - - try { - r2l = new StreamForwarder(cn, null, sock, cn.stdoutStream, out, "RemoteToLocal"); - l2r = new StreamForwarder(cn, r2l, sock, in, cn.stdinStream, "LocalToRemote"); - } catch (IOException e) { - try { - /* - * This message is only visible during debugging, since we - * discard the channel immediatelly - */ - cn.cm.closeChannel(cn, - "Weird error during creation of StreamForwarder (" - + e.getMessage() + ")", true); - } catch (IOException ignore) { - } - - return; - } - - r2l.setDaemon(true); - l2r.setDaemon(true); - r2l.start(); - l2r.start(); - } - } - - public DynamicAcceptThread(ChannelManager cm, int local_port) - throws IOException { - this.cm = cm; - - setName("DynamicAcceptThread"); - - ss = new ServerSocket(local_port); - } - - public DynamicAcceptThread(ChannelManager cm, InetSocketAddress localAddress) - throws IOException { - this.cm = cm; - - ss = new ServerSocket(); - ss.bind(localAddress); - } - - @Override - public void run() { - try { - cm.registerThread(this); - } catch (IOException e) { - stopWorking(); - return; - } - - while (true) { - Socket sock = null; - - try { - sock = ss.accept(); - } catch (IOException e) { - stopWorking(); - return; - } - - DynamicAcceptRunnable dar = new DynamicAcceptRunnable(new ServerAuthenticatorNone(), sock); - Thread t = new Thread(dar); - t.setDaemon(true); - t.start(); - } - } - - /* - * (non-Javadoc) - * - * @see com.trilead.ssh2.channel.IChannelWorkerThread#stopWorking() - */ - public void stopWorking() { - try { - /* This will lead to an IOException in the ss.accept() call */ - ss.close(); - } catch (IOException e) { - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/IChannelWorkerThread.java b/lib/src/main/java/com/trilead/ssh2/channel/IChannelWorkerThread.java deleted file mode 100644 index bce9b1b..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/IChannelWorkerThread.java +++ /dev/null @@ -1,13 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * IChannelWorkerThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: IChannelWorkerThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -interface IChannelWorkerThread -{ - public void stopWorking(); -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/LocalAcceptThread.java b/lib/src/main/java/com/trilead/ssh2/channel/LocalAcceptThread.java deleted file mode 100644 index 0d1bb35..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/LocalAcceptThread.java +++ /dev/null @@ -1,135 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; - -/** - * LocalAcceptThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: LocalAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class LocalAcceptThread extends Thread implements IChannelWorkerThread -{ - ChannelManager cm; - String host_to_connect; - int port_to_connect; - - final ServerSocket ss; - - public LocalAcceptThread(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect) - throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - ss = new ServerSocket(local_port); - } - - public LocalAcceptThread(ChannelManager cm, InetSocketAddress localAddress, String host_to_connect, - int port_to_connect) throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - ss = new ServerSocket(); - ss.bind(localAddress); - } - - public void run() - { - try - { - cm.registerThread(this); - } - catch (IOException e) - { - stopWorking(); - return; - } - - while (true) - { - Socket s = null; - - try - { - s = ss.accept(); - } - catch (IOException e) - { - stopWorking(); - return; - } - - Channel cn = null; - StreamForwarder r2l = null; - StreamForwarder l2r = null; - - try - { - /* This may fail, e.g., if the remote port is closed (in optimistic terms: not open yet) */ - - cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, s.getInetAddress().getHostAddress(), s - .getPort()); - - } - catch (IOException e) - { - /* Simply close the local socket and wait for the next incoming connection */ - - try - { - s.close(); - } - catch (IOException ignore) - { - } - - continue; - } - - try - { - r2l = new StreamForwarder(cn, null, s, cn.stdoutStream, s.getOutputStream(), "RemoteToLocal"); - l2r = new StreamForwarder(cn, r2l, s, s.getInputStream(), cn.stdinStream, "LocalToRemote"); - } - catch (IOException e) - { - try - { - /* This message is only visible during debugging, since we discard the channel immediatelly */ - cn.cm.closeChannel(cn, "Weird error during creation of StreamForwarder (" + e.getMessage() + ")", - true); - } - catch (IOException ignore) - { - } - - continue; - } - - r2l.setDaemon(true); - l2r.setDaemon(true); - r2l.start(); - l2r.start(); - } - } - - public void stopWorking() - { - try - { - /* This will lead to an IOException in the ss.accept() call */ - ss.close(); - } - catch (IOException e) - { - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/RemoteAcceptThread.java b/lib/src/main/java/com/trilead/ssh2/channel/RemoteAcceptThread.java deleted file mode 100644 index 29b02b8..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/RemoteAcceptThread.java +++ /dev/null @@ -1,103 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.net.Socket; - -import com.trilead.ssh2.log.Logger; - - -/** - * RemoteAcceptThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RemoteAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class RemoteAcceptThread extends Thread -{ - private static final Logger log = Logger.getLogger(RemoteAcceptThread.class); - - Channel c; - - String remoteConnectedAddress; - int remoteConnectedPort; - String remoteOriginatorAddress; - int remoteOriginatorPort; - String targetAddress; - int targetPort; - - Socket s; - - public RemoteAcceptThread(Channel c, String remoteConnectedAddress, int remoteConnectedPort, - String remoteOriginatorAddress, int remoteOriginatorPort, String targetAddress, int targetPort) - { - this.c = c; - this.remoteConnectedAddress = remoteConnectedAddress; - this.remoteConnectedPort = remoteConnectedPort; - this.remoteOriginatorAddress = remoteOriginatorAddress; - this.remoteOriginatorPort = remoteOriginatorPort; - this.targetAddress = targetAddress; - this.targetPort = targetPort; - - if (log.isEnabled()) - log.log(20, "RemoteAcceptThread: " + remoteConnectedAddress + "/" + remoteConnectedPort + ", R: " - + remoteOriginatorAddress + "/" + remoteOriginatorPort); - } - - public void run() - { - try - { - c.cm.sendOpenConfirmation(c); - - s = new Socket(targetAddress, targetPort); - - StreamForwarder r2l = new StreamForwarder(c, null, s, c.getStdoutStream(), s.getOutputStream(), - "RemoteToLocal"); - StreamForwarder l2r = new StreamForwarder(c, null, null, s.getInputStream(), c.getStdinStream(), - "LocalToRemote"); - - /* No need to start two threads, one can be executed in the current thread */ - - r2l.setDaemon(true); - r2l.start(); - l2r.run(); - - while (r2l.isAlive()) - { - try - { - r2l.join(); - } - catch (InterruptedException e) - { - } - } - - /* If the channel is already closed, then this is a no-op */ - - c.cm.closeChannel(c, "EOF on both streams reached.", true); - s.close(); - } - catch (IOException e) - { - log.log(50, "IOException in proxy code: " + e.getMessage()); - - try - { - c.cm.closeChannel(c, "IOException in proxy code (" + e.getMessage() + ")", true); - } - catch (IOException e1) - { - } - try - { - if (s != null) - s.close(); - } - catch (IOException e1) - { - } - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/RemoteForwardingData.java b/lib/src/main/java/com/trilead/ssh2/channel/RemoteForwardingData.java deleted file mode 100644 index d05378e..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/RemoteForwardingData.java +++ /dev/null @@ -1,17 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * RemoteForwardingData. Data about a requested remote forwarding. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RemoteForwardingData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class RemoteForwardingData -{ - public String bindAddress; - public int bindPort; - - String targetAddress; - int targetPort; -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/RemoteX11AcceptThread.java b/lib/src/main/java/com/trilead/ssh2/channel/RemoteX11AcceptThread.java deleted file mode 100644 index 9f99410..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/RemoteX11AcceptThread.java +++ /dev/null @@ -1,240 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -import com.trilead.ssh2.log.Logger; - - -/** - * RemoteX11AcceptThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RemoteX11AcceptThread.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class RemoteX11AcceptThread extends Thread -{ - private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class); - - Channel c; - - String remoteOriginatorAddress; - int remoteOriginatorPort; - - Socket s; - - public RemoteX11AcceptThread(Channel c, String remoteOriginatorAddress, int remoteOriginatorPort) - { - this.c = c; - this.remoteOriginatorAddress = remoteOriginatorAddress; - this.remoteOriginatorPort = remoteOriginatorPort; - } - - public void run() - { - try - { - /* Send Open Confirmation */ - - c.cm.sendOpenConfirmation(c); - - /* Read startup packet from client */ - - OutputStream remote_os = c.getStdinStream(); - InputStream remote_is = c.getStdoutStream(); - - /* The following code is based on the protocol description given in: - * Scheifler/Gettys, - * X Windows System: Core and Extension Protocols: - * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X - */ - - /* - * Client startup: - * - * 1 0X42 MSB first/0x6c lSB first - byteorder - * 1 - unused - * 2 card16 - protocol-major-version - * 2 card16 - protocol-minor-version - * 2 n - lenght of authorization-protocol-name - * 2 d - lenght of authorization-protocol-data - * 2 - unused - * string8 - authorization-protocol-name - * p - unused, p=pad(n) - * string8 - authorization-protocol-data - * q - unused, q=pad(d) - * - * pad(X) = (4 - (X mod 4)) mod 4 - * - * Server response: - * - * 1 (0 failed, 2 authenticate, 1 success) - * ... - * - */ - - /* Later on we will simply forward the first 6 header bytes to the "real" X11 server */ - - byte[] header = new byte[6]; - - if (remote_is.read(header) != 6) - throw new IOException("Unexpected EOF on X11 startup!"); - - if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first - throw new IOException("Unknown endian format in X11 message!"); - - /* Yes, I came up with this myself - shall I file an application for a patent? =) */ - - int idxMSB = (header[0] == 0x42) ? 0 : 1; - - /* Read authorization data header */ - - byte[] auth_buff = new byte[6]; - - if (remote_is.read(auth_buff) != 6) - throw new IOException("Unexpected EOF on X11 startup!"); - - int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff); - int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff); - - if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256)) - throw new IOException("Buggy X11 authorization data"); - - int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4); - int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4); - - byte[] authProtocolName = new byte[authProtocolNameLength]; - byte[] authProtocolData = new byte[authProtocolDataLength]; - - byte[] paddingBuffer = new byte[4]; - - if (remote_is.read(authProtocolName) != authProtocolNameLength) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolName)"); - - if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolNamePadding)"); - - if (remote_is.read(authProtocolData) != authProtocolDataLength) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolData)"); - - if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolDataPadding)"); - - if ("MIT-MAGIC-COOKIE-1".equals(new String(authProtocolName, "ISO-8859-1")) == false) - throw new IOException("Unknown X11 authorization protocol!"); - - if (authProtocolDataLength != 16) - throw new IOException("Wrong data length for X11 authorization data!"); - - StringBuffer tmp = new StringBuffer(32); - for (int i = 0; i < authProtocolData.length; i++) - { - String digit2 = Integer.toHexString(authProtocolData[i] & 0xff); - tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2); - } - String hexEncodedFakeCookie = tmp.toString(); - - /* Order is very important here - it may be that a certain x11 forwarding - * gets disabled right in the moment when we check and register our connection - * */ - - synchronized (c) - { - /* Please read the comment in Channel.java */ - c.hexX11FakeCookie = hexEncodedFakeCookie; - } - - /* Now check our fake cookie directory to see if we produced this cookie */ - - X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie); - - if (sd == null) - throw new IOException("Invalid X11 cookie received."); - - /* If the session which corresponds to this cookie is closed then we will - * detect this: the session's close code will close all channels - * with the session's assigned x11 fake cookie. - */ - - s = new Socket(sd.hostname, sd.port); - - OutputStream x11_os = s.getOutputStream(); - InputStream x11_is = s.getInputStream(); - - /* Now we are sending the startup packet to the real X11 server */ - - x11_os.write(header); - - if (sd.x11_magic_cookie == null) - { - byte[] emptyAuthData = new byte[6]; - /* empty auth data, hopefully you are connecting to localhost =) */ - x11_os.write(emptyAuthData); - } - else - { - if (sd.x11_magic_cookie.length != 16) - throw new IOException("The real X11 cookie has an invalid length!"); - - /* send X11 cookie specified by client */ - x11_os.write(auth_buff); - x11_os.write(authProtocolName); /* re-use */ - x11_os.write(paddingBuffer, 0, authProtocolNamePadding); - x11_os.write(sd.x11_magic_cookie); - x11_os.write(paddingBuffer, 0, authProtocolDataPadding); - } - - x11_os.flush(); - - /* Start forwarding traffic */ - - StreamForwarder r2l = new StreamForwarder(c, null, s, remote_is, x11_os, "RemoteToX11"); - StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote"); - - /* No need to start two threads, one can be executed in the current thread */ - - r2l.setDaemon(true); - r2l.start(); - l2r.run(); - - while (r2l.isAlive()) - { - try - { - r2l.join(); - } - catch (InterruptedException e) - { - } - } - - /* If the channel is already closed, then this is a no-op */ - - c.cm.closeChannel(c, "EOF on both X11 streams reached.", true); - s.close(); - } - catch (IOException e) - { - log.log(50, "IOException in X11 proxy code: " + e.getMessage()); - - try - { - c.cm.closeChannel(c, "IOException in X11 proxy code (" + e.getMessage() + ")", true); - } - catch (IOException e1) - { - } - try - { - if (s != null) - s.close(); - } - catch (IOException e1) - { - } - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/StreamForwarder.java b/lib/src/main/java/com/trilead/ssh2/channel/StreamForwarder.java deleted file mode 100644 index e1afee8..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/StreamForwarder.java +++ /dev/null @@ -1,113 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -/** - * A StreamForwarder forwards data between two given streams. - * If two StreamForwarder threads are used (one for each direction) - * then one can be configured to shutdown the underlying channel/socket - * if both threads have finished forwarding (EOF). - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: StreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class StreamForwarder extends Thread -{ - final OutputStream os; - final InputStream is; - final byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE]; - final Channel c; - final StreamForwarder sibling; - final Socket s; - final String mode; - - StreamForwarder(Channel c, StreamForwarder sibling, Socket s, InputStream is, OutputStream os, String mode) - throws IOException - { - this.is = is; - this.os = os; - this.mode = mode; - this.c = c; - this.sibling = sibling; - this.s = s; - } - - public void run() - { - try - { - while (true) - { - int len = is.read(buffer); - if (len <= 0) - break; - os.write(buffer, 0, len); - os.flush(); - } - } - catch (IOException ignore) - { - try - { - c.cm.closeChannel(c, "Closed due to exception in StreamForwarder (" + mode + "): " - + ignore.getMessage(), true); - } - catch (IOException e) - { - } - } - finally - { - try - { - os.close(); - } - catch (IOException e1) - { - } - try - { - is.close(); - } - catch (IOException e2) - { - } - - if (sibling != null) - { - while (sibling.isAlive()) - { - try - { - sibling.join(); - } - catch (InterruptedException e) - { - } - } - - try - { - c.cm.closeChannel(c, "StreamForwarder (" + mode + ") is cleaning up the connection", true); - } - catch (IOException e3) - { - } - } - - if (s != null) { - try - { - s.close(); - } - catch (IOException e1) - { - } - } - } - } -} diff --git a/lib/src/main/java/com/trilead/ssh2/channel/X11ServerData.java b/lib/src/main/java/com/trilead/ssh2/channel/X11ServerData.java deleted file mode 100644 index 041f9cb..0000000 --- a/lib/src/main/java/com/trilead/ssh2/channel/X11ServerData.java +++ /dev/null @@ -1,16 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * X11ServerData. Data regarding an x11 forwarding target. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: X11ServerData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - * - */ -public class X11ServerData -{ - public String hostname; - public int port; - public byte[] x11_magic_cookie; /* not the remote (fake) one, the local (real) one */ -} -- cgit v1.2.3