Example #1
0
  private void initDialback(S2SIOService serv, String remote_id) {
    try {
      CID cid = (CID) serv.getSessionData().get("cid");

      String secret = handler.getSecretForDomain(cid.getLocalHost());
      String key =
          Algorithms.generateDialbackKey(
              cid.getLocalHost(), cid.getRemoteHost(), secret, remote_id);

      if (!serv.isHandshakingOnly()) {
        Element elem =
            new Element(
                DB_RESULT_EL_NAME, key, new String[] {XMLNS_DB_ATT}, new String[] {XMLNS_DB_VAL});

        addToResultRequested(serv, cid.getRemoteHost());
        serv.getS2SConnection()
            .addControlPacket(
                Packet.packetInstance(
                    elem,
                    JID.jidInstanceNS(cid.getLocalHost()),
                    JID.jidInstanceNS(cid.getRemoteHost())));
      }
      serv.getS2SConnection().sendAllControlPackets();
    } catch (NotLocalhostException ex) {
      generateStreamError(false, "host-unknown", serv);
    }
  }
Example #2
0
  @Override
  public boolean process(Packet p, S2SIOService serv, Queue<Packet> results) {
    CID cid = (CID) serv.getSessionData().get("cid");
    boolean skipTLS = (cid == null) ? false : skipTLSForHost(cid.getRemoteHost());

    // If this is a dialback packet, process it accordingly
    if (p.getXMLNS() == XMLNS_DB_VAL) {
      if (log.isLoggable(Level.FINEST)) {
        log.log(Level.FINEST, "{0}, Processing dialback packet: {1}", new Object[] {serv, p});
      }
      processDialback(p, serv);

      return true;
    }

    // If this is stream features, then it depends....
    if (p.isElement(FEATURES_EL, FEATURES_NS)) {
      if (log.isLoggable(Level.FINEST)) {
        log.log(Level.FINEST, "{0}, Stream features received packet: {1}", new Object[] {serv, p});
      }

      CertCheckResult certCheckResult =
          (CertCheckResult) serv.getSessionData().get(S2SIOService.CERT_CHECK_RESULT);

      if (log.isLoggable(Level.FINEST)) {
        log.log(
            Level.FINEST,
            "{0}, TLS Certificate check: {1}, packet: {2}",
            new Object[] {serv, certCheckResult, p});
      }

      // If TLS is not yet started (announced in stream features) then it is not
      // the right time for dialback yet
      // Some servers send starttls in stream features, even if TLS is already
      // initialized....
      if (p.isXMLNSStaticStr(FEATURES_STARTTLS_PATH, START_TLS_NS)
          && (certCheckResult == null)
          && !skipTLS) {
        if (log.isLoggable(Level.FINEST)) {
          log.log(Level.FINEST, "{0}, Waiting for starttls, packet: {1}", new Object[] {serv, p});
        }

        return true;
      }

      // If TLS has been started and it is a trusted peer, we do not need
      // dialback here
      // but... sometimes the remote server may request dialback anyway,
      // especially if they
      // do not trust us.
      if ((certCheckResult == CertCheckResult.trusted)
          && !(p.isXMLNSStaticStr(FEATURES_DIALBACK_PATH, DIALBACK_NS))) {
        if (ejabberd_bug_workaround_active) {
          if (log.isLoggable(Level.FINEST)) {
            log.log(
                Level.FINEST,
                "{0}, Ejabberd bug workaround active, proceeding to dialback anyway, packet: {1}",
                new Object[] {serv, p});
          }
        } else {
          if (log.isLoggable(Level.FINEST)) {
            log.log(
                Level.FINEST,
                "{0}, TLS trusted peer, no dialback needed or requested, packet: {1}",
                new Object[] {serv, p});
          }

          CIDConnections cid_conns;

          try {
            cid_conns = handler.getCIDConnections(cid, true);
            cid_conns.connectionAuthenticated(serv, cid);
          } catch (NotLocalhostException ex) {

            // Should not happen....
            log.log(
                Level.INFO, "{0}, Incorrect local hostname, packet: {1}", new Object[] {serv, p});
            serv.forceStop();
          } catch (LocalhostException ex) {

            // Should not happen....
            log.log(
                Level.INFO,
                "{0}, Incorrect remote hostname name, packet: {1}",
                new Object[] {serv, p});
            serv.stop();
          }

          return true;
        }
      }

      // we need to check if TLS is required
      if (!skipTLS
          && cid != null
          && !serv.getSessionData().containsKey("TLS")
          && handler.isTlsRequired(cid.getLocalHost())) {
        log.log(
            Level.FINER,
            "{0}, TLS is required for domain {1} but STARTTLS was not "
                + "offered by {2} - policy-violation",
            new Object[] {serv, cid.getLocalHost(), cid.getRemoteHost()});
        serv.forceStop();
        return true;
      }

      // Nothing else can be done right now except the dialback
      if (log.isLoggable(Level.FINEST)) {
        log.log(Level.FINEST, "{0}, Initializing dialback, packet: {1}", new Object[] {serv, p});
      }
      initDialback(serv, serv.getSessionId());
    }

    return false;
  }
