Ejemplo n.º 1
0
Archivo: aci.c Proyecto: zipo/zipo
xht aci_load(router_t r) {
    xht aci;
    int aelem, uelem, attr;
    char type[33];
    aci_user_t list_head, list_tail, user;

    log_debug(ZONE, "loading aci");

    aci = xhash_new(51);

    if((aelem = nad_find_elem(r->config->nad, 0, -1, "aci", 1)) < 0)
        return aci;

    aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 1);
    while(aelem >= 0) {
        if((attr = nad_find_attr(r->config->nad, aelem, -1, "type", NULL)) < 0) {
            aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 0);
            continue;
        }

        list_head = NULL;
        list_tail = NULL;

        snprintf(type, 33, "%.*s", NAD_AVAL_L(r->config->nad, attr), NAD_AVAL(r->config->nad, attr));

        log_debug(ZONE, "building list for '%s'", type);

        uelem = nad_find_elem(r->config->nad, aelem, -1, "user", 1);
        while(uelem >= 0) {
            if(NAD_CDATA_L(r->config->nad, uelem) > 0) {
                user = (aci_user_t) calloc(1, sizeof(struct aci_user_st));

                user->name = (char *) malloc(sizeof(char) * (NAD_CDATA_L(r->config->nad, uelem) + 1));
                sprintf(user->name, "%.*s", NAD_CDATA_L(r->config->nad, uelem), NAD_CDATA(r->config->nad, uelem));

                if(list_tail != NULL) {
                   list_tail->next = user;
                   list_tail = user;
                }

                /* record the head of the list */
                if(list_head == NULL) {
                   list_head = user;
                   list_tail = user;
                }
                
                log_debug(ZONE, "added '%s'", user->name);
            }

            uelem = nad_find_elem(r->config->nad, uelem, -1, "user", 0);
        }

        if(list_head != NULL)
            xhash_put(aci, pstrdup(xhash_pool(aci), type), (void *) list_head);

        aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 0);
    }

    return aci;
}
Ejemplo n.º 2
0
xht aci_load(sm_t sm)
{
    xht acls;
    int aelem, jelem, attr;
    char type[33];
    jid_t list, jid;

    log_debug(ZONE, "loading aci");

    acls = xhash_new(51);

    if((aelem = nad_find_elem(sm->config->nad, 0, -1, "aci", 1)) < 0)
        return acls;

    aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 1);
    while(aelem >= 0)
    {
        list = NULL;

        if((attr = nad_find_attr(sm->config->nad, aelem, -1, "type", NULL)) < 0)
        {
            aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0);
            continue;
        }

        snprintf(type, 33, "%.*s", NAD_AVAL_L(sm->config->nad, attr), NAD_AVAL(sm->config->nad, attr));

        log_debug(ZONE, "building list for '%s'", type);

        jelem = nad_find_elem(sm->config->nad, aelem, -1, "jid", 1);
        while(jelem >= 0)
        {
            if(NAD_CDATA_L(sm->config->nad, jelem) > 0)
            {
                jid = jid_new(NAD_CDATA(sm->config->nad, jelem), NAD_CDATA_L(sm->config->nad, jelem));
                list = jid_append(list, jid);
                
                log_debug(ZONE, "added '%s'", jid_user(jid));

                jid_free(jid);
            }

            jelem = nad_find_elem(sm->config->nad, jelem, -1, "jid", 0);
        }

        if(list != NULL) {
            xhash_put(acls, pstrdup(xhash_pool(acls), type), (void *) list);
        }

        aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0);
    }

    return acls;
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
int message_log(nad_t nad, router_t r, const char *msg_from, const char *msg_to)
{
    time_t t;
    char *time_pos;
    int time_sz;
    struct stat filestat;
    FILE *message_file;
    short int new_msg_file = 0;
    int i;
    int nad_body_len = 0;
    const char *nad_body_start = 0;
    int body_count;
    const char *nad_body = NULL;
    char body[MAX_MESSAGE*2];

    assert((int) (nad != NULL));

    /* timestamp */
    t = time(NULL);
    time_pos = ctime(&t);
    time_sz = strlen(time_pos);
    /* chop off the \n */
    time_pos[time_sz-1]=' ';

    // Find the message body
    for (i = 0; NAD_ENAME_L(nad, i) > 0; i++)
    {
        if((NAD_ENAME_L(nad, i) == 4) && (strncmp("body", NAD_ENAME(nad, i), 4) == 0))
        {
            nad_body_len = NAD_CDATA_L(nad, i);
            if (nad_body_len > 0) {
                nad_body = NAD_CDATA(nad, i);
            } else {
                log_write(r->log, LOG_NOTICE, "message_log received a message with empty body");
                return 0;
            }
            break;
        }
    }

    // Don't log anything if we found no NAD body
    if (nad_body == NULL) {
        return 0;
    }

    // Store original pointer address so that we know when to stop iterating through nad_body
    nad_body_start = nad_body;

    // replace line endings with "\n"
    for (body_count = 0; (nad_body < nad_body_start + nad_body_len) && (body_count < (MAX_MESSAGE*2)-3); nad_body++) {
        if (*nad_body == '\n') {
            body[body_count++] = '\\';
            body[body_count++] = 'n';
        } else {
            body[body_count++] = *nad_body;
        }
    }
    body[body_count] = '\0';

    // Log our message
    umask((mode_t) 0077);
    if (stat(r->message_logging_file, &filestat)) {
        new_msg_file = 1;
    }

    if ((message_file = fopen(r->message_logging_file, "a")) == NULL)
    {
        log_write(r->log, LOG_ERR, "Unable to open message log for writing: %s", strerror(errno));
        return 1;
    }

    if (new_msg_file) {
        if (! fprintf(message_file, "# This message log is created by the jabberd router.\n"))
        {
            log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno));
            return 1;
        }
        fprintf(message_file, "# See router.xml for logging options.\n");
        fprintf(message_file, "# Format: (Date)<tab>(From JID)<tab>(To JID)<tab>(Message Body)<line end>\n");
    }

    if (! fprintf(message_file, "%s\t%s\t%s\t%s\n", time_pos, msg_from, msg_to, body))
    {
        log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno));
        return 1;
    }

    fclose(message_file);

    return 0;
}
Ejemplo n.º 5
0
Archivo: in.c Proyecto: 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;
}
Ejemplo n.º 6
0
Archivo: in.c Proyecto: 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);
}
Ejemplo n.º 7
0
static mod_ret_t _vacation_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
    module_t mod = mi->mod;
    vacation_t v = sess->user->module_data[mod->index];
    int ns, start, end, msg;
    char dt[30];
    pkt_t res;
    os_t os;
    os_object_t o;

    /* we only want to play with vacation iq packets */
    if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VACATION)
        return mod_PASS;

    /* if it has a to, throw it out */
    if(pkt->to != NULL)
        return -stanza_err_BAD_REQUEST;

    /* get */
    if(pkt->type == pkt_IQ) {
        if(v->msg == NULL) {
            res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL);
            pkt_id(pkt, res);
            pkt_free(pkt);

            pkt_sess(res, sess);

            return mod_HANDLED;
        }

        ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL);

        if(v->start != 0) {
            datetime_out(v->start, dt_DATETIME, dt, 30);
            nad_insert_elem(pkt->nad, 2, ns, "start", dt);
        } else
            nad_insert_elem(pkt->nad, 2, ns, "start", NULL);

        if(v->end != 0) {
            datetime_out(v->end, dt_DATETIME, dt, 30);
            nad_insert_elem(pkt->nad, 2, ns, "end", dt);
        } else
            nad_insert_elem(pkt->nad, 2, ns, "end", NULL);

        nad_insert_elem(pkt->nad, 2, ns, "message", v->msg);

        pkt_tofrom(pkt);
        nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
            
        pkt_sess(pkt, sess);

        return mod_HANDLED;
    }

    /* set */
    ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL);

    start = nad_find_elem(pkt->nad, 2, ns, "start", 1);
    end = nad_find_elem(pkt->nad, 2, ns, "end", 1);
    msg = nad_find_elem(pkt->nad, 2, ns, "message", 1);

    if(start < 0 || end < 0 || msg < 0) {
        /* forget */
        if(v->msg != NULL) {
            free(v->msg);
            v->msg = NULL;
        }
        v->start = 0;
        v->end = 0;

        storage_delete(mi->sm->st, "vacation-settings", jid_user(sess->jid), NULL);

        res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL);
        pkt_id(pkt, res);
        pkt_free(pkt);

        pkt_sess(res, sess);

        return mod_HANDLED;
    }

    if(NAD_CDATA_L(pkt->nad, start) > 0) {
        strncpy(dt, NAD_CDATA(pkt->nad, start), (30 < NAD_CDATA_L(pkt->nad, start) ? 30 : NAD_CDATA_L(pkt->nad, start)));
        v->start = datetime_in(dt);
    } else
        v->start = 0;

    if(NAD_CDATA_L(pkt->nad, end) > 0) {
        strncpy(dt, NAD_CDATA(pkt->nad, end), (30 < NAD_CDATA_L(pkt->nad, end) ? 30 : NAD_CDATA_L(pkt->nad, end)));
        v->end = datetime_in(dt);
    } else
        v->end = 0;

    v->msg = (char *) malloc(sizeof(char) * (NAD_CDATA_L(pkt->nad, msg) + 1));
    strncpy(v->msg, NAD_CDATA(pkt->nad, msg), NAD_CDATA_L(pkt->nad, msg));
    v->msg[NAD_CDATA_L(pkt->nad, msg)] = '\0';

    os = os_new();
    o = os_object_new(os);
    os_object_put(o, "start", &v->start, os_type_INTEGER);
    os_object_put(o, "end", &v->end, os_type_INTEGER);
    os_object_put(o, "message", v->msg, os_type_STRING);

    if(storage_replace(mod->mm->sm->st, "vacation-settings", jid_user(sess->user->jid), NULL, os) != st_SUCCESS) {
        free(v->msg);
        v->msg = NULL;
        v->start = 0;
        v->end = 0;
        return -stanza_err_INTERNAL_SERVER_ERROR;
    }
    
    res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL);
    pkt_id(pkt, res);
    pkt_free(pkt);

    pkt_sess(res, sess);

    return mod_HANDLED;
}
Ejemplo n.º 8
0
int message_log(nad_t nad, router_t r, const char *msg_from, const char *msg_to) {
    time_t t;
    struct tm *time_pos;
    char timestamp[25];
    struct stat filestat;
    FILE *message_file;
    short int new_msg_file = 0;
    int i;
    int nad_body_len = 0;
    char *nad_body = NULL;
    int elem;

    assert((int) (nad != NULL));

    // Find the message body
    elem = nad_find_elem(nad, 0, -1, "message", 1);
    if (elem >= 0) {
        elem = nad_find_elem(nad, elem, -1, "body", 1);
    }

    // Don't log anything if we found no NAD body
    if (elem == -1) {
        return 0;
    }

    nad_body_len = NAD_CDATA_L(nad, elem);
    nad_body = NAD_CDATA(nad, elem);

    // temporary replace line endings with 0x01, ASCII: <control> SOH <start of heading>
    for (i = 0; i < nad_body_len; i++) {
        if (nad_body[i] == '\n') {
            nad_body[i] = 0x01;
        }
    }

    // Log our message
    umask((mode_t) 0077);
    if (stat(r->message_logging_file, &filestat)) {
        new_msg_file = 1;
    }

    if ((message_file = fopen(r->message_logging_file, "a")) == NULL) {
        log_write(r->log, LOG_ERR, "Unable to open message log for writing: %s", strerror(errno));
        return 1;
    }

    if (new_msg_file) {
        if (! fprintf(message_file, "# This message log is created by the jabberd router.\n"))
        {
            log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno));
            return 1;
        }
        fprintf(message_file, "# See router.xml for logging options.\n");
        fprintf(message_file, "# Format: DateTime FromJID ToJID MessageBody<line end>\n");
    }

    /* ISO8601 timestamp */
    t = time(NULL);
    time_pos = localtime(&t);
    if (strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S%z", time_pos) == 0) {
        log_write(r->log, LOG_ERR, "strftime failed: %s", strerror(errno));
    }

    elem = fprintf(message_file, "%s %s %s %.*s\n", timestamp, msg_from, msg_to, nad_body_len, nad_body);

    fclose(message_file);

    // revert line endings
    for (i = 0; i < nad_body_len; i++) {
        if (nad_body[i] == 0x01) {
            nad_body[i] = '\n';
        }
    }

    if (!elem) {
        log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno));
        return 1;
    }

    return 0;
}
Ejemplo n.º 9
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;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 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;
}
Ejemplo n.º 12
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;
}
Ejemplo n.º 13
0
int user_table_load(router_t r) {
    const char *userfile;
    FILE *f;
    long size;
    char *buf;
    nad_t nad;
    int nusers, user, name, secret;

    log_debug(ZONE, "loading user table");

    if(r->users != NULL)
        xhash_free(r->users);

    r->users = xhash_new(51);

    userfile = config_get_one(r->config, "local.users", 0);
    if(userfile == NULL)
        userfile = CONFIG_DIR "/router-users.xml";

    f = fopen(userfile, "rb");
    if(f == NULL) {
        log_write(r->log, LOG_ERR, "couldn't open user table file %s: %s", userfile, strerror(errno));
        return 1;
    }

    fseek(f, 0, SEEK_END);
    size = ftell(f);
    if(size < 0) {
        log_write(r->log, LOG_ERR, "couldn't seek user table file %s: %s", userfile, strerror(errno));
        fclose(f);
        return 1;
    }
    if(size == 0) {
        log_write(r->log, LOG_ERR, "empty user table file %s", userfile);
        fclose(f);
        return 1;
    }
    fseek(f, 0, SEEK_SET);

    buf = (char *) malloc(sizeof(char) * size);

    if (fread(buf, 1, size, f) != size || ferror(f)) {
        log_write(r->log, LOG_ERR, "couldn't read from user table file: %s", strerror(errno));
        free(buf);
        fclose(f);
        return 1;
    }

    fclose(f);

    nad = nad_parse(buf, size);
    if(nad == NULL) {
        log_write(r->log, LOG_ERR, "couldn't parse user table");
        free(buf);
        return 1;
    }

    free(buf);

    nusers = 0;
    user = nad_find_elem(nad, 0, -1, "user", 1);
    while(user >= 0) {
        name = nad_find_elem(nad, user, -1, "name", 1);
        secret = nad_find_elem(nad, user, -1, "secret", 1);

        if(name < 0 || secret < 0 || NAD_CDATA_L(nad, name) <= 0 || NAD_CDATA_L(nad, secret) <= 0) {
            log_write(r->log, LOG_ERR, "malformed user entry in user table file, skipping");
            continue;
        }

        log_debug(ZONE, "remembering user '%.*s'", NAD_CDATA_L(nad, name), NAD_CDATA(nad, name));

        xhash_put(r->users, pstrdupx(xhash_pool(r->users), NAD_CDATA(nad, name), NAD_CDATA_L(nad, name)), pstrdupx(xhash_pool(r->users), NAD_CDATA(nad, secret), NAD_CDATA_L(nad, secret)));

        nusers++;

        user = nad_find_elem(nad, user, -1, "user", 0);
    }

    nad_free(nad);

    log_write(r->log, LOG_NOTICE, "loaded user table (%d users)", nusers);

    r->users_load = time(NULL);

    return 0;
}
Ejemplo n.º 14
0
/** Handles iq messages */
mod_ret_t archive_iq_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
    int prefs, type;
    int section, ptr;
    os_t os;
    os_object_t o;
    char* owner;
    char buff[2048];
    log_debug(ZONE, "In session");

    // we only want to play IQs
    if((!((pkt->type & pkt_IQ) || (pkt->type & pkt_IQ_SET))) || (pkt->ns != ns_ARCHIVE))
        return mod_PASS;
    log_debug(ZONE, "Passed through packet checks");

    // if it has a to, throw it out
    if(pkt->to != NULL)
        return -stanza_err_BAD_REQUEST;

    // Who are we?
    owner=jid_user(sess->jid);

    // Check for no type or get to send current settings
    if((type = (nad_find_attr(pkt->nad, 2, -1, "type", NULL)<0)) ||
       ((NAD_AVAL_L(pkt->nad, type ) == 3) && strncmp("get", NAD_AVAL(pkt->nad, type), 3))) {
        log_debug(ZONE, "Somebody is asking about settings");
        send_arch_prefs(mi, sess, pkt);
        return mod_HANDLED;
    }

    // We are setting stuff
    if(pkt->type == pkt_IQ_SET) {
        // Prepare to store them
        log_debug(ZONE, "Setting archiving preferences...");
        os = os_new();
        if(os == NULL) return mod_PASS;
        o = os_object_new(os);
        if(o  == NULL) return mod_PASS;

        // Get rid of old settings
        storage_delete(pkt->sm->st, tbl_name "_settings", owner, NULL);
        log_debug(ZONE, "Got rid of old preferences...");

        // Find if there is an default option
        if(!((prefs=nad_find_elem(pkt->nad, 1, -1, "prefs", 1))>0))
            return mod_PASS;
        ptr=nad_find_attr(pkt->nad, prefs, -1, "default", NULL);

        if(ptr>0) {
            // Defaults
            log_debug(ZONE, "Saving defaults...");
            os_object_put(o, "jid", owner, os_type_STRING);
            if     (strncmp("roster",NAD_AVAL(pkt->nad, ptr), NAD_AVAL_L(pkt->nad, ptr))==0)
                prefs=A_ROSTER;
            else if(strncmp("always",NAD_AVAL(pkt->nad, ptr), NAD_AVAL_L(pkt->nad, ptr))==0)
                prefs=A_ALWAYS;
            else
                prefs=A_NEVER;
            os_object_put(o, "setting", &prefs,  os_type_INTEGER);
            log_debug(ZONE, "Setting default to %d...", prefs);

            // What to save always
            log_debug(ZONE, "Saving what to save always...");
            if(((section = nad_find_elem(pkt->nad, prefs, -1, "always", 1))>0)) {
                log_debug(ZONE, "Found always section %d...", section);
                prefs=A_ALWAYS;
                for(ptr = nad_find_elem(pkt->nad, section, -1, "jid", 1); ptr > 0;
                    ptr = nad_find_elem(pkt->nad, ptr,     -1, "jid", 0)) {
                        o = os_object_new(os);
                        strncpy(buff, NAD_CDATA(pkt->nad, ptr), min(2047,NAD_CDATA_L(pkt->nad, ptr)));
                        buff[min(2047,NAD_CDATA_L(pkt->nad, ptr))]=0;
                        os_object_put(o, "jid",      buff,  os_type_STRING);
                        os_object_put(o, "setting", &prefs, os_type_INTEGER);
                        log_debug(ZONE, "Always archiving %s...", buff);
                }
            }

            // What to never save
            log_debug(ZONE, "Saving what never save...");
            if(((section = nad_find_elem(pkt->nad, 2, -1, "never",  1))>0)) {
                log_debug(ZONE, "Found never section %d...", section);
                prefs=A_NEVER;
                for(ptr = nad_find_elem(pkt->nad, section, -1, "jid", 1); ptr > 0;
                    ptr = nad_find_elem(pkt->nad, ptr,     -1, "jid", 0)) {
                        o = os_object_new(os);
                        strncpy(buff, NAD_CDATA(pkt->nad, ptr), min(2047,NAD_CDATA_L(pkt->nad, ptr)));
                        buff[min(2047,NAD_CDATA_L(pkt->nad, ptr))]=0;
                        os_object_put(o, "jid",      buff,  os_type_STRING);
                        os_object_put(o, "setting", &prefs, os_type_INTEGER);
                        log_debug(ZONE, "Never archiving %s...", buff);
                }
            }

            // Save everything
            storage_put(pkt->sm->st, tbl_name "_settings", owner, os);
        }

        // Send current settings
        send_arch_prefs(mi, sess, pkt);
        return mod_HANDLED;
    }
    return mod_PASS;
}
Ejemplo n.º 15
0
/**
 * Saves packet into database.
 * @param direct Direction of the message - 2 = incomming, 1 = sent
 */
