public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException { PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen); Channel c = getChannel(sm.recipientChannelID); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " + sm.recipientChannelID); synchronized (c) { if (c.state != Channel.STATE_OPENING) throw new IOException( "Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " + sm.recipientChannelID); c.remoteID = sm.senderChannelID; c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */ c.remoteMaxPacketSize = sm.maxPacketSize; c.state = Channel.STATE_OPEN; c.notifyAll(); } log.debug( "Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: " + sm.senderChannelID + ")"); }
public void closeChannel(Channel c, String reason, boolean force) throws IOException { byte msg[] = new byte[5]; synchronized (c) { if (force) { c.state = Channel.STATE_CLOSED; c.EOF = true; } c.setReasonClosed(reason); msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; msg[1] = (byte) (c.remoteID >> 24); msg[2] = (byte) (c.remoteID >> 16); msg[3] = (byte) (c.remoteID >> 8); msg[4] = (byte) (c.remoteID); c.notifyAll(); } synchronized (c.channelSendLock) { if (c.closeMessageSent == true) return; tm.sendMessage(msg); c.closeMessageSent = true; } log.debug("Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); }
public void msgChannelClose(byte[] msg, int msglen) throws IOException { if (msglen != 5) throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")"); int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); synchronized (c) { c.EOF = true; c.state = Channel.STATE_CLOSED; c.setReasonClosed("Close requested by remote"); c.closeMessageRecv = true; removeChannel(c.localID); c.notifyAll(); } log.debug("Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); }
public void msgChannelData(byte[] msg, int msglen) throws IOException { if (msglen <= 9) throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")"); int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); if (len != (msglen - 9)) throw new IOException( "SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got " + len + ")"); log.debug("Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); synchronized (c) { if (c.state == Channel.STATE_CLOSED) return; // ignore if (c.state != Channel.STATE_OPEN) throw new IOException( "Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); if (c.localWindow < len) throw new IOException("Remote sent too much data, does not fit into window."); c.localWindow -= len; System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); c.stdoutWritepos += len; c.notifyAll(); } }
public void msgChannelFailure(byte[] msg, int msglen) throws IOException { if (msglen != 5) throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")"); int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); synchronized (c) { c.failedCounter++; c.notifyAll(); } log.debug("Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); }
public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException { if (msglen != 9) throw new IOException( "SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")"); int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); synchronized (c) { final long huge = 0xFFFFffffL; /* 2^32 - 1 */ c.remoteWindow += (windowChange & huge); /* avoid sign extension */ /* TODO - is this a good heuristic? */ if ((c.remoteWindow > huge)) c.remoteWindow = huge; c.notifyAll(); } log.debug("Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); }
public void handleMessage(byte[] msg, int msglen) throws IOException { if (msg == null) { log.debug("HandleMessage: got shutdown"); synchronized (listenerThreads) { for (IChannelWorkerThread lat : listenerThreads) { lat.stopWorking(); } listenerThreadsAllowed = false; } synchronized (channels) { shutdown = true; for (Channel c : channels) { synchronized (c) { c.EOF = true; c.state = Channel.STATE_CLOSED; c.setReasonClosed("The connection is being shutdown"); c.closeMessageRecv = true; /* * You never know, perhaps * we are waiting for a * pending close message * from the server... */ c.notifyAll(); } } channels.clear(); channels.notifyAll(); /* Notify global response waiters */ return; } } switch (msg[0]) { case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: msgChannelOpenConfirmation(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: msgChannelWindowAdjust(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_DATA: msgChannelData(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: msgChannelExtendedData(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_REQUEST: msgChannelRequest(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_EOF: msgChannelEOF(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_OPEN: msgChannelOpen(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_CLOSE: msgChannelClose(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_SUCCESS: msgChannelSuccess(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_FAILURE: msgChannelFailure(msg, msglen); break; case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: msgChannelOpenFailure(msg, msglen); break; case Packets.SSH_MSG_GLOBAL_REQUEST: msgGlobalRequest(msg, msglen); break; case Packets.SSH_MSG_REQUEST_SUCCESS: msgGlobalSuccess(); break; case Packets.SSH_MSG_REQUEST_FAILURE: msgGlobalFailure(); break; default: throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff)); } }
public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException { if (msglen < 5) throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")"); TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); // skip packet type int id = tr.readUINT32(); /* sender channel */ Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); int reasonCode = tr.readUINT32(); String description = tr.readString("UTF-8"); String reasonCodeSymbolicName = null; switch (reasonCode) { case 1: reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; break; case 2: reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; break; case 3: reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; break; case 4: reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; break; default: reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; } StringBuilder descriptionBuffer = new StringBuilder(); descriptionBuffer.append(description); for (int i = 0; i < descriptionBuffer.length(); i++) { char cc = descriptionBuffer.charAt(i); if ((cc >= 32) && (cc <= 126)) continue; descriptionBuffer.setCharAt(i, '\uFFFD'); } synchronized (c) { c.EOF = true; c.state = Channel.STATE_CLOSED; c.setReasonClosed( "The server refused to open the channel (" + reasonCodeSymbolicName + ", '" + descriptionBuffer.toString() + "')"); c.notifyAll(); } log.debug("Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); }
public void msgChannelRequest(byte[] msg, int msglen) throws IOException { TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); // skip packet type int id = tr.readUINT32(); Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); ServerSessionImpl server_session = null; if (server_state != null) { synchronized (c) { server_session = c.ss; } } String type = tr.readString("US-ASCII"); boolean wantReply = tr.readBoolean(); log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); if (type.equals("exit-status")) { if (wantReply != false) throw new IOException( "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-status message, 'want reply' is true"); int exit_status = tr.readUINT32(); if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); synchronized (c) { c.exit_status = new Integer(exit_status); c.notifyAll(); } log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); return; } if ((server_state == null) && (type.equals("exit-signal"))) { if (wantReply != false) throw new IOException( "Badly formatted SSH_MSG_CHANNEL_REQUEST exit-signal message, 'want reply' is true"); String signame = tr.readString("US-ASCII"); tr.readBoolean(); tr.readString(); tr.readString(); if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); synchronized (c) { c.exit_signal = signame; c.notifyAll(); } log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); return; } if ((server_session != null) && (type.equals("pty-req"))) { PtySettings pty = new PtySettings(); pty.term = tr.readString(); pty.term_width_characters = tr.readUINT32(); pty.term_height_characters = tr.readUINT32(); pty.term_width_pixels = tr.readUINT32(); pty.term_height_pixels = tr.readUINT32(); pty.terminal_modes = tr.readByteString(); if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); Runnable run_after_sending_success = null; ServerSessionCallback sscb = server_session.getServerSessionCallback(); if (sscb != null) run_after_sending_success = sscb.requestPtyReq(server_session, pty); if (wantReply) { if (run_after_sending_success != null) { tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); } else { tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); } } if (run_after_sending_success != null) { runAsync(run_after_sending_success); } return; } if ((server_session != null) && (type.equals("shell"))) { if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); Runnable run_after_sending_success = null; ServerSessionCallback sscb = server_session.getServerSessionCallback(); if (sscb != null) run_after_sending_success = sscb.requestShell(server_session); if (wantReply) { if (run_after_sending_success != null) { tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); } else { tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); } } if (run_after_sending_success != null) { runAsync(run_after_sending_success); } return; } if ((server_session != null) && (type.equals("exec"))) { String command = tr.readString(); if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); Runnable run_after_sending_success = null; ServerSessionCallback sscb = server_session.getServerSessionCallback(); if (sscb != null) run_after_sending_success = sscb.requestExec(server_session, command); if (wantReply) { if (run_after_sending_success != null) { tm.sendAsynchronousMessage(new PacketChannelSuccess(c.remoteID).getPayload()); } else { tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); } } if (run_after_sending_success != null) { runAsync(run_after_sending_success); } return; } /* We simply ignore unknown channel requests, however, if the server wants a reply, * then we signal that we have no idea what it is about. */ if (wantReply) { tm.sendAsynchronousMessage(new PacketChannelFailure(c.remoteID).getPayload()); } log.debug("Channel request '" + type + "' is not known, ignoring it"); }
public void msgChannelRequest(byte[] msg, int msglen) throws IOException { TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); // skip packet type int id = tr.readUINT32(); Channel c = getChannel(id); if (c == null) throw new IOException( "Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); String type = tr.readString("US-ASCII"); boolean wantReply = tr.readBoolean(); log.debug("Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); if (type.equals("exit-status")) { if (wantReply != false) throw new IOException( "Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true"); int exit_status = tr.readUINT32(); if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); synchronized (c) { c.exit_status = new Integer(exit_status); c.notifyAll(); } log.debug("Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); return; } if (type.equals("exit-signal")) { if (wantReply != false) throw new IOException( "Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true"); String signame = tr.readString("US-ASCII"); tr.readBoolean(); tr.readString(); tr.readString(); if (tr.remain() != 0) throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); synchronized (c) { c.exit_signal = signame; c.notifyAll(); } log.debug("Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); return; } /* We simply ignore unknown channel requests, however, if the server wants a reply, * then we signal that we have no idea what it is about. */ if (wantReply) { byte[] reply = new byte[5]; reply[0] = Packets.SSH_MSG_CHANNEL_FAILURE; reply[1] = (byte) (c.remoteID >> 24); reply[2] = (byte) (c.remoteID >> 16); reply[3] = (byte) (c.remoteID >> 8); reply[4] = (byte) (c.remoteID); tm.sendAsynchronousMessage(reply); } log.debug("Channel request '" + type + "' is not known, ignoring it"); }