You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2008/12/04 19:59:36 UTC

svn commit: r723396 [8/12] - in /mina/sshd/trunk: ./ src/ src/docs/ src/main/ src/main/filtered-resources/ src/main/filtered-resources/org/ src/main/filtered-resources/org/apache/ src/main/filtered-resources/org/apache/sshd/ src/main/java/ src/main/jav...

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/client/channel/ChannelShell.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/client/channel/ChannelShell.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/client/channel/ChannelShell.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/client/channel/ChannelShell.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.client.channel;
+
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.util.Buffer;
+
+public class ChannelShell extends ChannelSession {
+
+    @Override
+    public void open() throws Exception {
+        super.open();
+        startShell();
+    }
+
+    protected void startShell() throws Exception {
+        Buffer buffer;
+
+        log.info("Send SSH_MSG_CHANNEL_REQUEST pty-req");
+        buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_REQUEST);
+        buffer.putInt(recipient);
+        buffer.putString("pty-req");
+        buffer.putBoolean(false);
+        buffer.putString(System.getProperty("TERM", "dummy"));
+        buffer.putInt(80);
+        buffer.putInt(24);
+        buffer.putInt(640);
+        buffer.putInt(480);
+        Buffer modes = new Buffer();
+        modes.putByte((byte) 50); // ISIG
+        modes.putInt(1);
+        modes.putByte((byte) 51); // ICANON
+        modes.putInt(1);
+        modes.putByte((byte) 53); // ECHO
+        modes.putInt(1);
+        modes.putByte((byte) 54); // ECHOE
+        modes.putInt(1);
+        modes.putByte((byte) 55); // ECHOK
+        modes.putInt(1);
+        modes.putByte((byte) 56); // ECHONL
+        modes.putInt(0);
+        modes.putByte((byte) 57); // NOFLSH
+        modes.putInt(0);
+        modes.putByte((byte) 0);
+        buffer.putBytes(modes.getCompactData());
+        session.writePacket(buffer);
+
+//        log.info("Send SSH_MSG_CHANNEL_REQUEST env");
+//        buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_REQUEST);
+//        buffer.putInt(recipient);
+//        buffer.putString("env");
+//        session.writePacket(buffer);
+
+        log.info("Send SSH_MSG_CHANNEL_REQUEST shell");
+        buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_REQUEST);
+        buffer.putInt(recipient);
+        buffer.putString("shell");
+        buffer.putBoolean(false);
+        session.writePacket(buffer);
+
+    }
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/AbstractDHGClient.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.client.kex;
+
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.apache.sshd.client.session.ClientSessionImpl;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.Digest;
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.digest.SHA1;
+import org.apache.sshd.common.kex.DH;
+import org.apache.sshd.common.util.Buffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractDHGClient implements KeyExchange {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private ClientSessionImpl session;
+    private byte[] V_S;
+    private byte[] V_C;
+    private byte[] I_S;
+    private byte[] I_C;
+    private Digest sha;
+    private DH dh;
+    private byte[] e;
+    private byte[] f;
+    private byte[] K;
+    private byte[] H;
+
+    public void init(AbstractSession s, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception {
+        if (!(s instanceof ClientSessionImpl)) {
+            throw new IllegalStateException("Using a client side KeyExchange on a server");
+        }
+        session = (ClientSessionImpl) s;
+        this.V_S = V_S;
+        this.V_C = V_C;
+        this.I_S = I_S;
+        this.I_C = I_C;
+        sha = new SHA1();
+        sha.init();
+        dh = new DH();
+        initDH(dh);
+        e = dh.getE();
+
+        log.info("Send SSH_MSG_KEXDH_INIT");
+        Buffer buffer = s.createBuffer(SshConstants.Message.SSH_MSG_KEXDH_INIT);
+        buffer.putMPInt(e);
+        session.writePacket(buffer);
+    }
+
+    protected abstract void initDH(DH dh);
+
+    public boolean next(Buffer buffer) throws Exception {
+        SshConstants.Message cmd = buffer.getCommand();
+        if (cmd != SshConstants.Message.SSH_MSG_KEXDH_REPLY_KEX_DH_GEX_GROUP) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                                   "Protocol error: expected packet " + SshConstants.Message.SSH_MSG_KEXDH_REPLY_KEX_DH_GEX_GROUP + ", got " + cmd);
+        }
+
+        log.info("Received SSH_MSG_KEXDH_REPLY");
+        
+        byte[] K_S = buffer.getBytes();
+        byte[] f = buffer.getMPIntAsBytes();
+        byte[] sig = buffer.getBytes();
+        dh.setF(f);
+        K = dh.getK();
+
+        buffer = new Buffer(K_S);
+        PublicKey key = buffer.getPublicKey();
+        String keyAlg = (key instanceof RSAPublicKey) ? KeyPairProvider.SSH_RSA : KeyPairProvider.SSH_DSS;
+
+        buffer = new Buffer();
+        buffer.putString(V_C);
+        buffer.putString(V_S);
+        buffer.putString(I_C);
+        buffer.putString(I_S);
+        buffer.putString(K_S);
+        buffer.putMPInt(e);
+        buffer.putMPInt(f);
+        buffer.putMPInt(K);
+        sha.update(buffer.array(), 0, buffer.available());
+        H = sha.digest();
+
+        Signature verif = NamedFactory.Utils.create(session.getFactoryManager().getSignatureFactories(), keyAlg);
+        verif.init(key, null);
+        verif.update(H, 0, H.length);
+        if (!verif.verify(sig)) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
+                                   "KeyExchange signature verification failed");
+        }
+        return true;
+    }
+
+    public Digest getHash() {
+        return sha;
+    }
+
+    public byte[] getH() {
+        return H;
+    }
+
+    public byte[] getK() {
+        return K;
+    }
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG1.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG1.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG1.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG1.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.client.kex;
+
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.kex.DH;
+import org.apache.sshd.common.kex.DHGroupData;
+
+public class DHG1 extends AbstractDHGClient {
+
+    public static class Factory implements NamedFactory<KeyExchange> {
+
+        public String getName() {
+            return "diffie-hellman-group1-sha1";
+        }
+
+        public KeyExchange create() {
+            return new DHG1();
+        }
+
+    }
+
+    protected void initDH(DH dh) {
+        dh.setG(DHGroupData.G);
+        dh.setP(DHGroupData.P_1);
+    }
+
+}
\ No newline at end of file

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG14.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG14.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG14.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/client/kex/DHG14.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.client.kex;
+
+import org.apache.sshd.common.KeyExchange;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.kex.DH;
+import org.apache.sshd.common.kex.DHGroupData;
+
+/**
+ * DHG14 does not work with the default JCE implementation provided by Sun
+ * because it does not support 2048 bits encryption.
+ * It requires BouncyCastle to be used.
+ *
+ */
+public class DHG14 extends AbstractDHGClient {
+
+    public static class Factory implements NamedFactory<KeyExchange> {
+
+        public String getName() {
+            return "diffie-hellman-group14-sha1";
+        }
+
+        public KeyExchange create() {
+            return new DHG14();
+        }
+
+    }
+
+    protected void initDH(DH dh) {
+        dh.setG(DHGroupData.G);
+        dh.setP(DHGroupData.P_14);
+    }
+
+}
\ No newline at end of file

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.client.session;
+
+import java.security.PublicKey;
+import java.io.IOException;
+
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.auth.UserAuthPassword;
+import org.apache.sshd.client.channel.ChannelShell;
+import org.apache.sshd.client.channel.AbstractClientChannel;
+import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.mina.common.IoSession;
+
+public class ClientSessionImpl extends AbstractSession implements ClientSession {
+
+    public static final String SESSION = ClientSessionImpl.class.getName();
+
+    public enum State {
+        ReceiveKexInit, Kex, ReceiveNewKeys, AuthRequestSent, WaitForAuth, UserAuth, Running, Unknown
+    }
+
+    private State state = State.ReceiveKexInit;
+    private UserAuth userAuth;
+
+    public ClientSessionImpl(SshClient client, IoSession session) throws Exception {
+        super(client, session);
+        log.info("Session created...");
+        sendClientIdentification();
+        sendKexInit();
+    }
+
+    public void authPassword(String username, String password) throws IOException {
+        if (closed) {
+            throw new IllegalStateException("Session is closed");
+        }
+        if (authed) {
+            throw new IllegalStateException("User authentication has already been performed");
+        }
+        if (userAuth != null) {
+            throw new IllegalStateException("A user authentication request is already pending");
+        }
+        waitFor(CLOSED | WAIT_AUTH, 0);
+        userAuth = new UserAuthPassword(this, username, password);
+        setState(ClientSessionImpl.State.UserAuth);
+    }
+
+    public void authPublicKey(String username, PublicKey key) throws IOException {
+        if (closed) {
+            throw new IllegalStateException("Session is closed");
+        }
+        if (authed) {
+            throw new IllegalStateException("User authentication has already been performed");
+        }
+        if (userAuth != null) {
+            throw new IllegalStateException("A user authentication request is already pending");
+        }
+        waitFor(CLOSED | WAIT_AUTH, 0);
+        // TODO: implement public key authentication method
+        throw new UnsupportedOperationException("Not supported yet");
+    }
+
+    public ClientChannel createChannel(String type) throws Exception {
+        // TODO: use NamedFactory to create channel
+        AbstractClientChannel channel;
+        if ("shell".equals(type)) {
+            channel = new ChannelShell();
+        } else {
+            throw new IllegalArgumentException("Unsupported channel type " + type);
+        }
+        int id = ++nextChannelId;
+        channel.init(this, id);
+        channels.put(id, channel);
+        return channel;
+    }
+
+    protected void handleMessage(Buffer buffer) throws Exception {
+        SshConstants.Message cmd = buffer.getCommand();
+        log.debug("Received packet {}", cmd);
+        switch (cmd) {
+            case SSH_MSG_DISCONNECT: {
+                int code = buffer.getInt();
+                String msg = buffer.getString();
+                log.info("Received SSH_MSG_DISCONNECT (reason={}, msg={})", code, msg);
+                close();
+                break;
+            }
+            case SSH_MSG_UNIMPLEMENTED: {
+                int code = buffer.getInt();
+                log.info("Received SSH_MSG_UNIMPLEMENTED #{}", code);
+                break;
+            }
+            case SSH_MSG_DEBUG: {
+                boolean display = buffer.getBoolean();
+                String msg = buffer.getString();
+                log.info("Received SSH_MSG_DEBUG '{}'", msg);
+                break;
+            }
+            case SSH_MSG_IGNORE:
+                log.info("Received SSH_MSG_IGNORE");
+                break;
+            default:
+                switch (state) {
+                    case ReceiveKexInit:
+                        if (cmd != SshConstants.Message.SSH_MSG_KEXINIT) {
+                            log.error("Ignoring command " + cmd + " while waiting for " + SshConstants.Message.SSH_MSG_KEXINIT);
+                            break;
+                        }
+                        log.info("Received SSH_MSG_KEXINIT");
+                        receiveKexInit(buffer);
+                        negociate();
+                        kex = NamedFactory.Utils.create(factoryManager.getKeyExchangeFactories(), negociated[SshConstants.PROPOSAL_KEX_ALGS]);
+                        kex.init(this, serverVersion.getBytes(), clientVersion.getBytes(), I_S, I_C);
+                        setState(State.Kex);
+                        break;
+                    case Kex:
+                        buffer.rpos(buffer.rpos() - 1);
+                        if (kex.next(buffer)) {
+                            checkHost();
+                            sendNewKeys();
+                            setState(State.ReceiveNewKeys);
+                        }
+                        break;
+                    case ReceiveNewKeys:
+                        if (cmd != SshConstants.Message.SSH_MSG_NEWKEYS) {
+                            disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Protocol error: expected packet SSH_MSG_NEWKEYS, got " + cmd);
+                            return;
+                        }
+                        log.info("Received SSH_MSG_NEWKEYS");
+                        receiveNewKeys(false);
+                        sendAuthRequest();
+                        setState(State.AuthRequestSent);
+                        break;
+                    case AuthRequestSent:
+                        if (cmd != SshConstants.Message.SSH_MSG_SERVICE_ACCEPT) {
+                            disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Protocol error: expected packet SSH_MSG_SERVICE_ACCEPT, got " + cmd);
+                            return;
+                        }
+                        setState(State.WaitForAuth);
+                        break;
+                    case WaitForAuth:
+                        // We're waiting for the client to send an authentication request
+                        // TODO: handle unexpected incoming packets
+                        break;
+                    case UserAuth:
+                        if (userAuth == null) {
+                            throw new IllegalStateException("State is userAuth, but no user auth pending!!!");
+                        }
+                        buffer.rpos(buffer.rpos() - 1);
+                        switch (userAuth.next(buffer)) {
+                             case Success:
+                                 authed = true;
+                                 setState(State.Running);
+                                 break;
+                             case Failure:
+                                 userAuth = null;
+                                 setState(State.WaitForAuth);
+                                 break;
+                             case Continued:
+                                 break;
+                        }
+                        break;
+                    case Running:
+                        switch (cmd) {
+                            case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
+                                channelOpenConfirmation(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_OPEN_FAILURE:
+                                channelOpenFailure(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_REQUEST:
+                                channelRequest(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_DATA:
+                                channelData(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_EXTENDED_DATA:
+                                channelExtendedData(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_FAILURE:
+                                channelFailure(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_WINDOW_ADJUST:
+                                channelWindowAdjust(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_EOF:
+                                channelEof(buffer);
+                                break;
+                            case SSH_MSG_CHANNEL_CLOSE:
+                                channelClose(buffer);
+                                break;
+                            // TODO: handle other requests
+                        }
+                        break;
+                }
+        }
+    }
+
+    public int waitFor(int mask, long timeout) {
+        long t = 0;
+        synchronized (lock) {
+            for (;;) {
+                int cond = 0;
+                if (closed) {
+                    cond |= CLOSED;
+                }
+                if (authed) {
+                    cond |= AUTHED;
+                }
+                if (state == State.WaitForAuth) {
+                    cond |= WAIT_AUTH;
+                }
+                if ((cond & mask) != 0) {
+                    return cond;
+                }
+                if (timeout > 0) {
+                    if (t == 0) {
+                        t = System.currentTimeMillis() + timeout;
+                    } else {
+                        timeout = t - System.currentTimeMillis();
+                        if (timeout <= 0) {
+                            cond |= TIMEOUT;
+                            return cond;
+                        }
+                    }
+                }
+                try {
+                    if (timeout > 0) {
+                        lock.wait(timeout);
+                    } else {
+                        lock.wait();
+                    }
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    public void setState(State newState) {
+        synchronized (lock) {
+            this.state = newState;
+            lock.notifyAll();
+        }
+    }
+
+    protected boolean readIdentification(Buffer buffer) throws IOException {
+        serverVersion = doReadIdentification(buffer);
+        if (serverVersion == null) {
+            return false;
+        }
+        log.info("Server version string: {}", serverVersion);
+        if (!serverVersion.startsWith("SSH-2.0-")) {
+            throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
+                                   "Unsupported protocol version: " + serverVersion);
+        }
+        return true;
+    }
+
+    private void sendClientIdentification() {
+        clientVersion = "SSH-2.0-" + getFactoryManager().getVersion();
+        sendIdentification(clientVersion);
+    }
+
+    private void sendKexInit() throws Exception {
+        clientProposal = createProposal(KeyPairProvider.SSH_RSA + "," + KeyPairProvider.SSH_DSS);
+        I_C = sendKexInit(clientProposal);
+    }
+
+    private void receiveKexInit(Buffer buffer) throws Exception {
+        serverProposal = new String[SshConstants.PROPOSAL_MAX];
+        I_S = receiveKexInit(buffer, serverProposal);
+    }
+
+    private void checkHost() throws Exception {
+        // TODO: check host fingerprint
+    }
+
+    private void sendAuthRequest() throws Exception {
+        log.info("Send SSH_MSG_SERVICE_REQUEST for ssh-userauth");
+        Buffer buffer = createBuffer(SshConstants.Message.SSH_MSG_SERVICE_REQUEST);
+        buffer.putString("ssh-userauth");
+        writePacket(buffer);
+    }
+
+    private void channelOpenConfirmation(Buffer buffer) throws IOException {
+        AbstractClientChannel channel = (AbstractClientChannel) getChannel(buffer);
+        log.info("Received SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel {}", channel.getId());
+        int recipient = buffer.getInt();
+        int rwsize = buffer.getInt();
+        int rmpsize = buffer.getInt();
+        channel.internalOpenSuccess(recipient, rwsize, rmpsize);
+    }
+
+    private void channelOpenFailure(Buffer buffer) throws IOException {
+        AbstractClientChannel channel = (AbstractClientChannel) getChannel(buffer);
+        log.info("Received SSH_MSG_CHANNEL_OPEN_FAILURE on channel {}", channel.getId());
+        channels.remove(channel.getId());
+        channel.internalOpenFailure(buffer);
+    }
+
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.util.List;
+import java.util.Properties;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.InputStream;
+
+public abstract class AbstractFactoryManager implements FactoryManager {
+
+    private Map<String,String> properties = new HashMap<String,String>();
+    private List<NamedFactory<KeyExchange>> keyExchangeFactories;
+    private List<NamedFactory<Cipher>> cipherFactories;
+    private List<NamedFactory<Compression>> compressionFactories;
+    private List<NamedFactory<Mac>> macFactories;
+    private List<NamedFactory<Signature>> signatureFactories;
+    private NamedFactory<Random> randomFactory;
+    private KeyPairProvider keyPairProvider;
+    private String version;
+
+    protected AbstractFactoryManager() {
+        loadVersion();
+    }
+
+    public List<NamedFactory<KeyExchange>> getKeyExchangeFactories() {
+        return keyExchangeFactories;
+    }
+
+    public void setKeyExchangeFactories(List<NamedFactory<KeyExchange>> keyExchangeFactories) {
+        this.keyExchangeFactories = keyExchangeFactories;
+    }
+
+    public List<NamedFactory<Cipher>> getCipherFactories() {
+        return cipherFactories;
+    }
+
+    public void setCipherFactories(List<NamedFactory<Cipher>> cipherFactories) {
+        this.cipherFactories = cipherFactories;
+    }
+
+    public List<NamedFactory<Compression>> getCompressionFactories() {
+        return compressionFactories;
+    }
+
+    public void setCompressionFactories(List<NamedFactory<Compression>> compressionFactories) {
+        this.compressionFactories = compressionFactories;
+    }
+
+    public List<NamedFactory<Mac>> getMacFactories() {
+        return macFactories;
+    }
+
+    public void setMacFactories(List<NamedFactory<Mac>> macFactories) {
+        this.macFactories = macFactories;
+    }
+
+    public List<NamedFactory<Signature>> getSignatureFactories() {
+        return signatureFactories;
+    }
+
+    public void setSignatureFactories(List<NamedFactory<Signature>> signatureFactories) {
+        this.signatureFactories = signatureFactories;
+    }
+
+    public NamedFactory<Random> getRandomFactory() {
+        return randomFactory;
+    }
+
+    public void setRandomFactory(NamedFactory<Random> randomFactory) {
+        this.randomFactory = randomFactory;
+    }
+
+    public KeyPairProvider getKeyPairProvider() {
+        return keyPairProvider;
+    }
+
+    public void setKeyPairProvider(KeyPairProvider keyPairProvider) {
+        this.keyPairProvider = keyPairProvider;
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(Map<String, String> properties) {
+        this.properties = properties;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    protected void loadVersion() {
+        this.version = "SSHD-UNKNOWN";
+        try {
+            InputStream input = getClass().getResourceAsStream("sshd-version.properties");
+            try {
+                Properties props = new Properties();
+                props.load(input);
+                this.version = props.getProperty("version").toUpperCase();
+            } finally {
+                input.close();
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+    }
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractSessionIoHandler.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractSessionIoHandler.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractSessionIoHandler.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/AbstractSessionIoHandler.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.sshd.common.session.AbstractSession;
+
+public abstract class AbstractSessionIoHandler extends IoHandlerAdapter {
+
+    protected abstract AbstractSession createSession(IoSession ioSession) throws Exception;
+
+    @Override
+    public void sessionCreated(IoSession ioSession) throws Exception {
+        AbstractSession session = createSession(ioSession);
+        AbstractSession.attachSession(ioSession, session);
+    }
+
+    @Override
+    public void sessionClosed(IoSession ioSession) throws Exception {
+        AbstractSession.getSession(ioSession).close();
+    }
+
+    @Override
+    public void exceptionCaught(IoSession ioSession, Throwable cause) throws Exception {
+        AbstractSession session = AbstractSession.getSession(ioSession, true);
+        if (session != null) {
+            session.exceptionCaught(cause);
+        } else {
+            throw new IllegalStateException("No session available", cause);
+        }
+    }
+
+    @Override
+    public void messageReceived(IoSession ioSession, Object message) throws Exception {
+        AbstractSession.getSession(ioSession).messageReceived((ByteBuffer) message);
+    }
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Channel.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Channel.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Channel.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Channel.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import org.apache.sshd.common.util.Buffer;
+
+public interface Channel extends Closeable {
+
+    int getId();
+
+    void handleWindowAdjust(Buffer buffer) throws IOException;
+
+    void handleRequest(Buffer buffer) throws IOException;
+
+    void handleData(Buffer buffer) throws IOException;
+
+    void handleExtendedData(Buffer buffer) throws IOException;
+
+    void handleEof() throws IOException;
+
+    void handleFailure() throws IOException;
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Cipher.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Cipher.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Cipher.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Cipher.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+public interface Cipher  {
+
+    enum Mode {
+        Encrypt, Decrypt
+    }
+
+    /**
+     * Retrieves the size of the initialization vector
+     *
+     * @return
+     */
+    int getIVSize();
+
+    /**
+     * Retrieves the block size for this cipher
+     *
+     * @return
+     */
+    int getBlockSize();
+
+    /**
+     * Initialize the cipher for encryption or decryption with
+     * the given private key and initialization vector
+     *
+     * @param mode
+     * @param key
+     * @param iv
+     * @throws Exception
+     */
+    void init(Mode mode, byte[] key, byte[] iv) throws Exception;
+
+    /**
+     * Performs in-place encryption or decryption on the given data.
+     * 
+     * @param input
+     * @param inputOffset
+     * @param inputLen
+     * @throws Exception
+     */
+    void update(byte[] input, int inputOffset, int inputLen) throws Exception;
+
+}
\ No newline at end of file

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Compression.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Compression.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Compression.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Compression.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.io.IOException;
+
+import org.apache.sshd.common.util.Buffer;
+
+public interface Compression {
+
+    enum Type {
+        Inflater,
+        Deflater
+    }
+
+    boolean isDelayed();
+
+    void init(Type type, int level);
+
+    void compress(Buffer buffer) throws IOException;
+
+    void uncompress(Buffer from, Buffer to) throws IOException;
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Digest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Digest.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Digest.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Digest.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+public interface Digest {
+
+    void init() throws Exception;
+
+    int getBlockSize();
+
+    void update(byte[] foo, int start, int len) throws Exception;
+
+    byte[] digest() throws Exception;
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/FactoryManager.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/FactoryManager.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/FactoryManager.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/FactoryManager.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.util.List;
+import java.util.Map;
+
+public interface FactoryManager {
+
+    public static final String WINDOW_SIZE = "window-size";
+    public static final String MAX_PACKET_SIZE = "packet-size";
+    public static final String MAX_AUTH_REQUESTS = "max-auth-requests";
+    public static final String AUTH_TIMEOUT = "auth-timeout";
+
+    Map<String,String> getProperties();
+
+    String getVersion();
+
+    List<NamedFactory<KeyExchange>> getKeyExchangeFactories();
+
+    List<NamedFactory<Cipher>> getCipherFactories();
+
+    List<NamedFactory<Compression>> getCompressionFactories();
+
+    List<NamedFactory<Mac>> getMacFactories();
+
+    List<NamedFactory<Signature>> getSignatureFactories();
+
+    KeyPairProvider getKeyPairProvider();
+
+    NamedFactory<Random> getRandomFactory();
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyExchange.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyExchange.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyExchange.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyExchange.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.session.AbstractSession;
+
+/**
+ * Key exchange algorithm.
+ */
+public interface KeyExchange {
+
+    /**
+     * Initialize the key exchange algorithm.
+     *
+     * @param session the session using this algorithm
+     * @param V_S the server identification string
+     * @param V_C the client identification string
+     * @param I_S the server key init packet
+     * @param I_C the client key init packet
+     * @throws Exception if an error occurs
+     */
+    void init(AbstractSession session, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception;
+
+    /**
+     * Process the next packet
+     *
+     * @param buffer the packet
+     * @return a boolean indicating if the processing is complete or if more packets are to be received
+     * @throws Exception if an error occurs
+     */
+    boolean next(Buffer buffer) throws Exception;
+
+    /**
+     * The message digest used by this key exchange algorithm.
+     *
+     * @return the message digest
+     */
+    Digest getHash();
+
+    /**
+     * Retrieves the computed H parameter
+     *
+     * @return
+     */
+    byte[] getH();
+
+    /**
+     * Retrieves the computed K parameter
+     *
+     * @return
+     */
+    byte[] getK();
+
+}
\ No newline at end of file

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyPairProvider.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyPairProvider.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyPairProvider.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/KeyPairProvider.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.security.KeyPair;
+
+/**
+ * Provider for key pairs.  This provider is used on the server side to provide
+ * the host key, or on the client side to provide the user key.
+ */
+public interface KeyPairProvider {
+
+    /**
+     * SSH identifier for RSA keys
+     */
+    String SSH_RSA = "ssh-rsa";
+
+    /**
+     * SSH identifier for DSA keys
+     */
+    String SSH_DSS = "ssh-dss";
+
+    /**
+     * Load a key of the specified type which can be "ssh-rsa" or "ssh-dss".
+     * If there is no key of this type, return <code>null</code>
+     *
+     * @param type the type of key to load
+     * @return a valid key pair or <code>null</code>
+     */
+    KeyPair loadKey(String type);
+
+    /**
+     * Return a comma separated list of the key types available
+     *
+     * @return the list of key availables
+     */
+    String getKeyTypes();
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Mac.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Mac.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Mac.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Mac.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+/**
+ * Message Authentication Code for use in SSH.
+ * It usually wraps a javax.crypto.Mac class.
+ */
+public interface Mac {
+
+    int getBlockSize();
+
+    void init(byte[] key) throws Exception;
+
+    void update(byte[] foo, int start, int len);
+
+    void update(int foo);
+
+    void doFinal(byte[] buf, int offset) throws Exception;
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/NamedFactory.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/NamedFactory.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/NamedFactory.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/NamedFactory.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.util.List;
+
+/**
+ * A named factory is a factory identified by a name.
+ * Such names are used mainly in the algorithm negociation at the beginning of the SSH connection.
+ *
+ * @param <T>
+ */
+public interface NamedFactory<T> {
+
+    /**
+     * Name of this factory
+     * @return
+     */
+    String getName();
+
+    /**
+     * Create a new instance
+     * @return
+     */
+    T create();
+
+    /**
+     * Utility class to help using NamedFactories
+     */
+    public static class Utils {
+
+        /**
+         * Create an instance of the spcecified name by looking up the needed factory
+         * in the list.
+         * 
+         * @param factories list of available factories
+         * @param name the factory name to use
+         * @param <T> type of object to create
+         * @return a newly created object or <code>null</code> if the factory is not in the list
+         */
+        public static <T> T create(List<NamedFactory<T>> factories, String name) {
+            for (NamedFactory<T> f : factories) {
+                if (f.getName().equals(name)) {
+                    return f.create();
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Get a comma separated list of the factory names from the given list.
+         *
+         * @param factories list of available factories
+         * @param <T> type of object to create
+         * @return a comma separated list of factory names
+         */
+        public static <T> String getNames(List<NamedFactory<T>> factories) {
+            StringBuffer sb = new StringBuffer();
+            for (NamedFactory f : factories) {
+                if (sb.length() > 0) {
+                    sb.append(",");
+                }
+                sb.append(f.getName());
+            }
+            return sb.toString();
+        }
+
+        /**
+         * Remove the factory identified by the name from the list.
+         *
+         * @param factories list of factories
+         * @param name the name of the factory to remove
+         * @param <T> type of object to create
+         * @return the factory removed from the list or <code>null</code> if not in the list
+         */
+        public static <T> NamedFactory<T> remove(List<NamedFactory<T>> factories, String name) {
+            for (NamedFactory<T> f : factories) {
+                if (f.getName().equals(name)) {
+                    factories.remove(f);
+                    return f;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Retrieve the factory identified by its name from the list.
+         *
+         * @param factories list of available factories
+         * @param name the name of the factory to retrieve
+         * @param <T> type of object create by the factories
+         * @return a factory or <code>null</code> if not found in the list
+         */
+        public static <T> NamedFactory<T> get(List<NamedFactory<T>> factories, String name) {
+            for (NamedFactory<T> f : factories) {
+                if (f.getName().equals(name)) {
+                    return f;
+                }
+            }
+            return null;
+        }
+
+    }
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Random.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Random.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Random.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Random.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+/**
+ * A pseudo random number generator
+ */
+public interface Random {
+
+    /**
+     * Fill part of bytes with random values.
+     *
+     * @param bytes byte array to be filled.
+     * @param start index to start filling at.
+     * @param len length of segment to fill.
+     */
+    void fill(byte[] bytes, int start, int len);
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/Signature.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/Signature.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/Signature.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/Signature.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * Signature interface for SSH used to sign or verify packets
+ * Usually wraps a javax.crypto.Signature object
+ */
+public interface Signature {
+
+    void init(PublicKey pubkey, PrivateKey prvkey) throws Exception;
+
+    void update(byte[] H, int off, int len) throws Exception;
+
+    boolean verify(byte[] sig) throws Exception;
+
+    byte[] sign() throws Exception;
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshConstants.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshConstants.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshConstants.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshConstants.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+public interface SshConstants {
+
+    public enum Message {
+
+        SSH_MSG_DISCONNECT(1),
+        SSH_MSG_IGNORE(2),
+        SSH_MSG_UNIMPLEMENTED(3),
+        SSH_MSG_DEBUG(4),
+        SSH_MSG_SERVICE_REQUEST(5),
+        SSH_MSG_SERVICE_ACCEPT(6),
+        SSH_MSG_KEXINIT(20),
+        SSH_MSG_NEWKEYS(21),
+
+        SSH_MSG_KEXDH_INIT(30),
+
+        // KEXDH_REPLY and KEX_DH_GEX_GROUP have the same command ID
+        SSH_MSG_KEXDH_REPLY_KEX_DH_GEX_GROUP(31),
+
+        SSH_MSG_KEX_DH_GEX_INIT(32),
+        SSH_MSG_KEX_DH_GEX_REPLY(33),
+        SSH_MSG_KEX_DH_GEX_REQUEST(34),
+
+        SSH_MSG_USERAUTH_REQUEST(50),
+        SSH_MSG_USERAUTH_FAILURE(51),
+        SSH_MSG_USERAUTH_SUCCESS(52),
+        SSH_MSG_USERAUTH_BANNER(53),
+        SSH_MSG_USERAUTH_INFO_REQUEST(60),
+        SSH_MSG_USERAUTH_INFO_RESPONSE(61),
+        SSH_MSG_USERAUTH_PK_OK(60),
+
+        SSH_MSG_GLOBAL_REQUEST(80),
+        SSH_MSG_REQUEST_SUCCESS(81),
+        SSH_MSG_REQUEST_FAILURE(82),
+        
+        SSH_MSG_CHANNEL_OPEN(90),
+        SSH_MSG_CHANNEL_OPEN_CONFIRMATION(91),
+        SSH_MSG_CHANNEL_OPEN_FAILURE(92),
+        SSH_MSG_CHANNEL_WINDOW_ADJUST(93),
+        SSH_MSG_CHANNEL_DATA(94),
+        SSH_MSG_CHANNEL_EXTENDED_DATA(95),
+        SSH_MSG_CHANNEL_EOF(96),
+        SSH_MSG_CHANNEL_CLOSE(97),
+        SSH_MSG_CHANNEL_REQUEST(98),
+        SSH_MSG_CHANNEL_SUCCESS(99),
+        SSH_MSG_CHANNEL_FAILURE(100);
+
+        private byte b;
+        private Message(int b) {
+            this.b = (byte) b;
+        }
+
+        public byte toByte() {
+            return b;
+        }
+
+        static Message[] commands;
+        static {
+            commands = new Message[256];
+            for (Message c : Message.values()) {
+                if (commands[c.toByte()] == null) {
+                    commands[c.toByte()] = c;
+                }
+            }
+        }
+        public static Message fromByte(byte b) {
+            return commands[b];
+        }
+    }
+
+    static final int PROPOSAL_KEX_ALGS = 0;
+    static final int PROPOSAL_SERVER_HOST_KEY_ALGS = 1;
+    static final int PROPOSAL_ENC_ALGS_CTOS = 2;
+    static final int PROPOSAL_ENC_ALGS_STOC = 3;
+    static final int PROPOSAL_MAC_ALGS_CTOS = 4;
+    static final int PROPOSAL_MAC_ALGS_STOC = 5;
+    static final int PROPOSAL_COMP_ALGS_CTOS = 6;
+    static final int PROPOSAL_COMP_ALGS_STOC = 7;
+    static final int PROPOSAL_LANG_CTOS = 8;
+    static final int PROPOSAL_LANG_STOC = 9;
+    static final int PROPOSAL_MAX = 10;
+
+    static final int SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT =     1;
+    static final int SSH2_DISCONNECT_PROTOCOL_ERROR =                  2;
+    static final int SSH2_DISCONNECT_KEY_EXCHANGE_FAILED =             3;
+    static final int SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED =      4;
+    static final int SSH2_DISCONNECT_RESERVED =                        4;
+    static final int SSH2_DISCONNECT_MAC_ERROR =                       5;
+    static final int SSH2_DISCONNECT_COMPRESSION_ERROR =               6;
+    static final int SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE =           7;
+    static final int SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED =  8;
+    static final int SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE =         9;
+    static final int SSH2_DISCONNECT_CONNECTION_LOST =                10;
+    static final int SSH2_DISCONNECT_BY_APPLICATION =                 11;
+    static final int SSH2_DISCONNECT_TOO_MANY_CONNECTIONS =           12;
+    static final int SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER =         13;
+    static final int SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14;
+    static final int SSH2_DISCONNECT_ILLEGAL_USER_NAME =              15;
+
+    static final int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED=     1;
+    static final int SSH_OPEN_CONNECT_FAILED=                  2;
+    static final int SSH_OPEN_UNKNOWN_CHANNEL_TYPE=            3;
+    static final int SSH_OPEN_RESOURCE_SHORTAGE=               4;
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshException.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshException.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshException.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/SshException.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common;
+
+import java.io.IOException;
+
+public class SshException extends IOException {
+
+    private final int disconnectCode;
+
+    public SshException() {
+        this(0, null, null);
+    }
+
+    public SshException(String message) {
+        this(0, message, null);
+    }
+
+    public SshException(String message, Throwable cause) {
+        this(0, message, cause);
+    }
+
+    public SshException(Throwable cause) {
+        this(0, null, cause);
+    }
+
+    public SshException(int disconnectCode) {
+        this(disconnectCode, null, null);
+    }
+
+    public SshException(int disconnectCode, String message) {
+        this(disconnectCode, message, null);
+    }
+
+    public SshException(int disconnectCode, Throwable cause) {
+        this(disconnectCode, null, cause);
+    }
+
+    public SshException(int disconnectCode, String message, Throwable cause) {
+        super(message);
+        this.disconnectCode = disconnectCode;
+        if (cause != null) {
+            initCause(cause);
+        }
+    }
+
+    public int getDisconnectCode() {
+        return disconnectCode;
+    }
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common.channel;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.sshd.common.session.AbstractSession;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.Channel;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.util.Buffer;
+import org.apache.sshd.common.util.BufferUtils;
+
+public abstract class AbstractChannel implements Channel {
+
+    public static final int DEFAULT_WINDOW_SIZE = 0x200000;
+    public static final int DEFAULT_PACKET_SIZE = 0x8000;
+
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    protected final Object lock = new Object();
+    protected final Window localWindow = new Window(this, null, getClass().getName().contains(".client."), true);
+    protected final Window remoteWindow = new Window(this, null, getClass().getName().contains(".client."), false);
+    protected AbstractSession session;
+    protected int id;
+    protected int recipient;
+    protected boolean eof;
+    protected boolean closed;
+    protected boolean closing;
+
+    public int getId() {
+        return id;
+    }
+
+    public int getRecipient() {
+        return recipient;
+    }
+
+    public Window getLocalWindow() {
+        return localWindow;
+    }
+
+    public AbstractSession getSession() {
+        return session;
+    }
+
+    public void close() throws IOException {
+        log.info("Received SSH_MSG_CHANNEL_CLOSE on channel {}", id);
+        synchronized (lock) {
+            internalClose();
+            closed = true;
+            lock.notifyAll();
+        }
+    }
+
+    protected void internalClose() throws IOException {
+        synchronized (lock) {
+            if (!closing && !closed) {
+                closing = true;
+                log.info("Send SSH_MSG_CHANNEL_CLOSE on channel {}", id);
+                Buffer buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_CLOSE);
+                buffer.putInt(recipient);
+                session.writePacket(buffer);
+            }
+        }
+    }
+
+    public void handleData(Buffer buffer) throws IOException {
+        int len = buffer.getInt();
+        if (len < 0 || len > 32768) {
+            throw new IllegalStateException("Bad item length: " + len);
+        }
+        log.debug("Received SSH_MSG_CHANNEL_DATA on channel {}", id);
+        if (log.isTraceEnabled()) {
+            log.trace("Received channel data: {}", BufferUtils.printHex(buffer.array(), buffer.rpos(), len));
+        }
+        doWriteData(buffer.array(), buffer.rpos(), len);
+    }
+
+    public void handleExtendedData(Buffer buffer) throws IOException {
+        int ex = buffer.getInt();
+        // Only accept extended data for stderr
+        if (ex != 1) {
+            log.info("Send SSH_MSG_CHANNEL_FAILURE on channel {}", id);
+            buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_FAILURE);
+            buffer.putInt(recipient);
+            session.writePacket(buffer);
+            return;
+        }
+        int len = buffer.getInt();
+        if (len < 0 || len > 32768) {
+            throw new IllegalStateException("Bad item length: " + len);
+        }
+        log.debug("Received SSH_MSG_CHANNEL_EXTENDED_DATA on channel {}", id);
+        if (log.isTraceEnabled()) {
+            log.trace("Received channel extended data: {}", BufferUtils.printHex(buffer.array(), buffer.rpos(), len));
+        }
+        doWriteExtendedData(buffer.array(), buffer.rpos(), len);
+    }
+
+    public void handleEof() throws IOException {
+        log.info("Received SSH_MSG_CHANNEL_EOF on channel {}", id);
+        synchronized (lock) {
+            eof = true;
+            lock.notifyAll();
+        }
+    }
+
+    public void handleWindowAdjust(Buffer buffer) throws IOException {
+        log.info("Received SSH_MSG_CHANNEL_WINDOW_ADJUST on channel {}", id);
+        int window = buffer.getInt();
+        remoteWindow.expand(window);
+    }
+
+    public void handleFailure() throws IOException {
+        log.info("Received SSH_MSG_CHANNEL_FAILURE on channel {}", id);
+        // TODO: do something to report failed requests?
+    }
+
+    protected abstract void doWriteData(byte[] data, int off, int len) throws IOException;
+
+    protected abstract void doWriteExtendedData(byte[] data, int off, int len) throws IOException;
+
+    protected void sendEof() throws IOException {
+        log.info("Send SSH_MSG_CHANNEL_EOF on channel {}", id);
+        Buffer buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_EOF);
+        buffer.putInt(recipient);
+        session.writePacket(buffer);
+    }
+
+    protected void configureWindow() {
+        int window = session.getIntProperty(FactoryManager.WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
+        int packet = session.getIntProperty(FactoryManager.MAX_PACKET_SIZE, DEFAULT_PACKET_SIZE);
+        localWindow.init(window, packet);
+    }
+
+    protected void sendWindowAdjust(int len) throws IOException {
+        log.info("Send SSH_MSG_CHANNEL_WINDOW_ADJUST on channel {}", id);
+        Buffer buffer = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_WINDOW_ADJUST);
+        buffer.putInt(recipient);
+        buffer.putInt(len);
+        session.writePacket(buffer);
+    }
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common.channel;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshException;
+import org.apache.sshd.common.util.Buffer;
+import org.slf4j.Logger;
+
+public class ChannelOutputStream extends OutputStream {
+
+    private final AbstractChannel channel;
+    private final Window remoteWindow;
+    private final Logger log;
+    private final SshConstants.Message cmd;
+    private final byte[] b = new byte[1];
+    private Buffer buffer;
+    private boolean closed;
+    private int bufferLength;
+
+    public ChannelOutputStream(AbstractChannel channel, Window remoteWindow, Logger log, SshConstants.Message cmd) {
+        this.channel = channel;
+        this.remoteWindow = remoteWindow;
+        this.log = log;
+        this.cmd = cmd;
+        newBuffer();
+    }
+
+    public synchronized void write(int w) throws IOException {
+        b[0] = (byte) w;
+        write(b, 0, 1);
+    }
+
+    public synchronized void write(byte[] buf, int s, int l) throws IOException {
+        if (closed) {
+            throw new SshException("Already closed");
+        }
+        while (l > 0) {
+            int _l = Math.min(l, remoteWindow.getPacketSize() - bufferLength);
+            if (_l <= 0) {
+                flush();
+                continue;
+            }
+            buffer.putRawBytes(buf, s, _l);
+            bufferLength += _l;
+            s += _l;
+            l -= _l;
+        }
+    }
+
+    @Override
+    public synchronized void flush() throws IOException {
+        if (closed) {
+            throw new SshException("Already closed");
+        }
+        int pos = buffer.wpos();
+        if (bufferLength <= 0) {
+            // No data to send
+            return;
+        }
+        buffer.wpos(cmd == SshConstants.Message.SSH_MSG_CHANNEL_EXTENDED_DATA ? 14 : 10);
+        buffer.putInt(bufferLength);
+        buffer.wpos(pos);
+        try {
+            remoteWindow.waitAndConsume(bufferLength);
+            log.debug("Send {} on channel {}", cmd, channel.getId());
+            channel.getSession().writePacket(buffer);
+        } catch (SshException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new SshException(e);
+        } finally {
+            newBuffer();
+        }
+    }
+
+    @Override
+    public synchronized void close() throws IOException {
+        closed = true;
+    }
+
+    private void newBuffer() {
+        buffer = channel.getSession().createBuffer(cmd);
+        buffer.putInt(channel.getRecipient());
+        if (cmd == SshConstants.Message.SSH_MSG_CHANNEL_EXTENDED_DATA) {
+            buffer.putInt(1);
+        }
+        buffer.putInt(0);
+        bufferLength = 0;
+    }
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common.channel;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+import org.apache.sshd.common.util.Buffer;
+
+public class ChannelPipedInputStream extends InputStream {
+
+    private final Window localWindow;
+    private final Buffer buffer = new Buffer();
+    private final byte[] b = new byte[1];
+    private boolean closed;
+
+    public ChannelPipedInputStream(Window localWindow) {
+        this.localWindow = localWindow;
+    }
+
+    public int read() throws IOException {
+        synchronized (b) {
+            int l = read(b, 0, 1);
+            if (l == -1) {
+                return -1;
+            }
+            return b[0];
+        }
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int avail;
+        synchronized (buffer) {
+            for (;;) {
+                if (closed) {
+                    throw new IOException("Pipe closed");
+                }
+                if (buffer.available() > 0) {
+                    break;
+                }
+                try {
+                    buffer.wait();
+                } catch (InterruptedException e) {
+                    throw (IOException) new InterruptedIOException().initCause(e);
+                }
+            }
+            if (len > buffer.available()) {
+                len = buffer.available();
+            }
+            buffer.getRawBytes(b, off, len);
+            if (buffer.rpos() > localWindow.getPacketSize() || buffer.available() == 0) {
+                buffer.compact();
+            }
+            avail = localWindow.getMaxSize() - buffer.available();
+        }
+        localWindow.check(avail);
+        return len;
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (buffer) {
+            closed = true;
+            buffer.notifyAll();
+        }
+    }
+
+    public void receive(byte[] bytes, int off, int len) throws IOException {
+        synchronized (buffer) {
+            if (closed) {
+                throw new IOException("Pipe closed");
+            }
+            buffer.putRawBytes(bytes, off, len);
+            buffer.notifyAll();
+        }
+        localWindow.consume(len);
+    }
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedOutputStream.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedOutputStream.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedOutputStream.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/ChannelPipedOutputStream.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common.channel;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+public class ChannelPipedOutputStream extends OutputStream {
+
+    private final ChannelPipedInputStream sink;
+    private final byte[] b = new byte[1];
+
+    public ChannelPipedOutputStream(ChannelPipedInputStream sink) {
+        this.sink = sink;
+    }
+
+    public void write(int i) throws IOException {
+        synchronized (b) {
+            b[0] = (byte) i;
+            write(b, 0, 1);
+        }
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        sink.receive(b, off, len);
+    }
+
+    @Override
+    public void close() throws IOException {
+        sink.close();
+    }
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/Window.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/Window.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/Window.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/channel/Window.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common.channel;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Window {
+
+    private final static Logger log = LoggerFactory.getLogger(Window.class);
+
+    private final AbstractChannel channel;
+    private final Object lock;
+    private final String name;
+
+    private int size;
+    private int maxSize;
+    private int packetSize;
+    private boolean waiting;
+
+    public Window(AbstractChannel channel, Object lock, boolean client, boolean local) {
+        this.channel = channel;
+        this.lock = lock != null ? lock : this;
+        this.name = (client ? "client" : "server") + " " + (local ? "local " : "remote") + " window";
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+    public int getPacketSize() {
+        return packetSize;
+    }
+
+    public void init(int size, int packetSize) {
+        this.size = size;
+        this.maxSize = size;
+        this.packetSize = packetSize;
+    }
+    public void expand(int window) {
+        synchronized (lock) {
+            size += window;
+            if (log.isDebugEnabled()) {
+                log.debug("Increase " + name + " by " + window + " up to " + size);
+            }
+            lock.notifyAll();
+        }
+    }
+
+    public void consume(int len) {
+        synchronized (lock) {
+            //assert size > len;
+            size -= len;
+            if (log.isTraceEnabled()) {
+                log.trace("Consume " + name + " by " + len + " down to " + size);
+            }
+        }
+    }
+
+
+    public void consumeAndCheck(int len) throws IOException {
+        synchronized (lock) {
+            //assert size > len;
+            size -= len;
+            if (log.isTraceEnabled()) {
+                log.trace("Consume " + name + " by " + len + " down to " + size);
+            }
+            check(maxSize);
+        }
+    }
+
+    public void check(int maxFree) throws IOException {
+        int threshold = Math.min(packetSize * 8, maxSize / 4);
+        synchronized (lock) {
+            if ((maxFree - size) > packetSize && (maxFree - size > threshold || size < threshold)) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Increase " + name + " by " + (maxFree - size) + " up to " + maxFree);
+                }
+                channel.sendWindowAdjust(maxFree - size);
+                size = maxFree;
+            }
+        }
+    }
+
+    public void waitAndConsume(int len) throws InterruptedException {
+        synchronized (lock) {
+            while (size < len) {
+                log.debug("Waiting for {} bytes on {}", len, name);
+                waiting = true;
+                lock.wait();
+            }
+            if (waiting) {
+                log.debug("Space available for {}", name);
+                waiting = false;
+            }
+            size -= len;
+            if (log.isTraceEnabled()) {
+                log.trace("Consume " + name + " by " + len + " down to " + size);
+            }
+        }
+    }
+
+}

Added: mina/sshd/trunk/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java?rev=723396&view=auto
==============================================================================
--- mina/sshd/trunk/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java (added)
+++ mina/sshd/trunk/src/main/java/org/apache/sshd/common/cipher/AES128CBC.java Thu Dec  4 10:59:31 2008
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.sshd.common.cipher;
+
+import org.apache.sshd.common.Cipher;
+import org.apache.sshd.common.NamedFactory;
+
+public class AES128CBC extends BaseCipher {
+
+    public static class Factory implements NamedFactory<Cipher> {
+        public String getName() {
+            return "aes128-cbc";
+        }
+        public Cipher create() {
+            return new AES128CBC();
+        }
+    }
+
+    public AES128CBC() {
+        super(16, 16, "AES", "AES/CBC/NoPadding");
+    }
+
+}