Logo Search packages:      
Sourcecode: jabberd14 version File versions  Download package

void dialback_in_read_db ( mio  m,
int  flags,
void *  arg,
xmlnode  x,
char *  unused1,
int  unused2 
)

callback for mio for accepted sockets that are dialback

  • We check if the other host wants to switch to using TLS.
  • We check if the other host wants to verify a dialback connection we made to them
  • We accept db:result element, where the peer wants to authenticate to use a domain
  • We accept stanzas send from a sender the peer has been authorized to use
  • Else we generate a stream:error

Parameters:
m the connection on which the stanza has been read
flags the mio action, should always be MIO_XML_NODE, other actions are ignored
arg the dbic instance of the stream on which the stanza has been read
x the stanza that has been read
unused1 unused/ignored
unused2 unused/ignored

Definition at line 113 of file dialback_in.cc.

References mio_st::authed_other_side, base64_decode(), dbic_struct::d, deliver(), dialback_check_settings(), dialback_in_read(), dialback_merlin(), dialback_miod_read(), dpacket_new(), mio_st::fd, db_struct::hosts_auth, db_struct::hosts_tls, db_struct::i, dbic_struct::id, instance_struct::id, db_struct::in_ok_db, j_strcasecmp(), j_strcmp(), j_strlen(), jutil_tofrom(), log_notice(), log_warn(), miod_struct::m, dbic_struct::m, mio_close(), mio_reset(), mio_ssl_starttls_possible(), mio_ssl_verify(), mio_write(), mio_xml_reset(), mio_xml_starttls(), dbic_struct::other_domain, mio_st::p, pmalloco(), pstrdup(), dbic_struct::results, db_struct::secret, streamerr_struct::severity, dbic_struct::we_domain, xhash_get(), xhash_get_by_domain(), xmlnode_free(), xmlnode_get_attrib_ns(), xmlnode_get_data(), xmlnode_get_firstchild(), xmlnode_get_localname(), xmlnode_get_namespace(), xmlnode_hide(), xmlnode_insert_node(), xmlnode_insert_tag_node(), xmlnode_new_tag_ns(), xmlnode_new_tag_pool_ns(), xmlnode_pool(), xmlnode_put_attrib_ns(), xmlnode_serialize_string(), dbic_struct::xmpp_version, xstream_format_error(), and xstream_parse_error().