mod_ret_t savepkt(pkt_t pkt, int direct) {
    int body=-1, sub=-1, type=-1, arch=-1;
    char *mem=NULL;
    const *owner = NULL, *other = NULL;
    int sz = 0;
    int archive=default_mode;
    char filter[2060]; // 2048 is jid_user maximum length
    time_t t=0;
    jid_t own_jid, other_jid;
    os_t os, set_os=NULL;
    os_object_t o, set_o=NULL;

    // Is it a message?
    log_debug(ZONE, "Testing message...");
    if ( (pkt->type & pkt_MESSAGE) == 0)
        return mod_PASS;

    log_debug(ZONE, "It is a message...");

    // 0 element is route, 1st is message, we need subelement of message
    body = nad_find_elem(pkt->nad, 1, -1, "body",    1);
    log_debug(ZONE, "Body is at %d", body);
    sub  = nad_find_elem(pkt->nad, 1, -1, "subject", 1);
    log_debug(ZONE, "Subject is at %d", sub);
    type = nad_find_attr(pkt->nad, 1, -1, "type", NULL);
    log_debug(ZONE, "Type %d", type);

    // Are these parts really interesting?
    if( ( (body < 0) || (NAD_CDATA_L(pkt->nad, body) < 1) ) &&
        ( (sub  < 0) || (NAD_CDATA_L(pkt->nad, sub ) < 1) ) )
        return mod_PASS;

    log_debug(ZONE, "It's meaningful message!", pkt->from);

    // What direction are we talking about?
    if (direct == IN_D) {
        own_jid   = pkt->to;
        other_jid = pkt->from;
    } else {
        own_jid   = pkt->from;
        other_jid = pkt->to;
    }

    // Get JIDs
    if(own_jid != NULL) {
        owner=jid_user(own_jid);
    } else {
        return mod_PASS;
    }
    if(other_jid != NULL) {
        other=jid_user(other_jid);
    } else {
        return mod_PASS;
    }

    // Check settings

    // Load defaults
    snprintf(filter, 2060, "(jid=%s)", owner);
    if((storage_get(pkt->sm->st, tbl_name "_settings", owner, filter, &set_os) == st_SUCCESS) &&
        (os_iter_first(set_os)) && ((set_o=os_iter_object(set_os))!=NULL))
        os_object_get_int(set_os, set_o, "setting", &archive);

    // Cleanup
    if(set_o != NULL) {
        os_object_free(set_o);
        set_o=NULL;
    }
    if(set_os != NULL) {
        os_free(set_os);
        set_os=NULL;
    }

    // Load contact specific
    snprintf(filter, 2060, "(jid=%s)", other);
    if((storage_get(pkt->sm->st, tbl_name "_settings", owner, filter, &set_os) == st_SUCCESS) &&
        (os_iter_first(set_os)) && ((set_o=os_iter_object(set_os))!=NULL))
        os_object_get_int(set_os, set_o, "setting", &archive);

    // Cleanup
    if(set_o != NULL) {
        os_object_free(set_o);
        set_o=NULL;
    }
    if(set_os != NULL) {
        os_free(set_os);
        set_os=NULL;
    }

    // Do we need to check roster?
    if(archive==A_ROSTER) {
        snprintf(filter, 2060, "(jid=%s)", other);
        if(storage_get(pkt->sm->st, "roster-items", owner, filter, &set_os) == st_SUCCESS)
            archive=A_ALWAYS;
        else
            archive=A_NEVER;
        if(set_os != NULL) {
            os_free(set_os);
            set_os=NULL;
        }
    }

    // Decide
    if(archive==A_NEVER)
        return mod_PASS;

    // Prepare to store them
    os = os_new();
    if(os == NULL) return mod_PASS;
    o = os_object_new(os);
    if(o  == NULL) return mod_PASS;

    // Real storing
    log_debug(ZONE, "Saving message for %s (other party is %s)", owner, other);

    // Message

    // Buffer allocation
    if(body > 0) {
        sz = NAD_CDATA_L(pkt->nad, body) / 1024;
        log_debug(ZONE, "Body size %d", NAD_CDATA_L(pkt->nad, body));
    }
    if(sub > 0) {
        sz = max(sz, NAD_CDATA_L(pkt->nad, sub)  / 1024);
        log_debug(ZONE, "Subj size %d", NAD_CDATA_L(pkt->nad, sub));
    }
    log_debug(ZONE, "Creating buffer of size %d", sz);
    mem = (char*)malloc(1024 * (sz+1));
    if(mem == NULL) return mod_PASS;
    log_debug(ZONE, "We got past the buffer allocation.");

    // JID
    os_object_put(o, "other_jid", other, os_type_STRING);

    // Body
    mem[0]=0;
    if ( (body > 0) && (NAD_CDATA_L(pkt->nad, body) > 0) ) {
        strncpy(mem, NAD_CDATA(pkt->nad, body), NAD_CDATA_L(pkt->nad, body));
        mem[NAD_CDATA_L(pkt->nad, body)] = 0;
    }
    os_object_put(o, "message", mem,                        os_type_STRING);

    // Subject
    mem[0]=0;
    if ( (sub  > 0) && (NAD_CDATA_L(pkt->nad, sub ) > 0) ) {
        strncpy(mem, NAD_CDATA(pkt->nad, sub),  NAD_CDATA_L(pkt->nad, sub));
        mem[NAD_CDATA_L(pkt->nad, sub)] = 0;
    }
    os_object_put(o, "subject", mem,                        os_type_STRING);

    // Type
    mem[0]=0;
    if ( (type  > 0) && (NAD_AVAL_L(pkt->nad, type ) > 0) ) {
        strncpy(mem, NAD_AVAL(pkt->nad, type), NAD_AVAL_L(pkt->nad, type));
        mem[NAD_AVAL_L(pkt->nad, type)] = 0;
    }
    os_object_put(o, "type",    mem,                        os_type_STRING);

    // To and from resources
    os_object_put(o, "my_resource",    own_jid->resource,   os_type_STRING);
    os_object_put(o, "other_resource", other_jid->resource, os_type_STRING);

    // Time and direction
    t=time(NULL);
    os_object_put(o, "direct",  &direct,                    os_type_INTEGER);
    os_object_put_time(o, "time",   &t);

    // Message ID
    if (direct == IN_D) {
        arch = nad_insert_elem(pkt->nad, 1, -1, "archived", "");
        nad_set_attr(pkt->nad,arch,-1,"by",jid_user(own_jid), strlen(jid_user(own_jid)));
    }
    set_mid(&(pkt->sm->st), &o, pkt->nad, arch);

    // Save itself
    storage_put(pkt->sm->st, tbl_name, owner, os);

    // Cleanup
    os_object_free(o);
    os_free(os);
    free(mem);
    log_debug(ZONE, "Saved.");

    return mod_PASS;
}
Ejemplo n.º 16
0
/** handler for read data */
void _sx_process_read(sx_t s, sx_buf_t buf) {
    sx_error_t sxe;
    nad_t nad;
    char *errstring;
    int i;
    int ns, elem;

    /* Note that buf->len can validly be 0 here, if we got data from
       the socket but the plugin didn't return anything to us (e.g. a
       SSL packet was split across a tcp segment boundary) */

    /* count bytes parsed */
    s->pbytes += buf->len;

    /* parse it */
    if(XML_Parse(s->expat, buf->data, buf->len, 0) == 0) {
        /* only report error we haven't already */
        if(!s->fail) {
            /* parse error */
            errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));

            _sx_debug(ZONE, "XML parse error: %s, character %d: %.*s",
                      errstring, XML_GetCurrentByteIndex(s->expat) - s->tbytes, buf->len, buf->data);
            _sx_gen_error(sxe, SX_ERR_XML_PARSE, "XML parse error", errstring);
            _sx_event(s, event_ERROR, (void *) &sxe);

            _sx_error(s, stream_err_XML_NOT_WELL_FORMED, errstring);
            _sx_close(s);

            _sx_buffer_free(buf);

            return;
        }

        /* !!! is this the right thing to do? we should probably set
         *     s->fail and let the code further down handle it. */
        _sx_buffer_free(buf);

        return;
    }

    /* check if the stanza size limit is exceeded (it wasn't reset by parser) */
    if(s->rbytesmax && s->pbytes > s->rbytesmax) {
        /* parse error */
        _sx_debug(ZONE, "maximum stanza size (%d) exceeded by reading %d bytes", s->rbytesmax, s->pbytes);

        errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));

        _sx_gen_error(sxe, SX_ERR_XML_PARSE, "stream read error", "Maximum stanza size exceeded");
        _sx_event(s, event_ERROR, (void *) &sxe);

        _sx_error(s, stream_err_POLICY_VIOLATION, errstring);
        _sx_close(s);

        _sx_buffer_free(buf);

        return;
    }

    /* count bytes processed */
    s->tbytes += buf->len;

    /* done with the buffer */
    _sx_buffer_free(buf);

    /* process completed nads */
    if(s->state >= state_STREAM)
        while((nad = jqueue_pull(s->rnadq)) != NULL) {
            int plugin_error;
#ifdef SX_DEBUG
            const char *out; int len;
            nad_print(nad, 0, &out, &len);
            _sx_debug(ZONE, "completed nad: %.*s", len, out);
#endif

            /* check for errors */
            if(NAD_ENS(nad, 0) >= 0 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS) && strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_STREAMS, strlen(uri_STREAMS)) == 0 && NAD_ENAME_L(nad, 0) == 5 && strncmp(NAD_ENAME(nad, 0), "error", 5) == 0) {

                errstring = NULL;

                /* get text error description if available - XMPP 4.7.2 */
                if((ns = nad_find_scoped_namespace(nad, uri_STREAM_ERR, NULL)) >= 0)
                    if((elem = nad_find_elem(nad, 0, ns, "text", 1)) >= 0)
                        if(NAD_CDATA_L(nad, elem) > 0) {
                            errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
                            sprintf(errstring, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
                        }

                /* if not available, look for legacy error text as in <stream:error>description</stream:error> */
                if (errstring == NULL && NAD_CDATA_L(nad, 0) > 0) {
                    errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, 0) + 1));
                    sprintf(errstring, "%.*s", NAD_CDATA_L(nad, 0), NAD_CDATA(nad, 0));
                }

                /* if not available, log the whole packet for debugging */
                if (errstring == NULL) {
                    const char *xml;
                    int xlen;

                    nad_print(nad, 0, &xml, &xlen);
                    errstring = (char *) malloc(sizeof(char) * (xlen + 1));
                    sprintf(errstring, "%.*s", xlen, xml);
                }

                if(s->state < state_CLOSING) {
                    _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", errstring);
                    _sx_event(s, event_ERROR, (void *) &sxe);
                    _sx_state(s, state_CLOSING);
                }

                free(errstring);

                nad_free(nad);

                break;
            }

            /* check for close */
            if ((s->flags & SX_WEBSOCKET_WRAPPER) && NAD_ENS(nad, 0) >= 0 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_XFRAMING) && strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_XFRAMING, strlen(uri_XFRAMING)) == 0 && NAD_ENAME_L(nad, 0) == 5 && strncmp(NAD_ENAME(nad, 0), "close", 5) == 0) {
                _sx_debug(ZONE, "<close/> frame @ depth %d", s->depth);
                s->fail = 1;
                break;
            }

            /* run it by the plugins */
            if(_sx_chain_nad_read(s, nad) == 0)
                return;

            /* now let the plugins process the completed nad */
            plugin_error = 0;
            if(s->env != NULL)
                for(i = 0; i < s->env->nplugins; i++)
                    if(s->env->plugins[i]->process != NULL) {
                        int plugin_ret;
                        plugin_ret = (s->env->plugins[i]->process)(s, s->env->plugins[i], nad);
                        if(plugin_ret == 0) {
                            plugin_error ++;
                            break;
                        }
                    }

            /* hand it to the app */
            if ((plugin_error == 0) && (s->state < state_CLOSING))
                _sx_event(s, event_PACKET, (void *) nad);
        }

    /* something went wrong, bail */
    if(s->fail) {
        _sx_close(s);

        return;
    }

    /* stream was closed */
    if(s->depth < 0 && s->state < state_CLOSING) {
        /* close the stream if necessary */

        if(s->state >= state_STREAM_SENT) {
            if (s->flags & SX_WEBSOCKET_WRAPPER)
                jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0);
            else
                jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
            s->want_write = 1;
        }

        _sx_state(s, state_CLOSING);

        return;
    }
}