Пример #1
0
/** register get handler */
static void _authreg_register_get(c2s_t c2s, sess_t sess, nad_t nad) {
    int attr, ns;
    char id[128];

    /* registrations can happen if reg is enabled and we can create users and set passwords */
    if(sess->active || !(sess->host->ar->set_password != NULL && sess->host->ar->create_user != NULL &&
        (sess->host->ar_register_enable || sess->host->ar_register_oob))) {

        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
        return;
    }

    /* extract the id */
    attr = nad_find_attr(nad, 0, -1, "id", NULL);
    if(attr >= 0)
        snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));

    nad_free(nad);

    /* build a result packet */
    nad = nad_new();

    ns = nad_add_namespace(nad, uri_CLIENT, NULL);

    nad_append_elem(nad, ns, "iq", 0);
    nad_append_attr(nad, -1, "type", "result");

    if(attr >= 0)
        nad_append_attr(nad, -1, "id", id);

    ns = nad_add_namespace(nad, uri_REGISTER, NULL);
    nad_append_elem(nad, ns, "query", 1);
    
    nad_append_elem(nad, ns, "instructions", 2);
    nad_append_cdata(nad, sess->host->ar_register_instructions, strlen(sess->host->ar_register_instructions), 3);

    if(sess->host->ar_register_enable) {
        nad_append_elem(nad, ns, "username", 2);
        nad_append_elem(nad, ns, "password", 2);
    }

    if(sess->host->ar_register_oob) {
        int ns = nad_add_namespace(nad, uri_OOB, NULL);
        nad_append_elem(nad, ns, "x", 2);
        nad_append_elem(nad, ns, "url", 3);
        nad_append_cdata(nad, sess->host->ar_register_oob, strlen(sess->host->ar_register_oob), 4);
    }

    /* give it back to the client */
    sx_nad_write(sess->s, nad);
}
Пример #2
0
static void _router_comp_write(component_t comp, nad_t nad) {
    int attr;

    if(comp->tq != NULL) {
        log_debug(ZONE, "%s port %d is throttled, jqueueing packet", comp->ip, comp->port);
        jqueue_push(comp->tq, nad, 0);
        return;
    }

    /* packets go raw to normal components */
    if(!comp->legacy) {
        sx_nad_write(comp->s, nad);
        return;
    }

    log_debug(ZONE, "packet for legacy component, munging");

    attr = nad_find_attr(nad, 0, -1, "error", NULL);
    if(attr >= 0) {
        if(NAD_AVAL_L(nad, attr) == 3 && strncmp("400", NAD_AVAL(nad, attr), 3) == 0)
            stanza_error(nad, 1, stanza_err_BAD_REQUEST);
        else
            stanza_error(nad, 1, stanza_err_SERVICE_UNAVAILABLE);
    }

    sx_nad_write_elem(comp->s, nad, 1);
}
Пример #3
0
/** tell a component about all the others */
static void _router_advertise_reverse(const char *key, int keylen, void *val, void *arg) {
    component_t dest = (component_t) arg;
    routes_t routes = (routes_t) val;
    int el, ns, i;
    nad_t nad;

    assert((int) (routes->name != NULL));
    assert((int) (routes->comp != NULL));
    assert(routes->ncomp);

    /* don't tell me about myself */
    for(i = 0; i < routes->ncomp; i++)
        if(routes->comp[i] == dest)
            return;

    log_debug(ZONE, "informing component about %.*s", keylen, key);

    /* create a new packet */
    nad = nad_new();
    ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
    el = nad_append_elem(nad, ns, "presence", 0);
    nad_set_attr(nad, el, -1, "from", key, keylen);

    sx_nad_write(dest->s, nad);
}
Пример #4
0
/** send a new action route */
void sm_c2s_action(sess_t dest, const char *action, const char *target) {
    nad_t nad;
    int rns, sns;

    nad = nad_new();

    rns = nad_add_namespace(nad, uri_COMPONENT, NULL);
    nad_append_elem(nad, rns, "route", 0);

    nad_append_attr(nad, -1, "to", dest->c2s);
    nad_append_attr(nad, -1, "from", dest->user->sm->id);

    sns = nad_add_namespace(nad, uri_SESSION, "sc");
    nad_append_elem(nad, sns, "session", 1);

    if (dest->c2s_id[0] != '\0')
        nad_append_attr(nad, sns, "c2s", dest->c2s_id);
    if (dest->sm_id[0] != '\0')
        nad_append_attr(nad, sns, "sm", dest->sm_id);

    nad_append_attr(nad, -1, "action", action);
    if (target != NULL)
        nad_append_attr(nad, -1, "target", target);

    log_debug(ZONE,
              "routing nad to %s from %s c2s %s s2s %s action %s target %s",
              dest->c2s, dest->user->sm->id, dest->c2s_id, dest->sm_id,
              action, target);

    sx_nad_write(dest->user->sm->router, nad);
}
Пример #5
0
/** send a packet to the client for this session */
void sess_route(sess_t sess, pkt_t pkt) {
    int ns;

    log_debug(ZONE, "routing pkt 0x%X to %s (%s) for %s", pkt, sess->c2s, sess->c2s_id, jid_full(sess->jid));

    if(pkt == NULL)
        return;

    /* wrap it up */
    ns = nad_append_namespace(pkt->nad, 1, uri_SESSION, "sm");

    nad_set_attr(pkt->nad, 1, ns, "c2s", sess->c2s_id, 0);
    nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0);

    nad_set_attr(pkt->nad, 0, -1, "to", sess->c2s, 0);
    nad_set_attr(pkt->nad, 0, -1, "from", sess->user->jid->domain, 0);

    /* remove error attribute */
    nad_set_attr(pkt->nad, 0, -1, "error", NULL, 0);

    /* and send it out */
    sx_nad_write(sess->user->sm->router, pkt->nad);

    /* free up the packet */
    if(pkt->rto != NULL) jid_free(pkt->rto);
    if(pkt->rfrom != NULL) jid_free(pkt->rfrom);
    if(pkt->to != NULL) jid_free(pkt->to);
    if(pkt->from != NULL) jid_free(pkt->from);
    free(pkt);
}
Пример #6
0
static void _router_process_unbind(component_t comp, nad_t nad) {
    int attr;
    jid_t name;

    attr = nad_find_attr(nad, 0, -1, "name", NULL);
    if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "no or invalid 'name' on unbind packet, bouncing");
        nad_set_attr(nad, 0, -1, "error", "400", 3);
        sx_nad_write(comp->s, nad);
        return;
    }

    if(xhash_get(comp->routes, name->domain) == NULL) {
        log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to unbind '%s', but it's not bound to this component", comp->ip, comp->port, name->domain);
        nad_set_attr(nad, 0, -1, "name", NULL, 0);
        nad_set_attr(nad, 0, -1, "error", "404", 3);
        sx_nad_write(comp->s, nad);
        jid_free(name);
        return;
    }

    xhash_zap(comp->r->log_sinks, name->domain);
    _route_remove(comp->r->routes, name->domain, comp);
    xhash_zap(comp->routes, name->domain);

    if(comp->r->default_route != NULL && strcmp(comp->r->default_route, name->domain) == 0) {
        log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", name->domain);
        free((void*)(comp->r->default_route));
        comp->r->default_route = NULL;
    }

    log_write(comp->r->log, LOG_NOTICE, "[%s] offline", name->domain);

    nad_set_attr(nad, 0, -1, "name", NULL, 0);
    sx_nad_write(comp->s, nad);

    /* deadvertise name */
    if(xhash_get(comp->r->routes, name->domain) == NULL)
        _router_advertise(comp->r, name->domain, comp, 1);

    jid_free(name);
}
Пример #7
0
static void _router_process_handshake(component_t comp, nad_t nad) {
    char *hash;
    int hashlen;

    /* must have a hash as cdata */
    if(NAD_CDATA_L(nad, 0) != 40) {
        log_debug(ZONE, "handshake isn't long enough to be a sha1 hash");
        sx_error(comp->s, stream_err_NOT_AUTHORIZED, "handshake isn't long enough to be a sha1 hash");
        sx_close(comp->s);

        nad_free(nad);
        return;
    }

    /* make room for shahash_r to work .. needs at least 41 chars */
    hashlen = strlen(comp->s->id) + strlen(comp->r->local_secret) + 1;
    if(hashlen < 41)
        hashlen = 41;

    /* build the creds and hash them */
    hash = (char *) malloc(sizeof(char) * hashlen);
    sprintf(hash, "%s%s", comp->s->id, comp->r->local_secret);
    shahash_r(hash, hash);

    /* check */
    log_debug(ZONE, "checking their hash %.*s against our hash %s", 40, NAD_CDATA(nad, 0), hash);

    if(strncmp(hash, NAD_CDATA(nad, 0), 40) == 0) {
        log_debug(ZONE, "handshake succeeded");

        free(hash);

        /* respond */
        nad->elems[0].icdata = nad->elems[0].itail = -1;
        nad->elems[0].lcdata = nad->elems[0].ltail = 0;
        sx_nad_write(comp->s, nad);

        sx_auth(comp->s, "handshake", comp->s->req_to);
        
        return;
    }
    
    log_debug(ZONE, "auth failed");

    free(hash);

    /* failed, let them know */
    sx_error(comp->s, stream_err_NOT_AUTHORIZED, "hash didn't match, auth failed");
    sx_close(comp->s);

    nad_free(nad);
}
Пример #8
0
/** broadcast a packet */
static void _router_broadcast(const char *key, int keylen, void *val, void *arg) {
    int i;
    broadcast_t bc = (broadcast_t) arg;
    routes_t routes = (routes_t) val;

    for(i = 0; i < routes->ncomp; i++) {
        /* I don't care about myself or the elderly (!?) */
        if(routes->comp[i] == bc->src || routes->comp[i]->legacy)
            continue;

        sx_nad_write(routes->comp[i]->s, nad_copy(bc->nad));
    }
}
Пример #9
0
void sm_packet(sess_t sess, bres_t res, nad_t nad) {
    int ns;

    ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
    nad_wrap_elem(nad, 0, ns, "route");

    nad_set_attr(nad, 0, -1, "to", sess->smcomp?sess->smcomp:((char *) res->jid->domain), 0);
    nad_set_attr(nad, 0, -1, "from", sess->c2s->id, 0);

    ns = nad_append_namespace(nad, 1, uri_SESSION, "sc");

    nad_set_attr(nad, 1, ns, "c2s", res->c2s_id, 0);
    if(res->c2s_id[0] != '\0')
        nad_set_attr(nad, 1, ns, "sm", res->sm_id, 0);

    sx_nad_write(sess->c2s->router, nad);
}
Пример #10
0
Файл: in.c Проект: zipo/zipo
/** they're trying to send us something */
static void _in_packet(conn_t in, nad_t nad) {
    int attr, ns, sns;
    jid_t from, to;
    char *rkey;
    
    attr = nad_find_attr(nad, 0, -1, "from", NULL);
    if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid from on incoming packet");
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "to", NULL);
    if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid to on incoming packet");
        jid_free(from);
        nad_free(nad);
        return;
    }

    rkey = s2s_route_key(NULL, to->domain, from->domain);

    log_debug(ZONE, "received packet from %s for %s", in->key, rkey);

    /* drop packets received on routes not valid on that connection as per XMPP 8.3.10 */
    if((conn_state_t) xhash_get(in->states, rkey) != conn_VALID) {
        log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dropping packet on unvalidated route: '%s'", in->fd->fd, in->ip, in->port, rkey);
        free(rkey);
        nad_free(nad);
        jid_free(from);
        jid_free(to);
        return;
    }

    free(rkey);

    /* its good, off to the router with it */

    log_debug(ZONE, "incoming packet on valid route, preparing it for the router");

    /* rewrite server packets into client packets */
    ns = nad_find_namespace(nad, 0, uri_SERVER, NULL);
    if(ns >= 0) {
        if(nad->elems[0].ns == ns)
            nad->elems[0].ns = nad->nss[nad->elems[0].ns].next;
        else {
            for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next);
            nad->nss[sns].next = nad->nss[nad->nss[sns].next].next;
        }
    }

    /*
     * If stanza is not in any namespace (either because we removed the
     * jabber:server namespace above or because it's in the default
     * namespace for this stream) then this packet is intended to be
     * handled by sm (and not just routed through the server), so set the
     * jabber:client namespace.
     */
    if(ns >= 0 || nad->elems[0].ns < 0) {
        ns = nad_add_namespace(nad, uri_CLIENT, NULL);
        nad->scope = -1;
        nad->nss[ns].next = nad->elems[0].ns;
        nad->elems[0].ns = ns;
    }

    nad->elems[0].my_ns = nad->elems[0].ns;

    /* wrap up the packet */
    ns = nad_add_namespace(nad, uri_COMPONENT, "comp");

    nad_wrap_elem(nad, 0, ns, "route");

    nad_set_attr(nad, 0, -1, "to", to->domain, 0);
    nad_set_attr(nad, 0, -1, "from", in->s2s->id, 0);   /* route is from s2s, not packet source */

    log_debug(ZONE, "sending packet to %s", to->domain);

    /* go */
    sx_nad_write(in->s2s->router, nad);

    jid_free(from);
    jid_free(to);
}
Пример #11
0
/** auth get handler */
static void _authreg_auth_get(c2s_t c2s, sess_t sess, nad_t nad) {
    int ns, elem, attr;
    char username[1024], id[128];
    int ar_mechs;

    /* can't auth if they're active */
    if(sess->active) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
        return;
    }

    /* sort out the username */
    ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL);
    elem = nad_find_elem(nad, 1, ns, "username", 1);
    if(elem < 0)
    {
        log_debug(ZONE, "auth get with no username, bouncing it");

        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));

        return;
    }

    snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
    if(stringprep_xmpp_nodeprep(username, 1024) != 0) {
        log_debug(ZONE, "auth get username failed nodeprep, bouncing it");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0));
        return;
    }

    ar_mechs = c2s->ar_mechanisms;
    if (sess->s->ssf>0) 
        ar_mechs = ar_mechs | c2s->ar_ssl_mechanisms;
        
    /* no point going on if we have no mechanisms */
    if(!(ar_mechs & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST))) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0));
        return;
    }
    
    /* do we have the user? */
    if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm) == 0) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0));
        return;
    }

    /* extract the id */
    attr = nad_find_attr(nad, 0, -1, "id", NULL);
    if(attr >= 0)
        snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));

    nad_free(nad);

    /* build a result packet */
    nad = nad_new();

    ns = nad_add_namespace(nad, uri_CLIENT, NULL);

    nad_append_elem(nad, ns, "iq", 0);
    nad_append_attr(nad, -1, "type", "result");

    if(attr >= 0)
        nad_append_attr(nad, -1, "id", id);

    ns = nad_add_namespace(nad, uri_AUTH, NULL);
    nad_append_elem(nad, ns, "query", 1);
    
    nad_append_elem(nad, ns, "username", 2);
    nad_append_cdata(nad, username, strlen(username), 3);

    nad_append_elem(nad, ns, "resource", 2);

    /* fill out the packet with available auth mechanisms */
    if(ar_mechs & AR_MECH_TRAD_PLAIN && (c2s->ar->get_password != NULL || c2s->ar->check_password != NULL))
        nad_append_elem(nad, ns, "password", 2);

    if(ar_mechs & AR_MECH_TRAD_DIGEST && c2s->ar->get_password != NULL)
        nad_append_elem(nad, ns, "digest", 2);

    /* give it back to the client */
    sx_nad_write(sess->s, nad);

    return;
}
Пример #12
0
/** auth set handler */
static void _authreg_auth_set(c2s_t c2s, sess_t sess, nad_t nad) {
    int ns, elem, attr, authd = 0;
    char username[1024], resource[1024], str[1024], hash[280];
    int ar_mechs;

    /* can't auth if they're active */
    if(sess->active) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
        return;
    }

    ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL);

    /* sort out the username */
    elem = nad_find_elem(nad, 1, ns, "username", 1);
    if(elem < 0)
    {
        log_debug(ZONE, "auth set with no username, bouncing it");

        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));

        return;
    }

    snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
    if(stringprep_xmpp_nodeprep(username, 1024) != 0) {
        log_debug(ZONE, "auth set username failed nodeprep, bouncing it");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0));
        return;
    }

    /* make sure we have the resource */
    elem = nad_find_elem(nad, 1, ns, "resource", 1);
    if(elem < 0)
    {
        log_debug(ZONE, "auth set with no resource, bouncing it");

        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));

        return;
    }

    snprintf(resource, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
    if(stringprep_xmpp_resourceprep(resource, 1024) != 0) {
        log_debug(ZONE, "auth set resource failed resourceprep, bouncing it");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0));
        return;
    }

    ar_mechs = c2s->ar_mechanisms;
    if (sess->s->ssf > 0)
        ar_mechs = ar_mechs | c2s->ar_ssl_mechanisms;
    
    /* no point going on if we have no mechanisms */
    if(!(ar_mechs & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST))) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0));
        return;
    }
    
    /* do we have the user? */
    if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm) == 0) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0));
        return;
    }
    
    /* digest auth */
    if(!authd && ar_mechs & AR_MECH_TRAD_DIGEST && c2s->ar->get_password != NULL)
    {
        elem = nad_find_elem(nad, 1, ns, "digest", 1);
        if(elem >= 0)
        {
            if((c2s->ar->get_password)(c2s->ar, username, sess->host->realm, str) == 0)
            {
                snprintf(hash, 280, "%s%s", sess->s->id, str);
                shahash_r(hash, hash);

                if(strlen(hash) == NAD_CDATA_L(nad, elem) && strncmp(hash, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0)
                {
                    log_debug(ZONE, "digest auth succeeded");
                    authd = 1;
                    _authreg_auth_log(c2s, sess, "traditional.digest", username, resource, TRUE);
                }
            }
        }
    }

    /* plaintext auth (compare) */
    if(!authd && ar_mechs & AR_MECH_TRAD_PLAIN && c2s->ar->get_password != NULL)
    {
        elem = nad_find_elem(nad, 1, ns, "password", 1);
        if(elem >= 0)
        {
            if((c2s->ar->get_password)(c2s->ar, username, sess->host->realm, str) == 0 && strlen(str) == NAD_CDATA_L(nad, elem) && strncmp(str, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0)
            {
                log_debug(ZONE, "plaintext auth (compare) succeeded");
                authd = 1;
                _authreg_auth_log(c2s, sess, "traditional.plain(compare)", username, resource, TRUE);
            }
        }
    }

    /* plaintext auth (check) */
    if(!authd && ar_mechs & AR_MECH_TRAD_PLAIN && c2s->ar->check_password != NULL)
    {
        elem = nad_find_elem(nad, 1, ns, "password", 1);
        if(elem >= 0)
        {
            snprintf(str, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
            if((c2s->ar->check_password)(c2s->ar, username, sess->host->realm, str) == 0)
            {
                log_debug(ZONE, "plaintext auth (check) succeded");
                authd = 1;
                _authreg_auth_log(c2s, sess, "traditional.plain", username, resource, TRUE);
            }
        }
    }

    /* now, are they authenticated? */
    if(authd)
    {
        /* create new bound jid holder */
        if(sess->resources == NULL) {
            sess->resources = (bres_t) calloc(1, sizeof(struct bres_st));
        }

        /* our local id */
        sprintf(sess->resources->c2s_id, "%d", sess->s->tag);

        /* the full user jid for this session */
        sess->resources->jid = jid_new(sess->s->req_to, -1);
        jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, resource);

        log_write(sess->c2s->log, LOG_NOTICE, "[%d] requesting session: jid=%s", sess->s->tag, jid_full(sess->resources->jid));

        /* build a result packet, we'll send this back to the client after we have a session for them */
        sess->result = nad_new();

        ns = nad_add_namespace(sess->result, uri_CLIENT, NULL);

        nad_append_elem(sess->result, ns, "iq", 0);
        nad_set_attr(sess->result, 0, -1, "type", "result", 6);

        attr = nad_find_attr(nad, 0, -1, "id", NULL);
        if(attr >= 0)
            nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));

        /* start a session with the sm */
        sm_start(sess, sess->resources);

        /* finished with the nad */
        nad_free(nad);

        return;
    }

    _authreg_auth_log(c2s, sess, "traditional", username, resource, FALSE);

    /* auth failed, so error */
    sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0));

    return;
}
Пример #13
0
/** register set handler */
static void _authreg_register_set(c2s_t c2s, sess_t sess, nad_t nad)
{
    int ns = 0, elem, attr;
    char username[1024], password[1024];

    /* if we're not configured for registration (or pw changes), or we can't set passwords, fail outright */
    if(!(sess->host->ar_register_enable || sess->host->ar_register_password) || c2s->ar->set_password == NULL) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
        return;
    }

    ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL);

    /* removals */
    if(sess->active && nad_find_elem(nad, 1, ns, "remove", 1) >= 0) {
        /* only if full reg is enabled */
        if(!sess->host->ar_register_enable) {
            sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
            return;
        }

        log_debug(ZONE, "user remove requested");

        /* make sure we can delete them */
        if(c2s->ar->delete_user == NULL) {
            sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
            return;
        }

        /* otherwise, delete them */
        if((c2s->ar->delete_user)(c2s->ar, sess->resources->jid->node, sess->host->realm) != 0) {
            log_debug(ZONE, "user delete failed");
            sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0));
            return;
        }

        log_write(c2s->log, LOG_NOTICE, "[%d] deleted user: user=%s; realm=%s", sess->s->tag, sess->resources->jid->node, sess->host->realm);

        log_write(c2s->log, LOG_NOTICE, "[%d] registration remove succeeded, requesting user deletion: jid=%s", sess->s->tag, jid_user(sess->resources->jid));

        /* make a result nad */
        sess->result = nad_new();

        ns = nad_add_namespace(sess->result, uri_CLIENT, NULL);

        nad_append_elem(sess->result, ns, "iq", 0);
        nad_set_attr(sess->result, 0, -1, "type", "result", 6);

        /* extract the id */
        attr = nad_find_attr(nad, 0, -1, "id", NULL);
        if(attr >= 0)
            nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));

        nad_free(nad);

        sx_nad_write(sess->s, sess->result);
        sess->result = NULL;

        /* get the sm to delete them (it will force their sessions to end) */
        sm_delete(sess, sess->resources);

        return;
    }

    /* username is required */
    elem = nad_find_elem(nad, 1, ns, "username", 1);
    if(elem < 0)
    {
        log_debug(ZONE, "register set with no username, bouncing it");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));
        return;
    }

    snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
    if(stringprep_xmpp_nodeprep(username, 1024) != 0) {
        log_debug(ZONE, "register set username failed nodeprep, bouncing it");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0));
        return;
    }

    elem = nad_find_elem(nad, 1, ns, "password", 1);
    if(elem < 0)
    {
        log_debug(ZONE, "register set with no password, bouncing it");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));
        return;
    }

    /* if they're already auth'd, its a password change */
    if(sess->active)
    {
        /* confirm that the username matches their auth id */
        if(strcmp(username, sess->resources->jid->node) != 0)
        {
            log_debug(ZONE, "%s is trying to change password for %s, bouncing it", jid_full(sess->resources->jid), username);
            sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0));
            return;
        }
    }

    /* can't go on if we're not doing full reg */
    else if(!sess->host->ar_register_enable) {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
        return;
    }

    /* if they exist, bounce */
    else if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm))
    {
        log_debug(ZONE, "attempt to register %s, but they already exist", username);
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_CONFLICT), 0));
        return;
    }

    /* make sure we can create them */
    else if(c2s->ar->create_user == NULL)
    {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
        return;
    }

    /* otherwise, create them */
    else if((c2s->ar->create_user)(c2s->ar, username, sess->host->realm) != 0)
    {
        log_debug(ZONE, "user create failed");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0));
        return;
    }

    else
        log_write(c2s->log, LOG_NOTICE, "[%d] created user: user=%s; realm=%s", sess->s->tag, username, sess->host->realm);

    /* extract the password */
    snprintf(password, 257, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));

    /* change it */
    if((c2s->ar->set_password)(c2s->ar, username, sess->host->realm, password) != 0)
    {
        log_debug(ZONE, "password store failed");
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0));
        return;
    }

    log_debug(ZONE, "updated auth creds for %s", username);

    /* make a result nad */
    sess->result = nad_new();

    ns = nad_add_namespace(sess->result, uri_CLIENT, NULL);

    nad_append_elem(sess->result, ns, "iq", 0);
    nad_set_attr(sess->result, 0, -1, "type", "result", 6);

    /* extract the id */
    attr = nad_find_attr(nad, 0, -1, "id", NULL);
    if(attr >= 0)
        nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));

    /* if they're active, then this was just a password change, and we're done */
    if(sess->active) {
        log_write(c2s->log, LOG_NOTICE, "[%d] password changed: jid=%s", sess->s->tag, jid_user(sess->resources->jid));
        sx_nad_write(sess->s, sess->result);
        sess->result = NULL;
        return;
    }

    /* create new bound jid holder */
    if(sess->resources == NULL) {
        sess->resources = (bres_t) calloc(1, sizeof(struct bres_st));
    }

    /* our local id */
    sprintf(sess->resources->c2s_id, "%d", sess->s->tag);

    /* the user jid for this transaction */
    sess->resources->jid = jid_new(sess->s->req_to, -1);
    jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, sess->resources->jid->resource);

    log_write(c2s->log, LOG_NOTICE, "[%d] registration succeeded, requesting user creation: jid=%s", sess->s->tag, jid_user(sess->resources->jid));

    /* get the sm to create them */
    sm_create(sess, sess->resources);

    nad_free(nad);

    return;
}
Пример #14
0
static void _router_process_bind(component_t comp, nad_t nad) {
    int attr, multi, n;
    jid_t name;
    alias_t alias;
    char *user, *c;

    attr = nad_find_attr(nad, 0, -1, "name", NULL);
    if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "no or invalid 'name' on bind packet, bouncing");
        nad_set_attr(nad, 0, -1, "error", "400", 3);
        sx_nad_write(comp->s, nad);
        return;
    }

    user = strdup(comp->s->auth_id);
    c = strchr(user, '@');
    if(c != NULL) *c = '\0';

    if(strcmp(user, name->domain) != 0 && !aci_check(comp->r->aci, "bind", user)) {
        log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but their username (%s) is not permitted to bind other names", comp->ip, comp->port, name->domain, user);
        nad_set_attr(nad, 0, -1, "name", NULL, 0);
        nad_set_attr(nad, 0, -1, "error", "403", 3);
        sx_nad_write(comp->s, nad);
        jid_free(name);
        free(user);
        return;
    }

    multi = nad_find_attr(nad, 0, -1, "multi", NULL);
    if(xhash_get(comp->r->routes, name->domain) != NULL && multi < 0) {
        log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but it's already bound", comp->ip, comp->port, name->domain);
        nad_set_attr(nad, 0, -1, "name", NULL, 0);
        nad_set_attr(nad, 0, -1, "error", "409", 3);
        sx_nad_write(comp->s, nad);
        jid_free(name);
        free(user);
        return;
    }

    for(alias = comp->r->aliases; alias != NULL; alias = alias->next)
        if(strcmp(alias->name, name->domain) == 0) {
            log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but that name is aliased", comp->ip, comp->port);
            nad_set_attr(nad, 0, -1, "name", NULL, 0);
            nad_set_attr(nad, 0, -1, "error", "409", 3);
            sx_nad_write(comp->s, nad);
            jid_free(name);
            free(user);
            return;
        }

    /* default route */
    if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "default", 1) >= 0) {
        if(!aci_check(comp->r->aci, "default-route", user)) {
            log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but their username (%s) is not permitted to set a default route", comp->ip, comp->port, name->domain, user);
            nad_set_attr(nad, 0, -1, "name", NULL, 0);
            nad_set_attr(nad, 0, -1, "error", "403", 3);
            sx_nad_write(comp->s, nad);
            jid_free(name);
            free(user);
            return;
        }

        if(comp->r->default_route != NULL) {
            log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but one already exists", comp->ip, comp->port, name->domain);
            nad_set_attr(nad, 0, -1, "name", NULL, 0);
            nad_set_attr(nad, 0, -1, "error", "409", 3);
            sx_nad_write(comp->s, nad);
            jid_free(name);
            return;
        }

        log_write(comp->r->log, LOG_NOTICE, "[%s] set as default route", name->domain);

        comp->r->default_route = strdup(name->domain);
    }

    /* log sinks */
    if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "log", 1) >= 0) {
        if(!aci_check(comp->r->aci, "log", user)) {
            log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as a log sink, but their username (%s) is not permitted to do this", comp->ip, comp->port, name->domain, user);
            nad_set_attr(nad, 0, -1, "name", NULL, 0);
            nad_set_attr(nad, 0, -1, "error", "403", 3);
            sx_nad_write(comp->s, nad);
            jid_free(name);
            free(user);
            return;
        }

        log_write(comp->r->log, LOG_NOTICE, "[%s] set as log sink", name->domain);

        xhash_put(comp->r->log_sinks, pstrdup(xhash_pool(comp->r->log_sinks), name->domain), (void *) comp);
    }

    free(user);

    n = _route_add(comp->r->routes, name->domain, comp, multi<0?route_SINGLE:route_MULTI_TO);
    xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), name->domain), (void *) comp);

    if(n>1)
        log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", name->domain, n, comp->ip, comp->port);
    else
        log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", name->domain, comp->ip, comp->port);

    nad_set_attr(nad, 0, -1, "name", NULL, 0);
    sx_nad_write(comp->s, nad);

    /* advertise name */
    _router_advertise(comp->r, name->domain, comp, 0);

    /* tell the new component about everyone else */
    xhash_walk(comp->r->routes, _router_advertise_reverse, (void *) comp);

    /* bind aliases */
    for(alias = comp->r->aliases; alias != NULL; alias = alias->next) {
        if(strcmp(alias->target, name->domain) == 0) {
            _route_add(comp->r->routes, name->domain, comp, route_MULTI_TO);
            xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp);
            
            log_write(comp->r->log, LOG_NOTICE, "[%s] online (alias of '%s', bound to %s, port %d)", alias->name, name->domain, comp->ip, comp->port);

            /* advertise name */
            _router_advertise(comp->r, alias->name, comp, 0);
        }
    }

    /* done with this */
    jid_free(name);
}
Пример #15
0
void sm_create(sess_t sess, bres_t res) {
    _sm_generate_id(sess, res, "create");

    sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "create", jid_user(res->jid), res->sm_request));
}
Пример #16
0
void sm_delete(sess_t sess, bres_t res) {
    sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "delete", jid_user(res->jid), NULL));
}
Пример #17
0
void sm_start(sess_t sess, bres_t res) {
    _sm_generate_id(sess, res, "start");

    sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "start", jid_full(res->jid), res->sm_request));
}
Пример #18
0
void sm_end(sess_t sess, bres_t res) {
    sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "end", NULL, NULL));
}
Пример #19
0
/**
 * processor for iq:auth and iq:register packets
 * return 0 if handled, 1 if not handled
 */
