コード例 #1
0
  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
            + ")");
  }
コード例 #2
0
  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 + ")");
  }
コード例 #3
0
  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 + ")");
  }
コード例 #4
0
  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();
    }
  }
コード例 #5
0
  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 + ")");
  }
コード例 #6
0
  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 + ")");
  }
コード例 #7
0
  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));
    }
  }
コード例 #8
0
  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 + ")");
  }
コード例 #9
0
  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");
  }
コード例 #10
0
  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");
  }