Example #3
0
  private void processDialback(Packet p, S2SIOService serv) {

    // Get the cid for which the connection has been created, the cid calculated
    // from the packet may be different though if the remote server tries to
    // multiplexing
    CID cid_main = (CID) serv.getSessionData().get("cid");
    CID cid_packet = new CID(p.getStanzaTo().getDomain(), p.getStanzaFrom().getDomain());

    if (log.isLoggable(Level.FINEST)) {
      log.log(
          Level.FINEST,
          "{0}, DIALBACK packet: {1}, CID_packet: {2}",
          new Object[] {serv, p, cid_packet});
    }

    CIDConnections cid_conns = null;

    // Some servers (ejabberd) do not send from/to attributes in the stream:open
    // which
    // violates the spec, they seem not to care though, so here we handle the
    // case.
    if (cid_main == null) {

      // This actually can only happen for 'accept' connection type
      // what we did not get in stream open we can get from here
      cid_main = cid_packet;
      serv.getSessionData().put("cid", cid_main);

      // For debuging purposes only....
      serv.getSessionData().put("local-hostname", cid_main.getLocalHost());
      serv.getSessionData().put("remote-hostname", cid_main.getRemoteHost());
    }
    try {
      cid_conns = handler.getCIDConnections(cid_main, true);
    } catch (NotLocalhostException ex) {
      log.log(Level.FINER, "{0} Incorrect local hostname: {1}", new Object[] {serv, p});
      generateStreamError(false, "host-unknown", serv);

      return;
    } catch (LocalhostException ex) {
      log.log(Level.FINER, "{0} Incorrect remote hostname: {1}", new Object[] {serv, p});
      generateStreamError(false, "invalid-from", serv);

      return;
    }
    if (serv.connectionType() == ConnectionType.accept) {
      cid_conns.addIncoming(serv);
    }

    String remote_key = p.getElemCData();

    // Dummy dialback implementation for now....
    if ((p.getElemName() == RESULT_EL_NAME) || (p.getElemName() == DB_RESULT_EL_NAME)) {
      if (p.getType() == null) {
        CID cid = (CID) serv.getSessionData().get("cid");
        boolean skipTls = this.skipTLSForHost(cid.getRemoteHost());
        if (!skipTls
            && !serv.getSessionData().containsKey("TLS")
            && handler.isTlsRequired(cid.getLocalHost())) {
          log.log(
              Level.FINER,
              "{0}, rejecting S2S connection from {1} to {2} due to policy violation - STARTTLS is required",
              new Object[] {serv, cid.getRemoteHost(), cid.getLocalHost()});
          handler.sendVerifyResult(
              DB_RESULT_EL_NAME,
              cid_main,
              cid_packet,
              false,
              null,
              serv.getSessionId(),
              null,
              false,
              new Element(
                  "error",
                  new Element[] {
                    new Element(
                        "policy-violation",
                        new String[] {"xmlns"},
                        new String[] {"urn:ietf:params:xml:ns:xmpp-stanzas"})
                  },
                  new String[] {"type"},
                  new String[] {"cancel"}));
        } else {
          String conn_sessionId = serv.getSessionId();
          handler.sendVerifyResult(
              DB_VERIFY_EL_NAME,
              cid_main,
              cid_packet,
              null,
              conn_sessionId,
              null,
              p.getElemCData(),
              true);
        }
      } else {
        if (p.getType() == StanzaType.valid) {
          if (wasResultRequested(serv, p.getStanzaFrom().toString())) {

            // serv.addCID(new CID(p.getStanzaTo().getDomain(),
            // p.getStanzaFrom().getDomain()));
            cid_conns.connectionAuthenticated(serv, cid_packet);
          } else if (log.isLoggable(Level.FINE)) {
            log.log(
                Level.FINE,
                "Received result with type valid for {0} but it was not requested!",
                p.getStanzaFrom());
          }
        } else {
          if (log.isLoggable(Level.FINE)) {
            log.log(
                Level.FINE,
                "Invalid result for DB authentication: {0}, stopping connection: {1}",
                new Object[] {cid_packet, serv});
          }
          serv.stop();
        }
      }
    }
    if ((p.getElemName() == VERIFY_EL_NAME) || (p.getElemName() == DB_VERIFY_EL_NAME)) {
      if (p.getType() == null) {
        boolean result;
        try {
          String secret = handler.getSecretForDomain(cid_packet.getLocalHost());
          String local_key =
              Algorithms.generateDialbackKey(
                  cid_packet.getLocalHost(), cid_packet.getRemoteHost(), secret, p.getStanzaId());

          if (local_key == null) {
            if (log.isLoggable(Level.FINER)) {
              log.log(
                  Level.FINER,
                  "The key is not available for connection CID: {0}, " + "or the packet CID: {1} ",
                  new Object[] {cid_main, cid_packet});
            }
          }
          result = local_key != null && local_key.equals(remote_key);
        } catch (NotLocalhostException ex) {
          if (log.isLoggable(Level.FINER)) {
            log.log(Level.FINER, "Could not retreive secret for " + cid_packet.getLocalHost(), ex);
          }
          result = false;
        }
        handler.sendVerifyResult(
            DB_VERIFY_EL_NAME,
            cid_main,
            cid_packet,
            result,
            p.getStanzaId(),
            serv.getSessionId(),
            null,
            false);
      } else {
        if (wasVerifyRequested(serv, p.getStanzaFrom().toString())) {
          handler.sendVerifyResult(
              DB_RESULT_EL_NAME,
              cid_main,
              cid_packet,
              (p.getType() == StanzaType.valid),
              null,
              p.getStanzaId(),
              null,
              false);
          if (p.getType() == StanzaType.valid) {
            cid_conns.connectionAuthenticated(p.getStanzaId(), cid_packet);
          }
        } else {
          if (log.isLoggable(Level.FINE)) {
            log.log(
                Level.FINE, "received verify for {0} but it was not requested!", p.getStanzaFrom());
          }
        }
        if (serv.isHandshakingOnly()) {
          serv.stop();
        }
      }
    }
  }