int authreg_process(c2s_t c2s, sess_t sess, nad_t nad) {
    int ns, query, type, authreg = -1, getset = -1;

    /* need iq */
    if(NAD_ENAME_L(nad, 0) != 2 || strncmp("iq", NAD_ENAME(nad, 0), 2) != 0)
        return 1;

    /* only want auth or register packets */
    if((ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL)) >= 0 && (query = nad_find_elem(nad, 0, ns, "query", 1)) >= 0)
        authreg = 0;
    else if((ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL)) >= 0 && (query = nad_find_elem(nad, 0, ns, "query", 1)) >= 0)
        authreg = 1;
    else
        return 1;

    /* if its to someone else, pass it */
    if(nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "to", sess->s->req_to) < 0)
        return 1;

    /* need a type */
    if((type = nad_find_attr(nad, 0, -1, "type", NULL)) < 0 || NAD_AVAL_L(nad, type) != 3)
    {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));
        return 0;
    }

    /* get or set? */
    if(strncmp("get", NAD_AVAL(nad, type), NAD_AVAL_L(nad, type)) == 0)
        getset = 0;
    else if(strncmp("set", NAD_AVAL(nad, type), NAD_AVAL_L(nad, type)) == 0)
        getset = 1;
    else
    {
        sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0));
        return 0;
    }

    /* hand to the correct handler */
    if(authreg == 0) {
        /* can't do iq:auth after sasl auth */
        if(sess->sasl_authd) {
            sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0));
            return 0;
        }

        if(getset == 0) {
            log_debug(ZONE, "auth get");
            _authreg_auth_get(c2s, sess, nad);
        } else if(getset == 1) {
            log_debug(ZONE, "auth set");
            _authreg_auth_set(c2s, sess, nad);
        }
    }

    if(authreg == 1) {
        if(getset == 0) {
            log_debug(ZONE, "register get");
            _authreg_register_get(c2s, sess, nad);
        } else if(getset == 1) {
            log_debug(ZONE, "register set");
            _authreg_register_set(c2s, sess, nad);
        }
    }

    /* handled */
    return 0;
}
Пример #20
0
Файл: in.c Проект: zipo/zipo
/** validate their key */
static void _in_verify(conn_t in, nad_t nad) {
    int attr;
    jid_t from, to;
    char *id, *dbkey, *type;
    
    attr = nad_find_attr(nad, 0, -1, "from", NULL);
    if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid from on db verify packet");
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "to", NULL);
    if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid to on db verify packet");
        jid_free(from);
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "id", NULL);
    if(attr < 0) {
        log_debug(ZONE, "missing id on db verify packet");
        jid_free(from);
        jid_free(to);
        nad_free(nad);
        return;
    }

    if(NAD_CDATA_L(nad, 0) <= 0) {
        log_debug(ZONE, "no cdata on db verify packet");
        jid_free(from);
        jid_free(to);
        nad_free(nad);
        return;
    }

    /* extract the id */
    id = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, attr) + 1));
    snprintf(id, NAD_AVAL_L(nad, attr) + 1, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));

    /* generate a dialback key */
    dbkey = s2s_db_key(NULL, in->s2s->local_secret, from->domain, id);

    /* valid */
    if(NAD_CDATA_L(nad, 0) == strlen(dbkey) && strncmp(dbkey, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)) == 0) {
        log_debug(ZONE, "valid dialback key %s, verify succeeded", dbkey);
        type = "valid";
    } else {
        log_debug(ZONE, "invalid dialback key %s, verify failed", dbkey);
        type = "invalid";
    }

    log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] checking dialback verification from %s: sending %s", in->fd->fd, in->ip, in->port, from->domain, type);

    log_debug(ZONE, "letting them know");

    /* now munge the packet and send it back to them */
    stanza_tofrom(nad, 0);
    nad_set_attr(nad, 0, -1, "type", type, 0);
    nad->elems[0].icdata = nad->elems[0].itail = -1;
    nad->elems[0].lcdata = nad->elems[0].ltail = 0;

    sx_nad_write(in->s, nad);

    free(dbkey);
    free(id);

    jid_free(from);
    jid_free(to);

    return;
}
Пример #21
0
Файл: in.c Проект: zipo/zipo
/** auth requests */
static void _in_result(conn_t in, nad_t nad) {
    int attr, ns;
    jid_t from, to;
    char *rkey;
    nad_t verify;
    pkt_t pkt;
    time_t now;

    attr = nad_find_attr(nad, 0, -1, "from", NULL);
    if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid from on db result packet");
        nad_free(nad);
        return;
    }

    attr = nad_find_attr(nad, 0, -1, "to", NULL);
    if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
        log_debug(ZONE, "missing or invalid to on db result packet");
        jid_free(from);
        nad_free(nad);
        return;
    }

    rkey = s2s_route_key(NULL, to->domain, from->domain);

    log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] received dialback auth request for route '%s'", in->fd->fd, in->ip, in->port, rkey);

    /* get current state */
    if((conn_state_t) xhash_get(in->states, rkey) == conn_VALID) {
        log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] route '%s' is already valid: sending valid", in->fd->fd, in->ip, in->port, rkey);

        /* its already valid, just reply right now */
        stanza_tofrom(nad, 0);
        nad_set_attr(nad, 0, -1, "type", "valid", 5);
        nad->elems[0].icdata = nad->elems[0].itail = -1;
        nad->elems[0].lcdata = nad->elems[0].ltail = 0;

        sx_nad_write(in->s, nad);

        free(rkey);

        jid_free(from);
        jid_free(to);

        return;
    }

    /* not valid, so we need to verify */

    /* need the key */
    if(NAD_CDATA_L(nad, 0) <= 0) {
        log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback key given with db result packet", in->fd->fd, in->ip, in->port, rkey);
        free(rkey);
        nad_free(nad);
        jid_free(from);
        jid_free(to);
        return;
    }

    log_debug(ZONE, "requesting verification for route %s", rkey);

    /* set the route status to INPROGRESS and set timestamp */
    xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_INPROGRESS);

    /* record the time that we set conn_INPROGRESS state */
    now = time(NULL);
    xhash_put(in->states_time, pstrdup(xhash_pool(in->states_time), rkey), (void *) now);

    free(rkey);

    /* new packet */
    verify = nad_new();
    ns = nad_add_namespace(verify, uri_DIALBACK, "db");

    nad_append_elem(verify, ns, "verify", 0);
    nad_append_attr(verify, -1, "to", from->domain);
    nad_append_attr(verify, -1, "from", to->domain);
    nad_append_attr(verify, -1, "id", in->s->id);
    nad_append_cdata(verify, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0), 1);

    /* new packet */
    pkt = (pkt_t) calloc(1, sizeof(struct pkt_st));

    pkt->nad = verify;

    pkt->to = from;
    pkt->from = to;

    pkt->db = 1;

    /* its away */
    out_packet(in->s2s, pkt);

    nad_free(nad);
}
Пример #22
0
/** our master callback */
int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
    sm_t sm = (sm_t) arg;
    sx_buf_t buf = (sx_buf_t) data;
    sx_error_t *sxe;
    nad_t nad;
    pkt_t pkt;
    int len, ns, elem, attr;
    char *domain;

    switch(e) {
        case event_WANT_READ:
            log_debug(ZONE, "want read");
            mio_read(sm->mio, sm->fd);
            break;

        case event_WANT_WRITE:
            log_debug(ZONE, "want write");
            mio_write(sm->mio, sm->fd);
            break;

        case event_READ:
            log_debug(ZONE, "reading from %d", sm->fd->fd);

            /* do the read */
            len = recv(sm->fd->fd, buf->data, buf->len, 0);

            if (len < 0) {
                if (MIO_WOULDBLOCK) {
                    buf->len = 0;
                    return 0;
                }

                log_write(sm->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);

                sx_kill(s);
                
                return -1;
            }

            else if (len == 0) {
                /* they went away */
                sx_kill(s);

                return -1;
            }

            log_debug(ZONE, "read %d bytes", len);

            buf->len = len;

            return len;

        case event_WRITE:
            log_debug(ZONE, "writing to %d", sm->fd->fd);

            len = send(sm->fd->fd, buf->data, buf->len, 0);
            if (len >= 0) {
                log_debug(ZONE, "%d bytes written", len);
                return len;
            }

            if (MIO_WOULDBLOCK)
                return 0;

            log_write(sm->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);

            sx_kill(s);

            return -1;

        case event_ERROR:
            sxe = (sx_error_t *) data;
            log_write(sm->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific);

            if(sxe->code == SX_ERR_AUTH)
                sx_close(s);

            break;

        case event_STREAM:
            break;

        case event_OPEN:
            log_write(sm->log, LOG_NOTICE, "connection to router established");

            /* set connection attempts counter */
            sm->retry_left = sm->retry_lost;

            nad = nad_new();
            ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
            nad_append_elem(nad, ns, "bind", 0);
            nad_append_attr(nad, -1, "name", sm->id);
            log_debug(ZONE, "requesting component bind for '%s'", sm->id);
            sx_nad_write(sm->router, nad);
            
            if(xhash_iter_first(sm->hosts))
            do {
                xhash_iter_get(sm->hosts, (void *) &domain, &len, NULL);

                /* skip already requested SM id */
                if (strlen(sm->id) == len && strncmp(sm->id, domain, len) == 0)
                    continue;

                nad = nad_new();
                ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
                elem = nad_append_elem(nad, ns, "bind", 0);
                nad_set_attr(nad, elem, -1, "name", domain, len);
                nad_append_attr(nad, -1, "multi", "to");
                log_debug(ZONE, "requesting domain bind for '%.*s'", len, domain);
                sx_nad_write(sm->router, nad);
            } while(xhash_iter_next(sm->hosts));
            
            sm_update_host = 1;
            
            break;

        case event_PACKET:
            nad = (nad_t) data;

            /* drop unqualified packets */
            if (NAD_ENS(nad, 0) < 0) {
                nad_free(nad);
                return 0;
            }
            /* watch for the features packet */
            if (s->state == state_STREAM) {
                if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS)
                    || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0
                    || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) {
                    log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping");
                    nad_free(nad);
                    return 0;
                }

