Beispiel #1
0
/** make a new action route */
static nad_t _sm_build_route(sess_t sess, bres_t res, const char *action, const char *target, const char *id) {
    nad_t nad;
    int ns, ans;

    nad = nad_new();

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

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

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

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

    nad_append_attr(nad, -1, "action", action);

    if(target != NULL) {
        nad_set_attr(nad, 0, -1, "target", target, NULL);
        nad_append_attr(nad, -1, "target", target);
    }
    if(id != NULL)
        nad_append_attr(nad, -1, "id", id);

    log_debug(ZONE, "built new route nad for %s action %s target %s id %s", jid_full(res->jid), action, target, id);

    return nad;
}
Beispiel #2
0
Datei: nad.c Projekt: zipo/zipo
nad_t nad_parse(const char *buf, int len) {
    struct build_data bd;
    XML_Parser p;

    if(len == 0)
        len = strlen(buf);

    p = XML_ParserCreateNS(NULL, '|');
    if(p == NULL)
        return NULL;

    XML_SetReturnNSTriplet(p, 1);

    bd.nad = nad_new();
    bd.depth = 0;

    XML_SetUserData(p, (void *) &bd);
    XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end);
    XML_SetCharacterDataHandler(p, _nad_parse_cdata);
    XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start);

    if(!XML_Parse(p, buf, len, 1)) {
        XML_ParserFree(p);
        nad_free(bd.nad);
        return NULL;
    }

    XML_ParserFree(p);

    if(bd.depth != 0)
        return NULL;

    return bd.nad;
}
Beispiel #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);
}
Beispiel #4
0
nad_t nad_copy(nad_t nad)
{
    nad_t copy;

    _nad_ptr_check(__func__, nad);

    if(nad == NULL) return NULL;

    copy = nad_new();

    /* if it's not large enough, make bigger */
    NAD_SAFE(copy->elems, nad->elen, copy->elen);
    NAD_SAFE(copy->attrs, nad->alen, copy->alen);
    NAD_SAFE(copy->nss, nad->nlen, copy->nlen);
    NAD_SAFE(copy->cdata, nad->clen, copy->clen);

    /* copy all data */
    memcpy(copy->elems, nad->elems, nad->elen);
    memcpy(copy->attrs, nad->attrs, nad->alen);
    memcpy(copy->nss, nad->nss, nad->nlen);
    memcpy(copy->cdata, nad->cdata, nad->clen);

    /* sync data */
    copy->ecur = nad->ecur;
    copy->acur = nad->acur;
    copy->ncur = nad->ncur;
    copy->ccur = nad->ccur;

    copy->scope = nad->scope;

    return copy;
}
Beispiel #5
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);
}
Beispiel #6
0
/** utility: generate an abort nad */
static nad_t _sx_sasl_abort(sx_t s) {
    nad_t nad;
    int ns;

    nad = nad_new();
    ns = nad_add_namespace(nad, uri_SASL, NULL);

    nad_append_elem(nad, ns, "abort", 0);

    return nad;
}
Beispiel #7
0
/** utility: generate a failure nad */
static nad_t _sx_sasl_failure(sx_t s, const char *err) {
    nad_t nad;
    int ns;

    nad = nad_new();
    ns = nad_add_namespace(nad, uri_SASL, NULL);

    nad_append_elem(nad, ns, "failure", 0);
    if(err != NULL)
        nad_append_elem(nad, ns, err, 1);

    return nad;
}
Beispiel #8
0
/** utility: generate a response nad */
static nad_t _sx_sasl_response(sx_t s, char *data, int dlen) {
    nad_t nad;
    int ns;

    nad = nad_new();
    ns = nad_add_namespace(nad, uri_SASL, NULL);

    nad_append_elem(nad, ns, "response", 0);
    if(data != NULL)
        nad_append_cdata(nad, data, dlen, 1);

    return nad;
}
Beispiel #9
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);
}
Beispiel #10
0
Datei: nad.c Projekt: zipo/zipo
nad_t nad_deserialize(const char *buf) {
    nad_t nad = nad_new();
    const char *pos = buf + sizeof(int);  /* skip len */

    _nad_ptr_check(__func__, nad);

    nad->ecur = * (int *) pos;
    pos += sizeof(int);
    nad->acur = * (int *) pos;
    pos += sizeof(int);
    nad->ncur = * (int *) pos;
    pos += sizeof(int);
    nad->ccur = * (int *) pos;
    pos += sizeof(int);
    nad->elen = nad->ecur;
    nad->alen = nad->acur;
    nad->nlen = nad->ncur;
    nad->clen = nad->ccur;

    if(nad->ecur > 0)
    {
        nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur);
        memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur);
        pos += sizeof(struct nad_elem_st) * nad->ecur;
    }

    if(nad->acur > 0)
    {
        nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur);
        memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur);
        pos += sizeof(struct nad_attr_st) * nad->acur;
    }

    if(nad->ncur > 0)
    {
        nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur);
        memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur);
        pos += sizeof(struct nad_ns_st) * nad->ncur;
    }

    if(nad->ccur > 0)
    {
        nad->cdata = (char *) malloc(sizeof(char) * nad->ccur);
        memcpy(nad->cdata, pos, sizeof(char) * nad->ccur);
    }

    return nad;
}
Beispiel #11
0
nad_t nad_parse(const char *buf, int len) {
    struct build_data bd;
    XML_Parser p;

    if(len == 0)
        len = strlen(buf);

    p = XML_ParserCreateNS(NULL, '|');
    if(p == NULL)
        return NULL;
    bd.p = p;

    XML_SetReturnNSTriplet(p, 1);
    /* Prevent the "billion laughs" attack against expat by disabling
     * internal entity expansion.  With 2.x, forcibly stop the parser
     * if an entity is declared - this is safer and a more obvious
     * failure mode.  With older versions, simply prevent expenansion
     * of such entities. */
#ifdef HAVE_XML_STOPPARSER
    XML_SetEntityDeclHandler(p, (void *) _nad_parse_entity_declaration);
#else
    XML_SetDefaultHandler(p, NULL);
#endif

    bd.nad = nad_new();
    bd.depth = 0;

    XML_SetUserData(p, (void *) &bd);
    XML_SetElementHandler(p, _nad_parse_element_start, _nad_parse_element_end);
    XML_SetCharacterDataHandler(p, _nad_parse_cdata);
    XML_SetStartNamespaceDeclHandler(p, _nad_parse_namespace_start);

    if(!XML_Parse(p, buf, len, 1)) {
        XML_ParserFree(p);
        nad_free(bd.nad);
        return NULL;
    }

    XML_ParserFree(p);

    if(bd.depth != 0)
        return NULL;

    return bd.nad;
}
Beispiel #12
0
/** domain advertisement */
static void _router_advertise(router_t r, const char *domain, component_t src, int unavail) {
    struct broadcast_st bc;
    int ns;

    log_debug(ZONE, "advertising %s to all routes (unavail=%d)", domain, unavail);

    bc.r = r;
    bc.src = src;

    /* create a new packet */
    bc.nad = nad_new();
    ns = nad_add_namespace(bc.nad, uri_COMPONENT, NULL);
    nad_append_elem(bc.nad, ns, "presence", 0);
    nad_append_attr(bc.nad, -1, "from", domain);
    if(unavail)
        nad_append_attr(bc.nad, -1, "type", "unavailable");

    xhash_walk(r->routes, _router_broadcast, (void *) &bc);

    nad_free(bc.nad);
}
Beispiel #13
0
static nad_t _pbx_presence_nad(int available, char *cmd)
{
	nad_t nad;
	int ns;
	char *show = NULL;

	nad = nad_new();
	ns = nad_add_namespace(nad, uri_CLIENT, NULL);
	nad_append_elem(nad, ns, "presence", 0);

	if(!available) {
		nad_append_attr(nad, -1, "type", "unavailable");
	}
	else {
		char *cont;
		long int priority;
		char prioritystr[5]; // -128 to +127 + \0

		priority = strtol(cmd, &cont, 10);
		log_debug(ZONE, "Read %ld priority", priority);
		if(cmd == cont) priority = -1; // use -1 priority if not given
		if(priority < -128) priority = -128;
		if(priority > 127) priority = 127;
		nad_append_elem(nad, -1, "priority", 1);
		snprintf(prioritystr, 5, "%ld", priority);
		nad_append_cdata(nad, prioritystr, strlen(prioritystr), 2);
		if(cmd != cont) {
			cmd = cont;
			while(*cmd == ' ') { cmd++; }
		}


		if(!strncmp("CHAT", cmd, 4)) {
			cmd += 4;
			show = "chat";
		}
		if(!strncmp("ONLINE", cmd, 6)) {
			cmd += 6;
		}
		if(!strncmp("DND", cmd, 3)) {
			cmd += 3;
			show = "dnd";
		}
		if(!strncmp("AWAY", cmd, 4)) {
			cmd += 4;
			show = "away";
		}
		if(!strncmp("XA", cmd, 2)) {
			cmd += 2;
			show = "xa";
		}
		if(show) {
			nad_append_elem(nad, -1, "show", 1);
			nad_append_cdata(nad, show, strlen(show), 2);
		}
	}

	while(*cmd == ' ') { cmd++; }

	if(*cmd != '\0' && *cmd != '\n') {
		int len = strlen(cmd);
		nad_append_elem(nad, -1, "status", 1);
		nad_append_cdata(nad, cmd, len - (cmd[len-1] == '\n' ? 1 : 0), 2);
	}

	return nad;
}
Beispiel #14
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;
}
Beispiel #15
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;
}
Beispiel #16
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;
}
Beispiel #17
0
Datei: in.c Projekt: 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);
}
Beispiel #18
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;
}
Beispiel #19
0
/** turn an xml file into a config hash */
int config_load_with_id(config_t c, const char *file, const char *id)
{
    struct build_data bd;
    FILE *f;
    XML_Parser p;
    int done, len, end, i, j, attr;
    char buf[1024], *next;
    struct nad_elem_st **path;
    config_elem_t elem;
    int rv = 0;
    
    /* open the file */
    f = fopen(file, "r");
    if(f == NULL)
    {
        fprintf(stderr, "config_load: couldn't open %s for reading: %s\n", file, strerror(errno));
        return 1;
    }

    /* new parser */
    p = XML_ParserCreate(NULL);
    if(p == NULL)
    {
        fprintf(stderr, "config_load: couldn't allocate XML parser\n");
        fclose(f);
        return 1;
    }

    /* nice new nad to parse it into */
    bd.nad = nad_new();
    bd.depth = 0;

    /* setup the parser */
    XML_SetUserData(p, (void *) &bd);
    XML_SetElementHandler(p, _config_startElement, _config_endElement);
    XML_SetCharacterDataHandler(p, _config_charData);

    for(;;)
    {
        /* read that file */
        len = fread(buf, 1, 1024, f);
        if(ferror(f))
        {
            fprintf(stderr, "config_load: read error: %s\n", strerror(errno));
            XML_ParserFree(p);
            fclose(f);
            nad_free(bd.nad);
            return 1;
        }
        done = feof(f);

        /* parse it */
        if(!XML_Parse(p, buf, len, done))
        {
            fprintf(stderr, "config_load: parse error at line %llu: %s\n", (unsigned long long) XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p)));
            XML_ParserFree(p);
            fclose(f);
            nad_free(bd.nad);
            return 1;
        }

        if(done)
            break;
    }

    /* done reading */
    XML_ParserFree(p);
    fclose(f);

    // Put id if specified
    if (id) {
        elem = (config_elem_t)pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st));
        xhash_put(c->hash, pstrdup(xhash_pool(c->hash), "id"), elem);
        elem->values = calloc(1, sizeof(char *));
        elem->values[0] = pstrdup(xhash_pool(c->hash), id);
        elem->nvalues = 1;
    }

    /* now, turn the nad into a config hash */
    path = NULL;
    len = 0, end = 0;
    /* start at 1, so we skip the root element */
    for(i = 1; i < bd.nad->ecur && rv == 0; i++)
    {
        /* make sure we have enough room to add this element to our path */
        if(end <= bd.nad->elems[i].depth)
        {
            end = bd.nad->elems[i].depth + 1;
            path = (struct nad_elem_st **) realloc((void *) path, sizeof(struct nad_elem_st *) * end);
        }

        /* save this path element */
        path[bd.nad->elems[i].depth] = &bd.nad->elems[i];
        len = bd.nad->elems[i].depth + 1;

        /* construct the key from the current path */
        next = buf;
        for(j = 1; j < len; j++)
        {
            strncpy(next, bd.nad->cdata + path[j]->iname, path[j]->lname);
            next = next + path[j]->lname;
            *next = '.';
            next++;
        }
        next--;
        *next = '\0';

        /* find the config element for this key */
        elem = (config_elem_t)xhash_get(c->hash, buf);
        if(elem == NULL)
        {
            /* haven't seen it before, so create it */
            elem = (config_elem_t)pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st));
            xhash_put(c->hash, pstrdup(xhash_pool(c->hash), buf), elem);
        }

        /* make room for this value .. can't easily realloc off a pool, so
         * we do it this way and let _config_reaper clean up */
        elem->values = realloc((void *) elem->values, sizeof(char *) * (elem->nvalues + 1));

		/* and copy it in */
        if(NAD_CDATA_L(bd.nad, i) > 0) {
            // Expand values

            const char *val = _config_expandx(c, NAD_CDATA(bd.nad, i), NAD_CDATA_L(bd.nad, i));

            if (!val) {
                rv = 1;
                break;
            }
            // Make a copy
            elem->values[elem->nvalues] = val;
        } else {
            elem->values[elem->nvalues] = "1";
        }

        /* make room for the attribute lists */
        elem->attrs = realloc((void *) elem->attrs, sizeof(char **) * (elem->nvalues + 1));

        elem->attrs[elem->nvalues] = NULL;

        /* count the attributes */
        for(attr = bd.nad->elems[i].attr, j = 0; attr >= 0; attr = bd.nad->attrs[attr].next, j++);

        /* make space */
        elem->attrs[elem->nvalues] = pmalloc(xhash_pool(c->hash), sizeof(char *) * (j * 2 + 2));

        /* if we have some */
        if(j > 0)
        {
            /* copy them in */
            j = 0;
            attr = bd.nad->elems[i].attr;
            while(attr >= 0)
            {
                elem->attrs[elem->nvalues][j] = pstrdupx(xhash_pool(c->hash), NAD_ANAME(bd.nad, attr), NAD_ANAME_L(bd.nad, attr));
                elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr));

		/*
		 * pstrdupx(blob, 0) returns NULL - which means that later
		 * there's no way of telling whether an attribute is defined
		 * as empty, or just not defined. This fixes that by creating
		 * an empty string for attributes which are defined empty
		 */
                if (NAD_AVAL_L(bd.nad, attr)==0) {
                    elem->attrs[elem->nvalues][j + 1] = pstrdup(xhash_pool(c->hash), "");
                } else {
                    elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr));
                }
                j += 2;
                attr = bd.nad->attrs[attr].next;
            }
        }

        /* do this and we can use j_attr */
        elem->attrs[elem->nvalues][j] = NULL;
        elem->attrs[elem->nvalues][j + 1] = NULL;

        elem->nvalues++;
    }

    if(path != NULL)
        free(path);

    if(c->nad != NULL)
        nad_free(c->nad);
    c->nad = bd.nad;

    return rv;
}