Ejemplo n.º 1
0
static int
_iq_handle_discoinfo_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
    void * const userdata)
{
    log_debug("Recieved diso#info response");
    const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID);
    const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);

    if (g_strcmp0(id, "discoinforeq") == 0) {
        GSList *identities = NULL;
        GSList *features = NULL;

        xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY);

        if (query != NULL) {
            xmpp_stanza_t *child = xmpp_stanza_get_children(query);
            while (child != NULL) {
                const char *stanza_name = xmpp_stanza_get_name(child);
                if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) {
                    const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR);
                    if (var != NULL) {
                        features = g_slist_append(features, strdup(var));
                    }
                } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) {
                    const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME);
                    const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE);
                    const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY);

                    if ((name != NULL) || (category != NULL) || (type != NULL)) {
                        DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t));

                        if (name != NULL) {
                            identity->name = strdup(name);
                        } else {
                            identity->name = NULL;
                        }
                        if (category != NULL) {
                            identity->category = strdup(category);
                        } else {
                            identity->category = NULL;
                        }
                        if (type != NULL) {
                            identity->type = strdup(type);
                        } else {
                            identity->type = NULL;
                        }

                        identities = g_slist_append(identities, identity);
                    }
                }

                child = xmpp_stanza_get_next(child);
            }

            handle_disco_info(from, identities, features);
            g_slist_free_full(features, free);
            g_slist_free_full(identities, (GDestroyNotify)_identity_destroy);
        }
    } else if ((id != NULL) && (g_str_has_prefix(id, "capsreq"))) {
        log_debug("Response to query: %s", id);
        xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY);
        char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE);
        if (node == NULL) {
            return 1;
        }

        char *caps_key = NULL;

        // xep-0115
        if (g_strcmp0(id, "capsreq") == 0) {
            log_debug("xep-0115 supported capabilities");
            caps_key = strdup(node);

            // validate sha1
            gchar **split = g_strsplit(node, "#", -1);
            char *given_sha1 = split[1];
            char *generated_sha1 = caps_create_sha1_str(query);

            if (g_strcmp0(given_sha1, generated_sha1) != 0) {
                log_info("Generated sha-1 does not match given:");
                log_info("Generated : %s", generated_sha1);
                log_info("Given     : %s", given_sha1);
                g_free(generated_sha1);
                g_strfreev(split);
                free(caps_key);

                return 1;
            }
            g_free(generated_sha1);
            g_strfreev(split);

        // non supported hash, or legacy caps
        } else {
            log_debug("Unsupported hash, or legacy capabilities");
            caps_key = strdup(id + 8);
            log_debug("Caps key: %s", caps_key);
        }

        // already cached
        if (caps_contains(caps_key)) {
            log_info("Client info already cached.");
            free(caps_key);
            return 1;
        }

        log_debug("Client info not cached");

        const char *category = NULL;
        const char *type = NULL;
        const char *name = NULL;
        const char *software = NULL;
        const char *software_version = NULL;
        const char *os = NULL;
        const char *os_version = NULL;
        GSList *features = NULL;

        xmpp_stanza_t *identity = xmpp_stanza_get_child_by_name(query, "identity");
        if (identity != NULL) {
            category = xmpp_stanza_get_attribute(identity, "category");
            type = xmpp_stanza_get_attribute(identity, "type");
            name = xmpp_stanza_get_attribute(identity, "name");
        }

        xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA);
        if (softwareinfo != NULL) {
            DataForm *form = stanza_create_form(softwareinfo);
            FormField *formField = NULL;

            if (g_strcmp0(form->form_type, STANZA_DATAFORM_SOFTWARE) == 0) {
                GSList *field = form->fields;
                while (field != NULL) {
                    formField = field->data;
                    if (formField->values != NULL) {
                        if (strcmp(formField->var, "software") == 0) {
                            software = formField->values->data;
                        } else if (strcmp(formField->var, "software_version") == 0) {
                            software_version = formField->values->data;
                        } else if (strcmp(formField->var, "os") == 0) {
                            os = formField->values->data;
                        } else if (strcmp(formField->var, "os_version") == 0) {
                            os_version = formField->values->data;
                        }
                    }
                    field = g_slist_next(field);
                }
            }

            stanza_destroy_form(form);
        }

        xmpp_stanza_t *child = xmpp_stanza_get_children(query);
        while (child != NULL) {
            if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) {
                features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var")));
            }

            child = xmpp_stanza_get_next(child);
        }

        caps_add(caps_key, category, type, name, software, software_version,
            os, os_version, features);

        free(caps_key);
    }

    return 1;
}
Ejemplo n.º 2
0
char *
caps_create_sha1_str(xmpp_stanza_t * const query)
{
    char *category = NULL;
    char *type = NULL;
    char *lang = NULL;
    char *name = NULL;
    char *feature_str = NULL;
    GSList *identities = NULL;
    GSList *features = NULL;
    GSList *form_names = NULL;
    DataForm *form = NULL;
    FormField *field = NULL;
    GHashTable *forms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)stanza_destroy_form);

    GString *s = g_string_new("");

    xmpp_stanza_t *child = xmpp_stanza_get_children(query);
    while (child != NULL) {
        if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_IDENTITY) == 0) {
            category = xmpp_stanza_get_attribute(child, "category");
            type = xmpp_stanza_get_attribute(child, "type");
            lang = xmpp_stanza_get_attribute(child, "xml:lang");
            name = xmpp_stanza_get_attribute(child, "name");

            GString *identity_str = g_string_new(category);
            g_string_append(identity_str, "/");
            if (type != NULL) {
                g_string_append(identity_str, type);
            }
            g_string_append(identity_str, "/");
            if (lang != NULL) {
                g_string_append(identity_str, lang);
            }
            g_string_append(identity_str, "/");
            if (name != NULL) {
                g_string_append(identity_str, name);
            }
            g_string_append(identity_str, "<");
            identities = g_slist_insert_sorted(identities, g_strdup(identity_str->str), (GCompareFunc)strcmp);
            g_string_free(identity_str, TRUE);
        } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_FEATURE) == 0) {
            feature_str = xmpp_stanza_get_attribute(child, "var");
            features = g_slist_insert_sorted(features, g_strdup(feature_str), (GCompareFunc)strcmp);
        } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_X) == 0) {
            if (strcmp(xmpp_stanza_get_ns(child), STANZA_NS_DATA) == 0) {
                form = stanza_create_form(child);
                form_names = g_slist_insert_sorted(form_names, g_strdup(form->form_type), (GCompareFunc)strcmp);
                g_hash_table_insert(forms, g_strdup(form->form_type), form);
            }
        }
        child = xmpp_stanza_get_next(child);
    }

    GSList *curr = identities;
    while (curr != NULL) {
        g_string_append(s, curr->data);
        curr = g_slist_next(curr);
    }

    curr = features;
    while (curr != NULL) {
        g_string_append(s, curr->data);
        g_string_append(s, "<");
        curr = g_slist_next(curr);
    }

    curr = form_names;
    while (curr != NULL) {
        form = g_hash_table_lookup(forms, curr->data);
        g_string_append(s, form->form_type);
        g_string_append(s, "<");

        GSList *curr_field = form->fields;
        while (curr_field != NULL) {
            field = curr_field->data;
            g_string_append(s, field->var);
            g_string_append(s, "<");
            GSList *curr_value = field->values;
            while (curr_value != NULL) {
                g_string_append(s, curr_value->data);
                g_string_append(s, "<");
                curr_value = g_slist_next(curr_value);
            }
            curr_field = g_slist_next(curr_field);
        }

        curr = g_slist_next(curr);
    }

    EVP_MD_CTX mdctx;
    const EVP_MD *md;

    unsigned char md_value[EVP_MAX_MD_SIZE];
    unsigned int md_len;
    OpenSSL_add_all_digests();
    md = EVP_get_digestbyname("SHA1");
    EVP_MD_CTX_init(&mdctx);
    EVP_DigestInit_ex(&mdctx, md, NULL);
    EVP_DigestUpdate(&mdctx, s->str, strlen(s->str));
    EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
    EVP_MD_CTX_cleanup(&mdctx);

    char *result = g_base64_encode(md_value, md_len);

    g_string_free(s, TRUE);
    g_slist_free_full(identities, g_free);
    g_slist_free_full(features, g_free);
    g_slist_free_full(form_names, g_free);
    g_hash_table_destroy(forms);

    return result;
}