Referenced by dialback_in_read().

                                                                                             {
    dbic c = (dbic)arg;
    miod md;
    jid key, from;
    xmlnode x2;

    if(flags != MIO_XML_NODE) return;

    log_debug2(ZONE, LOGT_IO, "dbin read dialback: fd %d packet %s",m->fd, xmlnode_serialize_string(x, xmppd::ns_decl_list(), 0));

    /* incoming stream error? */
    if (j_strcmp(xmlnode_get_localname(x), "error") == 0 && j_strcmp(xmlnode_get_namespace(x), NS_STREAM) == 0) {
        spool s = spool_new(x->p);
        streamerr errstruct = static_cast<streamerr>(pmalloco(x->p, sizeof(_streamerr)));
        char *errmsg = NULL;

        xstream_parse_error(x->p, x, errstruct);
        xstream_format_error(s, errstruct);
        errmsg = spool_print(s);

        switch (errstruct->severity) {
            case normal:
                log_debug2(ZONE, LOGT_IO, "stream error on incoming db conn from %s: %s", mio_ip(m), errmsg);
                break;
            case configuration:
            case feature_lack:
            case unknown:
                log_warn(c->d->i->id, "received stream error on incoming db conn from %s: %s", mio_ip(m), errmsg);
                break;
            case error:
            default:
                log_error(c->d->i->id, "received stream error on incoming db conn from %s: %s", mio_ip(m), errmsg);
        }
      mio_close(m);
      return;
    }

    /* incoming starttls */
    if (j_strcmp(xmlnode_get_localname(x), "starttls") == 0 && j_strcmp(xmlnode_get_namespace(x), NS_XMPP_TLS) == 0) {
      /* starting TLS possible? */
      if (mio_ssl_starttls_possible(m, c->we_domain) && j_strcmp(static_cast<char*>(xhash_get_by_domain(c->d->hosts_tls, c->other_domain)), "no")!=0) {
          /* ACK the start */
          xmlnode proceed = xmlnode_new_tag_ns("proceed", NULL, NS_XMPP_TLS);
          mio_write(m, proceed, NULL, 0);

          /* start TLS on this connection */
          if (mio_xml_starttls(m, 0, c->we_domain) != 0) {
            /* STARTTLS failed */
            mio_close(m);
            return;
          }

          /* we get a stream header again */
          mio_reset(m, dialback_in_read, (void *)c->d);
          
          return;
      } else {
          /* NACK */
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_TLS "'/></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }
    }
    
    /* incoming SASL */
    if (j_strcmp(xmlnode_get_localname(x), "auth") == 0 && j_strcmp(xmlnode_get_namespace(x), NS_XMPP_SASL) == 0) {
      const char *initial_exchange = xmlnode_get_data(x);
      char *decoded_initial_exchange = NULL;
      jid other_side_jid = NULL;

      log_debug2(ZONE, LOGT_IO, "incoming SASL: %s", xmlnode_serialize_string(x, xmppd::ns_decl_list(), 0));

      /* check that the peer is allowed to authenticate using SASL */
      if (j_strcmp(static_cast<char*>(xhash_get_by_domain(c->d->hosts_auth, c->other_domain)), "db") == 0) {
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_SASL "'><invalid-mechanism/></failure><stream:error><policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>This server is configured to not accept SASL auth from your host!</text></stream:error></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }

      /* check that the other end is requesting the EXTERNAL mechanism */
      if (j_strcasecmp(xmlnode_get_attrib_ns(x, "mechanism", NULL), "EXTERNAL") != 0) {
          /* unsupported mechanism */
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_SASL "'><invalid-mechanism/></failure></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }

      /* XXX: empty initial exchange? send empty challenge */
      if (initial_exchange == NULL) {
          /*
          mio_write(m, NULL, "<challenge xmlns='" NS_XMPP_SASL "'>=</challenge>", -1);
          */
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_SASL "'><not-authorized/></failure></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }

      /* decode initial exchange */
      decoded_initial_exchange = static_cast<char*>(pmalloco(x->p, (j_strlen(initial_exchange)+3)/4*3+1));
      base64_decode(initial_exchange, (unsigned char *)decoded_initial_exchange, (j_strlen(initial_exchange)+3)/4*3+1);
      other_side_jid = jid_new(x->p, decoded_initial_exchange);

      /* we only accept servers, no users */
      if (!other_side_jid || other_side_jid->user || other_side_jid->resource) {
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_SASL "'><invalid-authzid/></failure></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }

      /* check if the other host is who it supposes to be */
      if (!mio_ssl_verify(m, jid_full(other_side_jid))) {
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_SASL "'><not-authorized/></failure></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }

      /* check the security settings */
      if (!dialback_check_settings(c->d, c->m, other_side_jid->server, 0, 1, c->xmpp_version)) {
          mio_write(m, NULL, "<failure xmlns='" NS_XMPP_SASL "'><mechanism-too-weak/></failure></stream:stream>", -1);
          mio_close(m);
          xmlnode_free(x);
          return;
      }
      
      /* authorization was successfull! */
      mio_write(m, NULL, "<success xmlns='" NS_XMPP_SASL "'/>", -1);

      /* reset the stream */
      m->authed_other_side = pstrdup(m->p, jid_full(other_side_jid));
      mio_xml_reset(m);
      mio_reset(m, dialback_in_read, (void *)c->d);

      xmlnode_free(x);
      return;
    }

    /* incoming verification request, check and respond */
    if(j_strcmp(xmlnode_get_localname(x),"verify") == 0 && j_strcmp(xmlnode_get_namespace(x), NS_DIALBACK) == 0) {
      char *is = xmlnode_get_data(x);           /* what the peer tries to verify */
      char *should = dialback_merlin(xmlnode_pool(x), c->d->secret, xmlnode_get_attrib_ns(x, "from", NULL), xmlnode_get_attrib_ns(x, "to", NULL), xmlnode_get_attrib_ns(x, "id", NULL));

        if(j_strcmp(is, should) == 0) {
            xmlnode_put_attrib_ns(x, "type", NULL, NULL, "valid");
      } else {
            xmlnode_put_attrib_ns(x, "type", NULL, NULL, "invalid");
          log_notice(c->d->i->id, "Is somebody faking us? %s tried to verify the invalid dialback key %s (should be %s)", xmlnode_get_attrib_ns(x, "from", NULL), is, should);
      }

        /* reformat the packet reply */
        jutil_tofrom(x);
        while((x2 = xmlnode_get_firstchild(x)) != NULL)
            xmlnode_hide(x2); /* hide the contents */
        mio_write(m, x, NULL, 0);
        return;
    }

    /* valid sender/recipient jids */
    if ((from = jid_new(xmlnode_pool(x), xmlnode_get_attrib_ns(x, "from", NULL))) == NULL || (key = jid_new(xmlnode_pool(x), xmlnode_get_attrib_ns(x, "to", NULL))) == NULL) {
        mio_write(m, NULL, "<stream:error><improper-addressing xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>Invalid Packets Recieved!</text></stream:error>", -1);
        mio_close(m);
        xmlnode_free(x);
        return;
    }

    /* make our special key */
    jid_set(key,from->server,JID_RESOURCE);
    jid_set(key,c->id,JID_USER); /* special user of the id attrib makes this key unique */

    /* incoming result, track it and forward on */
    if(j_strcmp(xmlnode_get_localname(x),"result") == 0 && j_strcmp(xmlnode_get_namespace(x), NS_DIALBACK) == 0) {
        /* store the result in the connection, for later validation */
        xmlnode_put_attrib_ns(xmlnode_insert_tag_node(c->results, x), "key", NULL, NULL, jid_full(key));

        /* send the verify back to them, on another outgoing trusted socket, via deliver (so it is real and goes through dnsrv and anything else) */
        x2 = xmlnode_new_tag_pool_ns(xmlnode_pool(x), "verify", "db", NS_DIALBACK);
        xmlnode_put_attrib_ns(x2, "to", NULL, NULL, xmlnode_get_attrib_ns(x, "from", NULL));
        xmlnode_put_attrib_ns(x2, "ofrom", NULL, NULL, xmlnode_get_attrib_ns(x, "to", NULL));
        xmlnode_put_attrib_ns(x2, "from", NULL, NULL, c->d->i->id); /* so bounces come back to us to get tracked */
      xmlnode_put_attrib_ns(x2, "dnsqueryby", NULL, NULL, c->d->i->id); /* so this instance gets the DNS result back */
        xmlnode_put_attrib_ns(x2, "id", NULL, NULL, c->id);
        xmlnode_insert_node(x2, xmlnode_get_firstchild(x)); /* copy in any children */
        deliver(dpacket_new(x2), c->d->i);

        return;
    }

    /* hmm, incoming packet on dialback line, there better be a valid entry for it or else! */
    md = static_cast<miod>(xhash_get(c->d->in_ok_db, jid_full(key)));
    if(md == NULL || md->m != m)
    { /* dude, what's your problem!  *click* */
      log_notice(c->d->i->id, "Received unauthorized stanza for/from %s: %s", jid_full(key), xmlnode_serialize_string(x, xmppd::ns_decl_list(), 0));

        mio_write(m, NULL, "<stream:error><invalid-from xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>Invalid Packets Recieved!</text></stream:error>", -1);
        mio_close(m);
        xmlnode_free(x);
        return;
    }

    dialback_miod_read(md, x);
}


Generated by  Doxygen 1.6.0   Back to index