#ifdef HAVE_SSL
                /* starttls if we can */
                if (sm->sx_ssl != NULL && s->ssf == 0) {
                    ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
                    if (ns >= 0) {
                        elem = nad_find_elem(nad, 0, ns, "starttls", 1);
                        if (elem >= 0) {
                            if (sx_ssl_client_starttls(sm->sx_ssl, s, NULL, NULL) == 0) {
                                nad_free(nad);
                                return 0;
                            }
                            log_write(sm->log, LOG_NOTICE, "unable to establish encrypted session with router");
                        }
                    }
                }
#endif

                /* !!! pull the list of mechanisms, and choose the best one.
                 *     if there isn't an appropriate one, error and bail */

                /* authenticate */
                sx_sasl_auth(sm->sx_sasl, s, "jabberd-router", "DIGEST-MD5", sm->router_user, sm->router_pass);

                nad_free(nad);
                return 0;
            }

            /* watch for the bind response */
            if (s->state == state_OPEN && !sm->online) {
                if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT)
                    || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0
                    || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) {
                    log_debug(ZONE, "got a packet from router, but we're not online, dropping");
                    nad_free(nad);
                    return 0;
                }

                /* catch errors */
                attr = nad_find_attr(nad, 0, -1, "error", NULL);
                if(attr >= 0) {
                    log_write(sm->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
                    exit(1);
                }

                log_debug(ZONE, "coming online");

                /* we're online */
                sm->online = sm->started = 1;
                log_write(sm->log, LOG_NOTICE, "%s ready for sessions", sm->id);

                nad_free(nad);
                return 0;
            }

            log_debug(ZONE, "got a packet");

            pkt = pkt_new(sm, nad);
            if (pkt == NULL) {
                log_debug(ZONE, "invalid packet, dropping");
                return 0;
            }

            /* go */
            dispatch(sm, pkt);

            return 0;

        case event_CLOSED:
            mio_close(sm->mio, sm->fd);
            sm->fd = NULL;
            return -1;
    }

    return 0;
}
Пример #23
0
static mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) {
    sm_t sm = mi->mod->mm->sm;
    int ns, iq, elem, attr;
    jid_t jid;
    sess_t sess = (sess_t) NULL;
    mod_ret_t ret;

    /* if we've got this namespace, its from a c2s */
    if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0)
        return mod_PASS;

    /* don't bother if its a failure */
    if(pkt->type & pkt_SESS_FAILED) {
        /* !!! check failed=1, handle */
        pkt_free(pkt);
        return mod_HANDLED;
    }

    /* session commands */
    if(pkt->type & pkt_SESS) {

        ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL);

        /* only end can get away without a target */
        attr = nad_find_attr(pkt->nad, 1, -1, "target", NULL);
        if(attr < 0 && pkt->type != pkt_SESS_END) {
            nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);

            return mod_HANDLED;
        }

        /* session start */
        if(pkt->type == pkt_SESS) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

            if(jid != NULL)
                sess = sess_start(sm, jid);

            if(jid == NULL || sess == NULL) {
                nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
                sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

                pkt->nad = NULL;
                pkt_free(pkt);
                if(jid != NULL)
                    jid_free(jid);

                return mod_HANDLED;
            }

            /* c2s component that is handling this session */
            strcpy(sess->c2s, pkt->rfrom->domain);

            /* remember what c2s calls us */
            attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
            snprintf(sess->c2s_id, sizeof(sess->c2s_id), "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));

            /* mark PBX session as fake */
            if(!strncmp("PBX", sess->c2s_id, 3)) {
                sess->fake = 1;
            }

            /* add our id */
            nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0);

            /* mark that it started OK */
            nad_set_attr(pkt->nad, 1, -1, "action", "started", 7);

			/* set this SM name */
			nad_set_attr(pkt->nad, 0, -1, "to", sm->id, 0);

			/* inform c2s */
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* user create */
        if(pkt->type == pkt_SESS_CREATE) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

            if(jid == NULL || user_create(sm, jid) != 0) {
                nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
                sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

                pkt->nad = NULL;
                pkt_free(pkt);
                if(jid != NULL)
                    jid_free(jid);

                return mod_HANDLED;
            }

            /* inform c2s */
            nad_set_attr(pkt->nad, 1, -1, "action", "created", 7);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* user delete */
        if(pkt->type == pkt_SESS_DELETE) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
            if(jid == NULL) {
                pkt_free(pkt);
                return mod_HANDLED;
            }

            user_delete(sm, jid);

            /* inform c2s */
            nad_set_attr(pkt->nad, 1, -1, "action", "deleted", 7);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* get the session id */
        attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL);
        if(attr < 0) {
            log_debug(ZONE, "no session id, bouncing");
            nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);

            return mod_HANDLED;
        }

        /* find the corresponding session */
        sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

        /* active check */
        if(sess == NULL) {
            log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
            nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);

            return mod_HANDLED;
        }

        /* make sure its from them */
        attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
        if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) {
            log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", pkt->rfrom->domain, sess->sm_id, sess->c2s_id);
            pkt_free(pkt);
            return mod_HANDLED;
        }

        /* session end */
        if(pkt->type == pkt_SESS_END) {
            sm_c2s_action(sess, "ended", NULL);
            sess_end(sess);

            pkt_free(pkt);
            return mod_HANDLED;
        }

        log_debug(ZONE, "unknown session packet, dropping");
        pkt_free(pkt);

        return mod_HANDLED;
    }

    /* otherwise, its a normal packet for the session */

