com.sshtools.server.TransportProtocolServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maverick-synergy-server Show documentation
Show all versions of maverick-synergy-server Show documentation
The server-side implementation for the Maverick Synergy SSH API
/**
* (c) 2002-2021 JADAPTIVE Limited. All Rights Reserved.
*
* This file is part of the Maverick Synergy Java SSH API.
*
* Maverick Synergy is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Maverick Synergy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Maverick Synergy. If not, see .
*/
package com.sshtools.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import com.sshtools.common.events.Event;
import com.sshtools.common.events.EventCodes;
import com.sshtools.common.events.EventServiceImplementation;
import com.sshtools.common.logger.Log;
import com.sshtools.common.permissions.IPPolicy;
import com.sshtools.common.ssh.SshException;
import com.sshtools.common.ssh.components.SshKeyPair;
import com.sshtools.common.sshd.AbstractServerTransport;
import com.sshtools.common.sshd.SshMessage;
import com.sshtools.common.util.ByteArrayReader;
import com.sshtools.synergy.nio.ConnectRequestFuture;
import com.sshtools.synergy.nio.LicenseException;
import com.sshtools.synergy.nio.SocketConnection;
import com.sshtools.synergy.ssh.ConnectionStateListener;
import com.sshtools.synergy.ssh.Service;
import com.sshtools.synergy.ssh.TransportProtocol;
import com.sshtools.synergy.ssh.components.SshKeyExchange;
//#ifdef LICENSE
//import com.sshtools.synergy.common.nio.LicenseManager;
//#endif
public final class TransportProtocolServer extends TransportProtocol implements AbstractServerTransport {
int disconnectReason;
String disconnectText;
boolean denyConnection = false;
//#ifdef LICENSE
//final static LicenseVerification license = new LicenseVerification();
//#endif
public TransportProtocolServer(SshServerContext sshContext, ConnectRequestFuture connectFuture) throws LicenseException {
super(sshContext, connectFuture);
//#ifdef LICENSE
//checkLicensing();
//#endif
}
//#ifdef LICENSE
/*
private final void checkLicensing() throws LicenseException {
if(!license.isLicensed()) {
license.verifyLicense();
if(license.isValid()) {
if(Log.isInfoEnabled()) {
Log.info("This Maverick NG API product is licensed to " + license.getLicensee());
}
}
}
switch (license.getStatus() & LicenseVerification.LICENSE_VERIFICATION_MASK) {
case LicenseVerification.EXPIRED:
throw new LicenseException("Your license has expired! visit http://www.sshtools.com to obtain an update version of the software.");
case LicenseVerification.OK:
break;
case LicenseVerification.INVALID:
throw new LicenseException("Your license is invalid!");
case LicenseVerification.NOT_LICENSED:
throw new LicenseException("NOT_LICENSED_TEXT");
case LicenseVerification.EXPIRED_MAINTENANCE:
throw new LicenseException(
"Your support and maintenance has expired! visit http://www.sshtools.com to purchase a subscription");
default:
throw new LicenseException("An unexpected license status was received.");
}
}
*/
//#endif
public SshServerContext getContext() {
return sshContext;
}
@Override
protected boolean canConnect(SocketConnection connection) {
boolean canConnect = sshContext.getPolicy(IPPolicy.class).checkConnection(connection.getRemoteAddress(),
connection.getLocalAddress());
if(Log.isDebugEnabled()) {
Log.debug("IP policy has " + (canConnect ? "authorized" : "denied") + " access to "
+ ((InetSocketAddress) connection.getRemoteAddress()).getAddress());
}
if (!canConnect) {
return false;
}
synchronized (lock) {
Integer numberOfConnections = sshContext.getConnectionManager().getNumberOfConnections();
if (sshContext.getEngine().getContext().getMaximumConnections() > -1) {
if (numberOfConnections.intValue() >= sshContext.getEngine().getContext().getMaximumConnections()) {
denyConnection = true;
disconnectText = sshContext.getEngine().getContext().getTooManyConnectionsText();
disconnectReason = TransportProtocol.TOO_MANY_CONNECTIONS;
if (!sshContext.isEnsureGracefulDisconnect()) {
fireTooManyConnectionsDisconnectEvent(numberOfConnections);
if(Log.isDebugEnabled())
Log.debug("Denying connection.. too many users currently online");
connection.closeConnection();
return false;
}
/**
* Fix disconnect event when using getAllowedDeniedKEX() ==
* true
*/
sessionIdentifier = new byte[] {};
}
}
}
return true;
}
@Override
protected void initializeKeyExchange(SshKeyExchange keyExchange, boolean firstPacketFollows,
boolean useFirstPacket) throws IOException, SshException {
SshKeyPair pair = getContext().getHostKey(publicKey);
hostKey = pair.getPublicKey();
keyExchange.init(this, remoteIdentification.toString().trim(), localIdentification.trim(), remotekex, localkex,
pair.getPrivateKey(), pair.getPublicKey(), firstPacketFollows, useFirstPacket);
}
protected void onKeyExchangeInit() throws SshException {
if(getContext().isForceServerPreferences()) {
/**
* Reconfigure before sending kex init to ensure we only
* support the strongest algorithms of the client
*/
getContext().supportedKeyExchanges().removeAllBut(
getContext().supportedKeyExchanges().selectStrongestComponent(getRemoteKeyExchanges()));
getContext().supportedPublicKeys().removeAllBut(
getContext().supportedPublicKeys().selectStrongestComponent(getRemotePublicKeys()));
getContext().supportedCiphersCS().removeAllBut(
getContext().supportedCiphersCS().selectStrongestComponent(getRemoteCiphersCS()));
getContext().supportedCiphersCS().removeAllBut(
getContext().supportedCiphersCS().selectStrongestComponent(getRemoteCiphersSC()));
getContext().supportedMacsCS().removeAllBut(
getContext().supportedMacsCS().selectStrongestComponent(getRemoteMacsCS()));
getContext().supportedMacsSC().removeAllBut(
getContext().supportedMacsSC().selectStrongestComponent(getRemoteMacsSC()));
}
}
protected void keyExchangeInitialized() {
if (denyConnection) {
fireTooManyConnectionsDisconnectEvent(sshContext.getConnectionManager().getNumberOfConnections());
disconnect(disconnectReason, disconnectText);
}
}
@Override
protected boolean canSendKeyExchangeInit() {
return !getContext().isForceServerPreferences();
}
@Override
protected void onNewKeysReceived() {
generateNewKeysServerIn();
}
@Override
protected boolean processTransportMessage(int msgId, byte[] msg) throws IOException {
switch (msg[0]) {
case SSH_MSG_SERVICE_REQUEST: {
if(Log.isDebugEnabled())
Log.debug("Processing SSH_MSG_SERVICE_REQUEST");
startService(msg);
return true;
}
default: {
return false;
}
}
}
/**
* Request that the remote server starts a transport protocol service.
*
* @param servicename
* @throws IOException
*/
void startService(byte[] msg) throws IOException {
ByteArrayReader bar = new ByteArrayReader(msg);
try {
bar.skip(1);
final String servicename = bar.readString();
// Do we allow this service?
if (servicename.equals("ssh-userauth")) {
// Set the current service to the authentication protocol
activeService = new AuthenticationProtocolServer(this);
final byte[] serviceNameBytes = getBytes(servicename, CHARSET_ENCODING);
// Inform the client that we have accepted the service
postMessage(new SshMessage() {
public boolean writeMessageIntoBuffer(ByteBuffer buf) {
buf.put((byte) SSH_MSG_SERVICE_ACCEPT);
buf.putInt(serviceNameBytes.length);
buf.put(serviceNameBytes);
return true;
}
public void messageSent(Long sequenceNo) throws SshException {
if(Log.isDebugEnabled())
Log.debug("Sent SSH_MSG_SERVICE_ACCEPT");
activeService.start();
}
});
} else {
disconnect(SERVICE_NOT_AVAILABLE, servicename + " is not a valid service.");
}
} finally {
bar.close();
}
}
void startService(Service activeService) throws SshException {
this.activeService.stop();
this.activeService = activeService;
activeService.start();
}
@Override
protected void onNewKeysSent() {
generateNewKeysServerOut();
}
@Override
protected void disconnected() {
for (ConnectionStateListener stateListener : getContext().getStateListeners()) {
stateListener.disconnected(getContext().getConnectionManager().getConnectionById(getUUID()));
}
}
@Override
protected void onConnected() {
this.con = getContext().getConnectionManager().registerTransport(this, getContext());
getConnectFuture().connected(this, con);
}
@Override
protected void onDisconnected() {
getContext().getConnectionManager().unregisterTransport(this);
}
private void fireTooManyConnectionsDisconnectEvent(Integer numberOfConnections) {
EventServiceImplementation.getInstance()
.fireEvent((new Event(this, EventCodes.EVENT_REACHED_CONNECTION_LIMIT, false))
.addAttribute(EventCodes.ATTRIBUTE_CONNECTION, con).addAttribute(
EventCodes.ATTRIBUTE_NUMBER_OF_CONNECTIONS,
String.valueOf(numberOfConnections.intValue())));
}
public String getName() {
return "transport-server";
}
@Override
protected SocketAddress getConnectionAddress() {
return getRemoteAddress();
}
@Override
public void startService(com.sshtools.common.sshd.Service service) {
}
}