public PacketDisconnect(byte payload[], int off, int len) throws IOException { this.payload = new byte[len]; System.arraycopy(payload, off, this.payload, 0, len); TypesReader tr = new TypesReader(payload, off, len); int packet_type = tr.readByte(); if (packet_type != Packets.SSH_MSG_DISCONNECT) throw new IOException("This is not a Disconnect Packet! (" + packet_type + ")"); reason = tr.readUINT32(); desc = tr.readString(); lang = tr.readString(); }
public void msgGlobalRequest(byte[] msg, int msglen) throws IOException { /* Currently we do not support any kind of global request */ TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); // skip packet type String requestName = tr.readString(); boolean wantReply = tr.readBoolean(); if (wantReply) { byte[] reply_failure = new byte[1]; reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; tm.sendAsynchronousMessage(reply_failure); } /* We do not clean up the requestName String - that is OK for debug */ log.debug("Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); }
public void receiveLoop() throws IOException { byte[] msg = new byte[35000]; while (true) { int msglen; try { msglen = tc.receiveMessage(msg, 0, msg.length); } catch (SocketTimeoutException e) { // Timeout in read if (idle) { log.debug("Ignoring socket timeout"); continue; } throw e; } idle = true; int type = msg[0] & 0xff; if (type == Packets.SSH_MSG_IGNORE) { continue; } if (type == Packets.SSH_MSG_DEBUG) { if (log.isDebugEnabled()) { TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); tr.readBoolean(); StringBuilder debugMessageBuffer = new StringBuilder(); debugMessageBuffer.append(tr.readString("UTF-8")); for (int i = 0; i < debugMessageBuffer.length(); i++) { char c = debugMessageBuffer.charAt(i); if ((c >= 32) && (c <= 126)) { continue; } debugMessageBuffer.setCharAt(i, '\uFFFD'); } log.debug("DEBUG Message from remote: '" + debugMessageBuffer.toString() + "'"); } continue; } if (type == Packets.SSH_MSG_UNIMPLEMENTED) { throw new IOException("Peer sent UNIMPLEMENTED message, that should not happen."); } if (type == Packets.SSH_MSG_DISCONNECT) { TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); int reason_code = tr.readUINT32(); StringBuilder reasonBuffer = new StringBuilder(); reasonBuffer.append(tr.readString("UTF-8")); /* * Do not get fooled by servers that send abnormal long error * messages */ if (reasonBuffer.length() > 255) { reasonBuffer.setLength(255); reasonBuffer.setCharAt(254, '.'); reasonBuffer.setCharAt(253, '.'); reasonBuffer.setCharAt(252, '.'); } /* * Also, check that the server did not send characters that may * screw up the receiver -> restrict to reasonable US-ASCII * subset -> "printable characters" (ASCII 32 - 126). Replace * all others with 0xFFFD (UNICODE replacement character). */ for (int i = 0; i < reasonBuffer.length(); i++) { char c = reasonBuffer.charAt(i); if ((c >= 32) && (c <= 126)) { continue; } reasonBuffer.setCharAt(i, '\uFFFD'); } throw new IOException( "Peer sent DISCONNECT message (reason code " + reason_code + "): " + reasonBuffer.toString()); } /* * Is it a KEX Packet? */ if ((type == Packets.SSH_MSG_KEXINIT) || (type == Packets.SSH_MSG_NEWKEYS) || ((type >= 30) && (type <= 49))) { km.handleMessage(msg, msglen); continue; } MessageHandler mh = null; for (int i = 0; i < messageHandlers.size(); i++) { HandlerEntry he = messageHandlers.get(i); if ((he.low <= type) && (type <= he.high)) { mh = he.mh; break; } } if (mh == null) { throw new IOException("Unexpected SSH message (type " + type + ")"); } mh.handleMessage(msg, msglen); } }
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 msgChannelOpen(byte[] msg, int msglen) throws IOException { TypesReader tr = new TypesReader(msg, 0, msglen); tr.readByte(); // skip packet type String channelType = tr.readString(); int remoteID = tr.readUINT32(); /* sender channel */ int remoteWindow = tr.readUINT32(); /* initial window size */ int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ if ("x11".equals(channelType)) { synchronized (x11_magic_cookies) { /* If we did not request X11 forwarding, then simply ignore this bogus request. */ if (x11_magic_cookies.size() == 0) { PacketChannelOpenFailure pcof = new PacketChannelOpenFailure( remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); tm.sendAsynchronousMessage(pcof.getPayload()); log.warning("Unexpected X11 request, denying it!"); return; } } String remoteOriginatorAddress = tr.readString(); int remoteOriginatorPort = tr.readUINT32(); Channel c = new Channel(this); synchronized (c) { c.remoteID = remoteID; c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ c.remoteMaxPacketSize = remoteMaxPacketSize; c.localID = addChannel(c); } /* * The open confirmation message will be sent from another thread */ RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); rxat.setDaemon(true); rxat.start(); return; } if ("forwarded-tcpip".equals(channelType)) { String remoteConnectedAddress = tr.readString(); /* address that was connected */ int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ String remoteOriginatorAddress = tr.readString(); /* originator IP address */ int remoteOriginatorPort = tr.readUINT32(); /* originator port */ RemoteForwardingData rfd = null; synchronized (remoteForwardings) { rfd = remoteForwardings.get(new Integer(remoteConnectedPort)); } if (rfd == null) { PacketChannelOpenFailure pcof = new PacketChannelOpenFailure( remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "No thanks, unknown port in forwarded-tcpip request", ""); /* Always try to be polite. */ tm.sendAsynchronousMessage(pcof.getPayload()); log.debug("Unexpected forwarded-tcpip request, denying it!"); return; } Channel c = new Channel(this); synchronized (c) { c.remoteID = remoteID; c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ c.remoteMaxPacketSize = remoteMaxPacketSize; c.localID = addChannel(c); } /* * The open confirmation message will be sent from another thread. */ RemoteAcceptThread rat = new RemoteAcceptThread( c, remoteConnectedAddress, remoteConnectedPort, remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); rat.setDaemon(true); rat.start(); return; } if ((server_state != null) && ("session".equals(channelType))) { ServerConnectionCallback cb = null; synchronized (server_state) { cb = server_state.cb_conn; } if (cb == null) { tm.sendAsynchronousMessage( new PacketChannelOpenFailure( remoteID, Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "Sessions are currently not enabled", "en") .getPayload()); return; } final Channel c = new Channel(this); synchronized (c) { c.remoteID = remoteID; c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ c.remoteMaxPacketSize = remoteMaxPacketSize; c.localID = addChannel(c); c.state = Channel.STATE_OPEN; c.ss = new ServerSessionImpl(c); } PacketChannelOpenConfirmation pcoc = new PacketChannelOpenConfirmation( c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); tm.sendAsynchronousMessage(pcoc.getPayload()); c.ss.sscb = cb.acceptSession(c.ss); return; } /* Tell the server that we have no idea what it is talking about */ PacketChannelOpenFailure pcof = new PacketChannelOpenFailure( remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, "Unknown channel type", ""); tm.sendAsynchronousMessage(pcof.getPayload()); log.warning("The peer tried to open an unsupported channel type (" + channelType + ")"); }
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"); }