/* #ifdef ENABLE_SUPERSEDED       // FIXME XXX TODO clients are not yet ready for this */
        /* check for RFC3920 session request *
         * with RFC3920bis it is unneeded *
         * session is activated by bind, so we just return back result */
        if((ns = nad_find_scoped_namespace(pkt->nad, uri_XSESSION, NULL)) >= 0 &&
           (iq = nad_find_elem(pkt->nad, 0, -1, "iq", 1)) >= 0 &&
           (elem = nad_find_elem(pkt->nad, iq, ns, "session", 1)) >= 0) {
            log_debug(ZONE, "session create request");
    
            /* build a result packet */
            nad_drop_elem(pkt->nad, elem);
            nad_set_attr(pkt->nad, iq, -1, "type", "result", 6);
    
            /* return the result */
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
    
            pkt->nad = NULL;
            pkt_free(pkt);
    
            return mod_HANDLED;
        }
/* #endif */
    /* get the session id */
    attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL);
    if(attr < 0) {
        log_debug(ZONE, "no session id, bouncing");
        nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
        sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

        pkt->nad = NULL;
        pkt_free(pkt);

        return mod_HANDLED;
    }

    /* find the corresponding session */
    sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

    /* active check */
    if(sess == NULL) {
        log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
        nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
        sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

        pkt->nad = NULL;
        pkt_free(pkt);

        return mod_HANDLED;
    }

    /* make sure its from them */
    attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
    if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) {
        log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", jid_full(pkt->rfrom), sess->sm_id, sess->c2s_id);
        pkt_free(pkt);
        return mod_HANDLED;
    }

    /* where it came from */
    pkt->source = sess;

    /* hand it to the modules */
    ret = mm_in_sess(pkt->sm->mm, sess, pkt);
    switch(ret) {
        case mod_HANDLED:
            break;

        case mod_PASS:
            /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */
            if(pkt->type == pkt_IQ_RESULT)
               break;
            else
               ret = -stanza_err_FEATURE_NOT_IMPLEMENTED;

        default:
            pkt_sess(pkt_error(pkt, -ret), sess);

            break;
    }

    return mod_HANDLED;
}