Updated Branches: refs/heads/master 03aa3979d -> 488f4211f
[SSHD-222] Add pluggable global request handlers Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/488f4211 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/488f4211 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/488f4211 Branch: refs/heads/master Commit: 488f4211fc878c97d6a4f981007c01f2b5e6c197 Parents: 03aa397 Author: Guillaume Nodet <[email protected]> Authored: Wed Jan 29 13:57:01 2014 +0100 Committer: Guillaume Nodet <[email protected]> Committed: Wed Jan 29 13:57:01 2014 +0100 ---------------------------------------------------------------------- .../main/java/org/apache/sshd/SshServer.java | 11 ++ .../client/session/ClientConnectionService.java | 97 ----------- .../sshd/common/AbstractFactoryManager.java | 9 ++ .../org/apache/sshd/common/FactoryManager.java | 7 + .../sshd/common/GlobalRequestHandler.java | 45 ++++++ .../session/AbstractConnectionService.java | 159 ++++++++++++++++++- .../sshd/common/session/AbstractSession.java | 103 +----------- .../sshd/common/session/ConnectionService.java | 3 + .../global/CancelTcpipForwardHandler.java | 49 ++++++ .../sshd/server/global/KeepAliveHandler.java | 44 +++++ .../server/global/NoMoreSessionsHandler.java | 45 ++++++ .../sshd/server/global/TcpipForwardHandler.java | 50 ++++++ .../server/session/ServerConnectionService.java | 158 +----------------- 13 files changed, 421 insertions(+), 359 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/SshServer.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/SshServer.java index 56e84cd..90df02d 100644 --- a/sshd-core/src/main/java/org/apache/sshd/SshServer.java +++ b/sshd-core/src/main/java/org/apache/sshd/SshServer.java @@ -41,6 +41,7 @@ import org.apache.sshd.common.Cipher; import org.apache.sshd.common.Compression; import org.apache.sshd.common.Factory; import org.apache.sshd.common.ForwardingFilter; +import org.apache.sshd.common.GlobalRequestHandler; import org.apache.sshd.common.KeyExchange; import org.apache.sshd.common.Mac; import org.apache.sshd.common.NamedFactory; @@ -96,6 +97,10 @@ import org.apache.sshd.server.auth.gss.GSSAuthenticator; import org.apache.sshd.server.auth.gss.UserAuthGSS; import org.apache.sshd.server.channel.ChannelSession; import org.apache.sshd.server.command.ScpCommandFactory; +import org.apache.sshd.server.global.CancelTcpipForwardHandler; +import org.apache.sshd.server.global.KeepAliveHandler; +import org.apache.sshd.server.global.NoMoreSessionsHandler; +import org.apache.sshd.server.global.TcpipForwardHandler; import org.apache.sshd.server.kex.DHG1; import org.apache.sshd.server.kex.DHG14; import org.apache.sshd.server.kex.DHGEX; @@ -495,6 +500,12 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa new TcpipServerChannel.DirectTcpipFactory())); sshd.setFileSystemFactory(new NativeFileSystemFactory()); sshd.setTcpipForwarderFactory(new DefaultTcpipForwarderFactory()); + sshd.setGlobalRequestHandlers(Arrays.<GlobalRequestHandler>asList( + new KeepAliveHandler(), + new NoMoreSessionsHandler(), + new TcpipForwardHandler(), + new CancelTcpipForwardHandler() + )); return sshd; } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java index bc9e316..d183284 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java @@ -99,43 +99,6 @@ public class ClientConnectionService extends AbstractConnectionService { } } - public void process(SshConstants.Message cmd, Buffer buffer) throws Exception { - switch (cmd) { - case SSH_MSG_CHANNEL_OPEN: - channelOpen(buffer); - break; - 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; - default: - throw new IllegalStateException("Unsupported command: " + cmd); - } - } - // TODO: remove from interface public String initAgentForward() throws IOException { throw new IllegalStateException("Server side operation"); @@ -146,64 +109,4 @@ public class ClientConnectionService extends AbstractConnectionService { throw new IllegalStateException("Server side operation"); } - private void channelOpen(Buffer buffer) throws Exception { - String type = buffer.getString(); - final int id = buffer.getInt(); - final int rwsize = buffer.getInt(); - final int rmpsize = buffer.getInt(); - - log.info("Received SSH_MSG_CHANNEL_OPEN {}", type); - - if (closing) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - buf.putInt(SshConstants.SSH_OPEN_CONNECT_FAILED); - buf.putString("SSH server is shutting down: " + type); - buf.putString(""); - session.writePacket(buf); - return; - } - - final Channel channel = NamedFactory.Utils.create(getSession().getFactoryManager().getChannelFactories(), type); - if (channel == null) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - buf.putInt(SshConstants.SSH_OPEN_UNKNOWN_CHANNEL_TYPE); - buf.putString("Unsupported channel type: " + type); - buf.putString(""); - session.writePacket(buf); - return; - } - - final int channelId = registerChannel(channel); - channel.open(id, rwsize, rmpsize, buffer).addListener(new SshFutureListener<OpenFuture>() { - public void operationComplete(OpenFuture future) { - try { - if (future.isOpened()) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 0); - buf.putInt(id); - buf.putInt(channelId); - buf.putInt(channel.getLocalWindow().getSize()); - buf.putInt(channel.getLocalWindow().getPacketSize()); - session.writePacket(buf); - } else if (future.getException() != null) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - if (future.getException() instanceof OpenChannelException) { - buf.putInt(((OpenChannelException)future.getException()).getReasonCode()); - buf.putString(future.getException().getMessage()); - } else { - buf.putInt(0); - buf.putString("Error opening channel: " + future.getException().getMessage()); - } - buf.putString(""); - session.writePacket(buf); - } - } catch (IOException e) { - session.exceptionCaught(e); - } - } - }); - } - } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java index 450dce4..6c5bf4f 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java @@ -60,6 +60,7 @@ public abstract class AbstractFactoryManager implements FactoryManager { protected ForwardingFilter tcpipForwardingFilter; protected FileSystemFactory fileSystemFactory; protected List<ServiceFactory> serviceFactories; + protected List<GlobalRequestHandler> globalRequestHandlers; protected AbstractFactoryManager() { loadVersion(); @@ -236,4 +237,12 @@ public abstract class AbstractFactoryManager implements FactoryManager { public void setServiceFactories(List<ServiceFactory> serviceFactories) { this.serviceFactories = serviceFactories; } + + public List<GlobalRequestHandler> getGlobalRequestHandlers() { + return globalRequestHandlers; + } + + public void setGlobalRequestHandlers(List<GlobalRequestHandler> globalRequestHandlers) { + this.globalRequestHandlers = globalRequestHandlers; + } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java index 86e0155..43df005 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java @@ -184,4 +184,11 @@ public interface FactoryManager { */ List<ServiceFactory> getServiceFactories(); + /** + * Retrieve the list of global request handlers. + * + * @return a list of named <code>GlobalRequestHandler</code> + */ + List<GlobalRequestHandler> getGlobalRequestHandlers(); + } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java b/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java new file mode 100644 index 0000000..5409a4f --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/GlobalRequestHandler.java @@ -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.common; + +import org.apache.sshd.common.session.ConnectionService; +import org.apache.sshd.common.util.Buffer; + +/** + * A global request handler. + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public interface GlobalRequestHandler { + + /** + * Process the ssh-connection global request. + * If an exception is thrown, the ConnectionService will send a failure message if needed + * and the request will be considered handled. + * + * @param connectionService + * @param request + * @param wantReply + * @param buffer + * @return <code>true</code> if the request was handled + * @throws Exception + */ + boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java index 2f7b070..54432a8 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java @@ -27,16 +27,19 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.sshd.agent.common.AgentForwardSupport; import org.apache.sshd.client.channel.AbstractClientChannel; +import org.apache.sshd.client.future.OpenFuture; import org.apache.sshd.common.Channel; +import org.apache.sshd.common.GlobalRequestHandler; +import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.Session; import org.apache.sshd.common.SshConstants; import org.apache.sshd.common.SshException; import org.apache.sshd.common.TcpipForwarder; import org.apache.sshd.common.future.CloseFuture; import org.apache.sshd.common.future.DefaultCloseFuture; -import org.apache.sshd.common.future.SshFuture; import org.apache.sshd.common.future.SshFutureListener; import org.apache.sshd.common.util.Buffer; +import org.apache.sshd.server.channel.OpenChannelException; import org.apache.sshd.server.x11.X11ForwardSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +66,7 @@ public abstract class AbstractConnectionService implements ConnectionService { protected final X11ForwardSupport x11Forward; protected final CloseFuture closeFuture; protected volatile boolean closing; + protected boolean allowMoreSessions = true; protected AbstractConnectionService(Session session) { this.session = session; @@ -97,8 +101,8 @@ public abstract class AbstractConnectionService implements ConnectionService { final AtomicInteger latch = new AtomicInteger(channelToClose.size()); for (Channel channel : channelToClose) { log.debug("Closing channel {}", channel.getId()); - channel.close(immediately).addListener(new SshFutureListener() { - public void operationComplete(SshFuture sshFuture) { + channel.close(immediately).addListener(new SshFutureListener<CloseFuture>() { + public void operationComplete(CloseFuture future) { if (latch.decrementAndGet() == 0) { closeFuture.setClosed(); } @@ -125,7 +129,7 @@ public abstract class AbstractConnectionService implements ConnectionService { * * @param channel the channel to register * @return the id of this channel - * @throws Exception + * @throws IOException */ public int registerChannel(Channel channel) throws IOException { int channelId = getNextChannelId(); @@ -143,6 +147,50 @@ public abstract class AbstractConnectionService implements ConnectionService { channels.remove(channel.getId()); } + public void process(SshConstants.Message cmd, Buffer buffer) throws Exception { + switch (cmd) { + case SSH_MSG_CHANNEL_OPEN: + channelOpen(buffer); + break; + 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; + case SSH_MSG_GLOBAL_REQUEST: + globalRequest(buffer); + break; + default: + throw new IllegalStateException("Unsupported command: " + cmd); + } + } + + public void setAllowMoreSessions(boolean allow) { + allowMoreSessions = allow; + } + public void channelOpenConfirmation(Buffer buffer) throws IOException { Channel channel = getChannel(buffer); log.debug("Received SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel {}", channel.getId()); @@ -268,4 +316,107 @@ public abstract class AbstractConnectionService implements ConnectionService { return channel; } + protected void channelOpen(Buffer buffer) throws Exception { + String type = buffer.getString(); + final int id = buffer.getInt(); + final int rwsize = buffer.getInt(); + final int rmpsize = buffer.getInt(); + + log.debug("Received SSH_MSG_CHANNEL_OPEN {}", type); + + if (closing) { + Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); + buf.putInt(id); + buf.putInt(SshConstants.SSH_OPEN_CONNECT_FAILED); + buf.putString("SSH server is shutting down: " + type); + buf.putString(""); + session.writePacket(buf); + return; + } + if (!allowMoreSessions) { + Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); + buf.putInt(id); + buf.putInt(SshConstants.SSH_OPEN_CONNECT_FAILED); + buf.putString("additional sessions disabled"); + buf.putString(""); + session.writePacket(buf); + return; + } + + final Channel channel = NamedFactory.Utils.create(session.getFactoryManager().getChannelFactories(), type); + if (channel == null) { + Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); + buf.putInt(id); + buf.putInt(SshConstants.SSH_OPEN_UNKNOWN_CHANNEL_TYPE); + buf.putString("Unsupported channel type: " + type); + buf.putString(""); + session.writePacket(buf); + return; + } + + final int channelId = registerChannel(channel); + channel.open(id, rwsize, rmpsize, buffer).addListener(new SshFutureListener<OpenFuture>() { + public void operationComplete(OpenFuture future) { + try { + if (future.isOpened()) { + Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 0); + buf.putInt(id); + buf.putInt(channelId); + buf.putInt(channel.getLocalWindow().getSize()); + buf.putInt(channel.getLocalWindow().getPacketSize()); + session.writePacket(buf); + } else if (future.getException() != null) { + Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); + buf.putInt(id); + if (future.getException() instanceof OpenChannelException) { + buf.putInt(((OpenChannelException) future.getException()).getReasonCode()); + buf.putString(future.getException().getMessage()); + } else { + buf.putInt(0); + buf.putString("Error opening channel: " + future.getException().getMessage()); + } + buf.putString(""); + session.writePacket(buf); + } + } catch (IOException e) { + session.exceptionCaught(e); + } + } + }); + } + + /** + * Process global requests + * + * @param buffer the request + * @throws Exception + */ + protected void globalRequest(Buffer buffer) throws Exception { + String req = buffer.getString(); + boolean wantReply = buffer.getBoolean(); + log.debug("Received SSH_MSG_GLOBAL_REQUEST {}", req); + List<GlobalRequestHandler> handlers = session.getFactoryManager().getGlobalRequestHandlers(); + if (handlers != null) { + for (GlobalRequestHandler handler : handlers) { + try { + if (handler.process(this, req, wantReply, buffer)) { + return; + } + } catch (Exception e) { + log.warn("Error processing global request " + req, e); + if (wantReply) { + buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0); + session.writePacket(buffer); + } + return; + } + } + } + log.warn("Unknown global request: {}", req); + if (wantReply) { + buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0); + session.writePacket(buffer); + } + } + } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java index a7c6ec7..942809e 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java @@ -24,11 +24,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import org.apache.sshd.client.channel.AbstractClientChannel; -import org.apache.sshd.common.Channel; import org.apache.sshd.common.Cipher; import org.apache.sshd.common.Compression; import org.apache.sshd.common.Digest; @@ -42,14 +39,12 @@ import org.apache.sshd.common.Session; import org.apache.sshd.common.SessionListener; import org.apache.sshd.common.SshConstants; import org.apache.sshd.common.SshException; -import org.apache.sshd.common.TcpipForwarder; import org.apache.sshd.common.future.CloseFuture; import org.apache.sshd.common.future.DefaultCloseFuture; -import org.apache.sshd.common.future.SshFuture; import org.apache.sshd.common.future.SshFutureListener; import org.apache.sshd.common.io.IoCloseFuture; -import org.apache.sshd.common.io.IoWriteFuture; import org.apache.sshd.common.io.IoSession; +import org.apache.sshd.common.io.IoWriteFuture; import org.apache.sshd.common.util.Buffer; import org.apache.sshd.common.util.BufferUtils; import org.apache.sshd.common.util.Readable; @@ -337,7 +332,7 @@ public abstract class AbstractSession implements Session { lock.notifyAll(); } state = State.Closed; - log.info("Session {}@{} closed", s.getUsername(), s.getIoSession().getRemoteAddress()); + log.info("SMessession {}@{} closed", s.getUsername(), s.getIoSession().getRemoteAddress()); // Fire 'close' event final ArrayList<SessionListener> l = new ArrayList<SessionListener>(listeners); for (SessionListener sl : l) { @@ -998,100 +993,6 @@ public abstract class AbstractSession implements Session { } } - - /* - protected int getNextChannelId() { - return nextChannelId.incrementAndGet(); - } - - public int registerChannel(Channel channel) throws IOException { - int channelId = getNextChannelId(); - channel.init(this, session, channelId); - channels.put(channelId, channel); - return channelId; - } - - public void channelOpenConfirmation(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - log.debug("Received SSH_MSG_CHANNEL_OPEN_CONFIRMATION on channel {}", channel.getId()); - int recipient = buffer.getInt(); - int rwsize = buffer.getInt(); - int rmpsize = buffer.getInt(); - channel.handleOpenSuccess(recipient, rwsize, rmpsize, buffer); - } - - public void channelOpenFailure(Buffer buffer) throws IOException { - AbstractClientChannel channel = (AbstractClientChannel) getChannel(buffer); - log.debug("Received SSH_MSG_CHANNEL_OPEN_FAILURE on channel {}", channel.getId()); - channels.remove(channel.getId()); - channel.handleOpenFailure(buffer); - } - - public void channelData(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - channel.handleData(buffer); - } - - public void channelExtendedData(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - channel.handleExtendedData(buffer); - } - - public void channelWindowAdjust(Buffer buffer) throws IOException { - try { - Channel channel = getChannel(buffer); - channel.handleWindowAdjust(buffer); - } catch (SshException e) { - log.info(e.getMessage()); - } - } - - public void channelEof(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - channel.handleEof(); - } - - public void channelClose(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - channel.handleClose(); - unregisterChannel(channel); - } - - public void unregisterChannel(Channel channel) { - channels.remove(channel.getId()); - } - - public void channelRequest(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - String type = buffer.getString(); - boolean wantReply = buffer.getBoolean(); - boolean success = channel.handleRequest(type, buffer); - if (wantReply) { - Buffer replyBuffer = createBuffer( - success ? SshConstants.Message.SSH_MSG_CHANNEL_SUCCESS - : SshConstants.Message.SSH_MSG_CHANNEL_FAILURE, 0); - replyBuffer.putInt(channel.getRecipient()); - writePacket(replyBuffer); - } - } - - public void channelFailure(Buffer buffer) throws IOException { - Channel channel = getChannel(buffer); - channel.handleFailure(); - } - - protected Channel getChannel(Buffer buffer) throws IOException { - int recipient = buffer.getInt(); - Channel channel = channels.get(recipient); - if (channel == null) { - buffer.rpos(buffer.rpos() - 5); - SshConstants.Message cmd = buffer.getCommand(); - throw new SshException("Received " + cmd + " on unknown channel " + recipient); - } - return channel; - } - */ - /** * Retrieve a configuration property as an integer * http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java index 600986a..45c6266 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/session/ConnectionService.java @@ -60,4 +60,7 @@ public interface ConnectionService extends Service { // TODO: remove from interface, it's server side only String createX11Display(boolean singleConnection, String authenticationProtocol, String authenticationCookie, int screen) throws IOException; + + void setAllowMoreSessions(boolean allow); + } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java new file mode 100644 index 0000000..23c127d --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java @@ -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.server.global; + +import org.apache.sshd.common.GlobalRequestHandler; +import org.apache.sshd.common.SshConstants; +import org.apache.sshd.common.SshdSocketAddress; +import org.apache.sshd.common.session.ConnectionService; +import org.apache.sshd.common.util.Buffer; + +/** + * Handler for cancel-tcpip-forward global request. + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class CancelTcpipForwardHandler implements GlobalRequestHandler { + + public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception { + if (request.equals("cancel-tcpip-forward")) { + String address = buffer.getString(); + int port = buffer.getInt(); + connectionService.getTcpipForwarder().localPortForwardingCancelled(new SshdSocketAddress(address, port)); + if (wantReply){ + buffer = connectionService.getSession().createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0); + buffer.putInt(port); + connectionService.getSession().writePacket(buffer); + } + return true; + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java new file mode 100644 index 0000000..3371ed9 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/server/global/KeepAliveHandler.java @@ -0,0 +1,44 @@ +/* + * 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.server.global; + +import org.apache.sshd.common.GlobalRequestHandler; +import org.apache.sshd.common.SshConstants; +import org.apache.sshd.common.session.ConnectionService; +import org.apache.sshd.common.util.Buffer; + +/** + * Handler for keepalive@xxx global request. + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class KeepAliveHandler implements GlobalRequestHandler { + + public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception { + if (request.startsWith("keepalive@")) { + if (wantReply) { + buffer = connectionService.getSession().createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0); + connectionService.getSession().writePacket(buffer); + } + return true; + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java new file mode 100644 index 0000000..98fe3a3 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/server/global/NoMoreSessionsHandler.java @@ -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.server.global; + +import org.apache.sshd.common.GlobalRequestHandler; +import org.apache.sshd.common.SshConstants; +import org.apache.sshd.common.session.ConnectionService; +import org.apache.sshd.common.util.Buffer; + +/** + * Handler for no-more-sessions@xxx global request. + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class NoMoreSessionsHandler implements GlobalRequestHandler { + + public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception { + if (request.startsWith("no-more-sessions@")) { + connectionService.setAllowMoreSessions(false); + if (wantReply) { + buffer = connectionService.getSession().createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0); + connectionService.getSession().writePacket(buffer); + } + return true; + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java new file mode 100644 index 0000000..01aa6a5 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java @@ -0,0 +1,50 @@ +/* + * 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.server.global; + +import org.apache.sshd.common.GlobalRequestHandler; +import org.apache.sshd.common.SshConstants; +import org.apache.sshd.common.SshdSocketAddress; +import org.apache.sshd.common.session.ConnectionService; +import org.apache.sshd.common.util.Buffer; + +/** + * Handler for tcpip-forward global request. + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class TcpipForwardHandler implements GlobalRequestHandler { + + public boolean process(ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception { + if (request.equals("tcpip-forward")) { + String address = buffer.getString(); + int port = buffer.getInt(); + SshdSocketAddress bound = connectionService.getTcpipForwarder().localPortForwardingRequested(new SshdSocketAddress(address, port)); + port = bound.getPort(); + if (wantReply){ + buffer = connectionService.getSession().createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0); + buffer.putInt(port); + connectionService.getSession().writePacket(buffer); + } + return true; + } + return false; + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/488f4211/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java index b5a4461..50c0cf8 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerConnectionService.java @@ -22,6 +22,7 @@ import java.io.IOException; import org.apache.sshd.client.future.OpenFuture; import org.apache.sshd.common.Channel; +import org.apache.sshd.common.GlobalRequestHandler; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.Service; import org.apache.sshd.common.ServiceFactory; @@ -53,8 +54,6 @@ public class ServerConnectionService extends AbstractConnectionService { } - private boolean allowMoreSessions = true; - protected ServerConnectionService(Session s) throws SshException { super(s); if (!(s instanceof ServerSession)) { @@ -66,161 +65,6 @@ public class ServerConnectionService extends AbstractConnectionService { } } - public void process(SshConstants.Message cmd, Buffer buffer) throws Exception { - switch (cmd) { - case SSH_MSG_CHANNEL_OPEN: - channelOpen(buffer); - break; - 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; - case SSH_MSG_GLOBAL_REQUEST: - globalRequest(buffer); - break; - default: - throw new IllegalStateException("Unsupported command: " + cmd); - } - } - - private void channelOpen(Buffer buffer) throws Exception { - String type = buffer.getString(); - final int id = buffer.getInt(); - final int rwsize = buffer.getInt(); - final int rmpsize = buffer.getInt(); - - log.debug("Received SSH_MSG_CHANNEL_OPEN {}", type); - - if (closing) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - buf.putInt(SshConstants.SSH_OPEN_CONNECT_FAILED); - buf.putString("SSH server is shutting down: " + type); - buf.putString(""); - session.writePacket(buf); - return; - } - if (!allowMoreSessions) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - buf.putInt(SshConstants.SSH_OPEN_CONNECT_FAILED); - buf.putString("additional sessions disabled"); - buf.putString(""); - session.writePacket(buf); - return; - } - - final Channel channel = NamedFactory.Utils.create(session.getFactoryManager().getChannelFactories(), type); - if (channel == null) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - buf.putInt(SshConstants.SSH_OPEN_UNKNOWN_CHANNEL_TYPE); - buf.putString("Unsupported channel type: " + type); - buf.putString(""); - session.writePacket(buf); - return; - } - - final int channelId = registerChannel(channel); - channel.open(id, rwsize, rmpsize, buffer).addListener(new SshFutureListener<OpenFuture>() { - public void operationComplete(OpenFuture future) { - try { - if (future.isOpened()) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 0); - buf.putInt(id); - buf.putInt(channelId); - buf.putInt(channel.getLocalWindow().getSize()); - buf.putInt(channel.getLocalWindow().getPacketSize()); - session.writePacket(buf); - } else if (future.getException() != null) { - Buffer buf = session.createBuffer(SshConstants.Message.SSH_MSG_CHANNEL_OPEN_FAILURE, 0); - buf.putInt(id); - if (future.getException() instanceof OpenChannelException) { - buf.putInt(((OpenChannelException) future.getException()).getReasonCode()); - buf.putString(future.getException().getMessage()); - } else { - buf.putInt(0); - buf.putString("Error opening channel: " + future.getException().getMessage()); - } - buf.putString(""); - session.writePacket(buf); - } - } catch (IOException e) { - session.exceptionCaught(e); - } - } - }); - } - - private void globalRequest(Buffer buffer) throws Exception { - String req = buffer.getString(); - boolean wantReply = buffer.getBoolean(); - log.debug("Received global request {}", req); - if (req.startsWith("keepalive@")) { - // Relatively standard KeepAlive directive, just wants failure - } else if (req.equals("[email protected]")) { - allowMoreSessions = false; - } else if (req.equals("tcpip-forward")) { - String address = buffer.getString(); - int port = buffer.getInt(); - try { - SshdSocketAddress bound = tcpipForwarder.localPortForwardingRequested(new SshdSocketAddress(address, port)); - port = bound.getPort(); - if (wantReply){ - buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0); - buffer.putInt(port); - session.writePacket(buffer); - } - } catch (Exception e) { - log.debug("Error starting tcpip forward", e); - if (wantReply) { - buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0); - session.writePacket(buffer); - } - } - return; - } else if (req.equals("cancel-tcpip-forward")) { - String address = buffer.getString(); - int port = buffer.getInt(); - tcpipForwarder.localPortForwardingCancelled(new SshdSocketAddress(address, port)); - if (wantReply){ - buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_SUCCESS, 0); - session.writePacket(buffer); - } - return; - } else { - log.debug("Received SSH_MSG_GLOBAL_REQUEST {}", req); - log.warn("Unknown global request: {}", req); - } - if (wantReply) { - buffer = session.createBuffer(SshConstants.Message.SSH_MSG_REQUEST_FAILURE, 0); - session.writePacket(buffer); - } - } - public String initAgentForward() throws IOException { return agentForward.initialize(); }
