protected int readRawInput() throws IOException { if (buffer.available() > 0) { return buffer.getUByte(); } else { return this.in.read(); } }
@Override public synchronized int read(byte[] b, int off, int len) throws IOException { if (len == 1) { int c = read(); if (c == -1) { return -1; } b[off] = (byte) c; return 1; } if (buffer.available() == 0) { int nb = this.in.read(b, off, len); if (nb == -1) { return nb; } buffer.putRawBytes(b, off, nb); } int nb = 0; for (int curPos = off; (nb < len) && (buffer.available() > 0); nb++, curPos++) { b[curPos] = (byte) read(); } return nb; }
/** * @param extraSize Extra size - besides the extension name * @return A {@link Buffer} with the extension name set */ protected Buffer getCommandBuffer(int extraSize) { String opcode = getName(); Buffer buffer = new ByteArrayBuffer( (Integer.SIZE / Byte.SIZE) + GenericUtils.length(opcode) + extraSize + Byte.SIZE); buffer.putString(opcode); return buffer; }
@Override protected void reply(Buffer buf) throws IOException { ByteBuffer b = ByteBuffer.wrap(buf.array(), buf.rpos(), buf.available()); int result = sessionChannel.write(b); if (result < 0) { throw new IOException("Could not write response to socket"); } }
@Override public void messageReceived(IoSession session, Readable message) throws Exception { TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class); Buffer buffer = new ByteArrayBuffer(); buffer.putBuffer(message); channel.waitFor(ClientChannel.OPENED | ClientChannel.CLOSED, Long.MAX_VALUE); OutputStream outputStream = channel.getInvertedIn(); outputStream.write(buffer.array(), buffer.rpos(), buffer.available()); outputStream.flush(); }
/** * @param buffer The {@link Buffer} * @param target A target path {@link String} or {@link Handle} or {@code byte[]} to be encoded in * the buffer * @return The updated buffer * @throws UnsupportedOperationException If target is not one of the above supported types */ public Buffer putTarget(Buffer buffer, Object target) { if (target instanceof CharSequence) { buffer.putString(target.toString()); } else if (target instanceof byte[]) { buffer.putBytes((byte[]) target); } else if (target instanceof Handle) { buffer.putBytes(((Handle) target).getIdentifier()); } else { throw new UnsupportedOperationException("Unknown target type: " + target); } return buffer; }
@Override protected void process(int cmd, Buffer req, Buffer rep) throws Exception { switch (cmd) { case SSH_AGENTC_REQUEST_RSA_IDENTITIES: // stop causing ssh-add -l to log errors rep.putByte(SSH_AGENT_RSA_IDENTITIES_ANSWER); rep.putInt(0); break; default: super.process(cmd, req, rep); break; } }
protected void sendHeartBeat() { String request = FactoryManagerUtils.getStringProperty( session, ClientFactoryManager.HEARTBEAT_REQUEST, ClientFactoryManager.DEFAULT_KEEP_ALIVE_HEARTBEAT_STRING); try { Buffer buf = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST); buf.putString(request); buf.putBoolean(false); session.writePacket(buf); } catch (IOException e) { log.info("Error sending keepalive message=" + request, e); } }
public synchronized void write(byte[] buf, int off, int len) { if (len == 1) { write(buf[off] & 0xFF); } else { buffer.putBytes(buf, off, len); } }
/** Test whether onWindowExpanded is called from server session */ @Test public void testHandleWindowAdjust() throws Exception { final Buffer buffer = new ByteArrayBuffer(); buffer.putInt(1234); try (ChannelSession channelSession = new ChannelSession()) { channelSession.asyncOut = new ChannelAsyncOutputStream(new BogusChannel(), (byte) 0) { @SuppressWarnings("synthetic-access") @Override public void onWindowExpanded() throws IOException { expanded = true; super.onWindowExpanded(); } }; channelSession.handleWindowAdjust(buffer); assertTrue(expanded); } }
@Override public synchronized OpenFuture open() throws IOException { if (isClosing()) { throw new SshException("Session has been closed"); } openFuture = new DefaultOpenFuture(lock); if (log.isDebugEnabled()) { log.debug("open({}) Send SSH_MSG_CHANNEL_OPEN - type={}", this, type); } Session session = getSession(); Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN, type.length() + Integer.SIZE); buffer.putString(type); buffer.putInt(getId()); buffer.putInt(localWindow.getSize()); buffer.putInt(localWindow.getPacketSize()); writePacket(buffer); return openFuture; }
/** * @param buffer The {@link Buffer} to check * @return The {@link Buffer} if this is an {@link SftpConstants#SSH_FXP_EXTENDED_REPLY}, or * {@code null} if this is a {@link SftpConstants#SSH_FXP_STATUS} carrying an {@link * SftpConstants#SSH_FX_OK} result * @throws IOException If a non-{@link SftpConstants#SSH_FX_OK} result or not a {@link * SftpConstants#SSH_FXP_EXTENDED_REPLY} buffer */ protected Buffer checkExtendedReplyBuffer(Buffer buffer) throws IOException { int length = buffer.getInt(); int type = buffer.getUByte(); int id = buffer.getInt(); if (type == SftpConstants.SSH_FXP_STATUS) { int substatus = buffer.getInt(); String msg = buffer.getString(); String lang = buffer.getString(); if (log.isDebugEnabled()) { log.debug( "checkStatus({}}[id={}] - status: {} [{}] {}", getName(), id, substatus, lang, msg); } if (substatus != SftpConstants.SSH_FX_OK) { throwStatusException(id, substatus, msg, lang); } return null; } else if (type == SftpConstants.SSH_FXP_EXTENDED_REPLY) { return buffer; } else { throw new SshException( "Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length); } }
@Override public void handleOpenFailure(Buffer buffer) { int reason = buffer.getInt(); String msg = buffer.getString(); String lang = buffer.getString(); if (log.isDebugEnabled()) { log.debug( "handleOpenFailure({}) reason={}, lang={}, msg={}", this, SshConstants.getOpenErrorCodeName(reason), lang, msg); } this.openFailureReason = reason; this.openFailureMsg = msg; this.openFailureLang = lang; this.openFuture.setException(new SshException(msg)); this.closeFuture.setClosed(); this.doCloseImmediately(); notifyStateChanged(); }
@Override public Result process( ConnectionService connectionService, String request, boolean wantReply, Buffer buffer) throws Exception { if (!REQUEST.equals(request)) { return super.process(connectionService, request, wantReply, buffer); } String address = buffer.getString(); int port = buffer.getInt(); SshdSocketAddress socketAddress = new SshdSocketAddress(address, port); TcpipForwarder forwarder = Objects.requireNonNull(connectionService.getTcpipForwarder(), "No TCP/IP forwarder"); SshdSocketAddress bound = forwarder.localPortForwardingRequested(socketAddress); if (log.isDebugEnabled()) { log.debug( "process({})[{}][want-reply-{}] {} => {}", connectionService, request, wantReply, socketAddress, bound); } if (bound == null) { return Result.ReplyFailure; } port = bound.getPort(); if (wantReply) { Session session = connectionService.getSession(); buffer = session.createBuffer(SshConstants.SSH_MSG_REQUEST_SUCCESS, Integer.BYTES); buffer.putInt(port); session.writePacket(buffer); } return Result.Replied; }
@Override public synchronized void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException { SshdSocketAddress bound; synchronized (remoteToLocal) { bound = remoteToLocal.remove(remote.getPort()); } if (bound != null) { if (log.isDebugEnabled()) { log.debug("stopRemotePortForwarding(" + remote + ") cancel forwarding to " + bound); } Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST); buffer.putString("cancel-tcpip-forward"); buffer.putBoolean(false); buffer.putString(remote.getHostName()); buffer.putInt(remote.getPort()); session.writePacket(buffer); } else { if (log.isDebugEnabled()) { log.debug("stopRemotePortForwarding(" + remote + ") no binding found"); } } }
protected Pair<String, Collection<byte[]>> doGetHash( Object target, Collection<String> algorithms, long offset, long length, int blockSize) throws IOException { Buffer buffer = getCommandBuffer(target, Byte.MAX_VALUE); putTarget(buffer, target); buffer.putString(GenericUtils.join(algorithms, ',')); buffer.putLong(offset); buffer.putLong(length); buffer.putInt(blockSize); if (log.isDebugEnabled()) { log.debug( "doGetHash({})[{}] - offset={}, length={}, block-size={}", getName(), (target instanceof CharSequence) ? target : BufferUtils.toHex(BufferUtils.EMPTY_HEX_SEPARATOR, (byte[]) target), offset, length, blockSize); } buffer = checkExtendedReplyBuffer(receive(sendExtendedCommand(buffer))); if (buffer == null) { throw new StreamCorruptedException("Missing extended reply data"); } String targetType = buffer.getString(); if (String.CASE_INSENSITIVE_ORDER.compare(targetType, SftpConstants.EXT_CHECK_FILE) != 0) { throw new StreamCorruptedException( "Mismatched reply type: expected=" + SftpConstants.EXT_CHECK_FILE + ", actual=" + targetType); } String algo = buffer.getString(); Collection<byte[]> hashes = new LinkedList<>(); while (buffer.available() > 0) { byte[] hashValue = buffer.getBytes(); hashes.add(hashValue); } return new Pair<String, Collection<byte[]>>(algo, hashes); }
@Override public synchronized SshdSocketAddress startRemotePortForwarding( SshdSocketAddress remote, SshdSocketAddress local) throws IOException { ValidateUtils.checkNotNull(local, "Local address is null"); ValidateUtils.checkNotNull(remote, "Remote address is null"); Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST); buffer.putString("tcpip-forward"); buffer.putBoolean(true); buffer.putString(remote.getHostName()); buffer.putInt(remote.getPort()); Buffer result = session.request(buffer); if (result == null) { throw new SshException("Tcpip forwarding request denied by server"); } int port = (remote.getPort() == 0) ? result.getInt() : remote.getPort(); // TODO: Is it really safe to only store the local address after the request ? SshdSocketAddress prev; synchronized (remoteToLocal) { prev = remoteToLocal.put(port, local); } if (prev != null) { throw new IOException( "Multiple remote port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev); } SshdSocketAddress bound = new SshdSocketAddress(remote.getHostName(), port); if (log.isDebugEnabled()) { log.debug("startRemotePortForwarding(" + remote + " -> " + local + "): " + bound); } return bound; }
@Override public Boolean doAuth(Buffer buffer, boolean init) throws Exception { ValidateUtils.checkTrue(init, "Instance not initialized"); boolean hasSig = buffer.getBoolean(); String alg = buffer.getString(); int oldLim = buffer.wpos(); int oldPos = buffer.rpos(); int len = buffer.getInt(); buffer.wpos(buffer.rpos() + len); PublicKey key = buffer.getRawPublicKey(); ServerFactoryManager manager = session.getFactoryManager(); Signature verif = ValidateUtils.checkNotNull( NamedFactory.Utils.create(manager.getSignatureFactories(), alg), "No verifier located for algorithm=%s", alg); verif.initVerifier(key); buffer.wpos(oldLim); byte[] sig = hasSig ? buffer.getBytes() : null; PublickeyAuthenticator authenticator = ValidateUtils.checkNotNull( manager.getPublickeyAuthenticator(), "No PublickeyAuthenticator configured"); if (!authenticator.authenticate(username, key, session)) { return Boolean.FALSE; } if (!hasSig) { Buffer buf = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_PK_OK); buf.putString(alg); buf.putRawBytes(buffer.array(), oldPos, 4 + len); session.writePacket(buf); return null; } else { Buffer buf = new ByteArrayBuffer(); buf.putBytes(session.getKex().getH()); buf.putByte(SshConstants.SSH_MSG_USERAUTH_REQUEST); buf.putString(username); buf.putString(service); buf.putString(UserAuthPublicKeyFactory.NAME); buf.putBoolean(true); buf.putString(alg); buffer.rpos(oldPos); buffer.wpos(oldPos + 4 + len); buf.putBuffer(buffer); verif.update(buf.array(), buf.rpos(), buf.available()); if (!verif.verify(sig)) { throw new Exception("Key verification failed"); } return Boolean.TRUE; } }
public synchronized void write(int c) { buffer.putByte((byte) c); }
// TODO add 'insertXXX' methods to the Buffer class protected Buffer insertCharacter(Buffer org, int c) { int remaining = org.capacity(); int readPos = org.rpos(); // see if can accommodate the character in the original buffer if ((remaining > 0) && (readPos > 0)) { int writePos = org.wpos(); org.wpos(readPos - 1); org.putByte((byte) c); org.wpos(writePos); org.rpos(readPos - 1); return org; } else { Buffer buf = new ByteArrayBuffer(org.available() + Byte.SIZE, false); buf.putByte((byte) c); buf.putBuffer(org); return buf; } }
@Override public synchronized int available() throws IOException { return super.available() + buffer.available(); }