Esempio n. 1
0
static int ooxml_content_cb(int fd, cli_ctx *ctx)
{
    int ret = CL_SUCCESS, tmp, toval = 0, state;
    int core=0, extn=0, cust=0, dsig=0;
    int mcore=0, mextn=0, mcust=0;
    const xmlChar *name, *value, *CT, *PN;
    xmlTextReaderPtr reader = NULL;
    uint32_t loff;

    unsigned long sav_scansize = ctx->scansize;
    unsigned int sav_scannedfiles = ctx->scannedfiles;

    cli_dbgmsg("in ooxml_content_cb\n");

    /* perform engine limit checks in temporary tracking session */
    ret = ooxml_updatelimits(fd, ctx);
    if (ret != CL_CLEAN)
        return ret;

    /* apply a reader to the document */
    reader = xmlReaderForFd(fd, "[Content_Types].xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS);
    if (reader == NULL) {
        cli_dbgmsg("ooxml_content_cb: xmlReaderForFd error for ""[Content_Types].xml""\n");
        cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_FD");

        ctx->scansize = sav_scansize;
        ctx->scannedfiles = sav_scannedfiles;
        return CL_SUCCESS; // libxml2 failed!
    }

    /* locate core-properties, extended-properties, and custom-properties (optional) */
    while ((state = xmlTextReaderRead(reader)) == 1) {
        if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
            ret = CL_ETIMEOUT;
            goto ooxml_content_exit;
        }

        name = xmlTextReaderConstLocalName(reader);
        if (name == NULL) continue;

        if (strcmp((const char *)name, "Override")) continue;

        if (xmlTextReaderHasAttributes(reader) != 1) continue;

        CT = PN = NULL;
        while (xmlTextReaderMoveToNextAttribute(reader) == 1) {
            name = xmlTextReaderConstLocalName(reader);
            value = xmlTextReaderConstValue(reader);
            if (name == NULL || value == NULL) continue;

            if (!xmlStrcmp(name, (const xmlChar *)"ContentType")) {
                CT = value;
            }
            else if (!xmlStrcmp(name, (const xmlChar *)"PartName")) {
                PN = value;
            }

            cli_dbgmsg("%s: %s\n", name, value);
        }

        if (!CT && !PN) continue;

        if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-package.core-properties+xml")) {
            /* default: /docProps/core.xml*/
            tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff);
            if (tmp == CL_ETIMEOUT) {
                ret = tmp;
            }
            else if (tmp != CL_VIRUS) {
                cli_dbgmsg("cli_process_ooxml: failed to find core properties file \"%s\"!\n", PN);
                mcore++;
            }
            else {
                cli_dbgmsg("ooxml_content_cb: found core properties file \"%s\" @ %x\n", PN, loff);
                if (!core) {
                    tmp = unzip_single_internal(ctx, loff, ooxml_core_cb);
                    if (tmp == CL_ETIMEOUT || tmp == CL_EMEM) {
                        ret = tmp;
                    }
                }
                core++;
            }
        }
        else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-officedocument.extended-properties+xml")) {
            /* default: /docProps/app.xml */
            tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff);
            if (tmp == CL_ETIMEOUT) {
                ret = tmp;
            }
            else if (tmp != CL_VIRUS) {
                cli_dbgmsg("cli_process_ooxml: failed to find extended properties file \"%s\"!\n", PN);
                mextn++;
            }
            else {
                cli_dbgmsg("ooxml_content_cb: found extended properties file \"%s\" @ %x\n", PN, loff);
                if (!extn) {
                    tmp = unzip_single_internal(ctx, loff, ooxml_extn_cb);
                    if (tmp == CL_ETIMEOUT || tmp == CL_EMEM) {
                        ret = tmp;
                    }
                }
                extn++;
            }
        }
        else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-officedocument.custom-properties+xml")) {
            /* default: /docProps/custom.xml */
            tmp = unzip_search_single(ctx, (const char *)(PN+1), xmlStrlen(PN)-1, &loff);
            if (tmp == CL_ETIMEOUT) {
                ret = tmp;
            }
            else if (tmp != CL_VIRUS) {
                cli_dbgmsg("cli_process_ooxml: failed to find custom properties file \"%s\"!\n", PN);
                mcust++;
            }
            else {
                cli_dbgmsg("ooxml_content_cb: found custom properties file \"%s\" @ %x\n", PN, loff);
                /* custom properties are not parsed */
                cust++;
            }
        }
        else if (!xmlStrcmp(CT, (const xmlChar *)"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml")) {
            dsig++;
        }

        if (ret != CL_SUCCESS)
            goto ooxml_content_exit;
    }

 ooxml_content_exit:
    if (core) {
        cli_jsonint(ctx->wrkproperty, "CorePropertiesFileCount", core);
        if (core > 1)
            cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES");
    }
    else if (!mcore)
        cli_dbgmsg("cli_process_ooxml: file does not contain core properties file\n");
    if (mcore) {
        cli_jsonint(ctx->wrkproperty, "CorePropertiesMissingFileCount", mcore);
        cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CORE_PROPFILES");
    }

    if (extn) {
        cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesFileCount", extn);
        if (extn > 1)
            cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES");
    }
    else if (!mextn)
        cli_dbgmsg("cli_process_ooxml: file does not contain extended properties file\n");
    if (mextn) {
        cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesMissingFileCount", mextn);
        cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_EXTN_PROPFILES");
    }

    if (cust) {
        cli_jsonint(ctx->wrkproperty, "CustomPropertiesFileCount", cust);
        if (cust > 1)
            cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES");
    }
    else if (!mcust)
        cli_dbgmsg("cli_process_ooxml: file does not contain custom properties file\n");
    if (mcust) {
        cli_jsonint(ctx->wrkproperty, "CustomPropertiesMissingFileCount", mcust);
        cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CUST_PROPFILES");
    }

    if (dsig) {
        cli_jsonint(ctx->wrkproperty, "DigitalSignaturesCount", dsig);
    }

    /* restore the engine tracking limits; resets session limit tracking */
    ctx->scansize = sav_scansize;
    ctx->scannedfiles = sav_scannedfiles;

    xmlTextReaderClose(reader);
    xmlFreeTextReader(reader);
    return ret;
}
Esempio n. 2
0
static int ooxml_basic_json(int fd, cli_ctx *ctx, const char *key)
{
    int ret = CL_SUCCESS;
    const xmlChar *stack[OOXML_JSON_RECLEVEL];
    json_object *summary, *wrkptr;
    int type, rlvl = 0;
    int32_t val2;
    const xmlChar *name, *value;
    xmlTextReaderPtr reader = NULL;

    cli_dbgmsg("in ooxml_basic_json\n");

    reader = xmlReaderForFd(fd, "properties.xml", NULL, 0);
    if (reader == NULL) {
        cli_dbgmsg("ooxml_basic_json: xmlReaderForFd error for %s\n", key);
        return CL_SUCCESS; // libxml2 failed!
    }

    summary = json_object_new_object();
    if (NULL == summary) {
        cli_errmsg("ooxml_basic_json: no memory for json object.\n");
        ret = CL_EFORMAT;
        goto ooxml_basic_exit;
    }

    while (xmlTextReaderRead(reader) == 1) {
        name = xmlTextReaderConstLocalName(reader);
        value = xmlTextReaderConstValue(reader);
        type = xmlTextReaderNodeType(reader);

        cli_dbgmsg("%s [%i]: %s\n", name, type, value);

        switch (type) {
        case XML_READER_TYPE_ELEMENT:
            stack[rlvl] = name;
            rlvl++;
            break;
        case XML_READER_TYPE_TEXT:
            {
                wrkptr = summary;
                if (rlvl > 2) { /* 0 is root xml object */
                    int i;
                    for (i = 1; i < rlvl-1; ++i) {
                        json_object *newptr = json_object_object_get(wrkptr, stack[i]);
                        if (!newptr) {
                            newptr = json_object_new_object();
                            if (NULL == newptr) {
                                cli_errmsg("ooxml_basic_json: no memory for json object.\n");
                                ret = CL_EMEM;
                                goto ooxml_basic_exit;
                            }
                            json_object_object_add(wrkptr, stack[i], newptr);
                        }
                        else {
                            /* object already exists */
                            if (!json_object_is_type(newptr, json_type_object)) {
                                cli_warnmsg("ooxml_content_cb: json object already exists as not an object\n");
                                ret = CL_EFORMAT;
                                goto ooxml_basic_exit;
                            } 
                        }
                        wrkptr = newptr;
                        cli_dbgmsg("stack %d: %s\n", i, stack[i]);
                    }
                }
                
                if (ooxml_is_int(value, xmlStrlen(value), &val2)) {
                    ret = cli_jsonint(wrkptr, stack[rlvl-1], val2);
                }
                else if (!xmlStrcmp(value, "true")) {
                    ret = cli_jsonbool(wrkptr, stack[rlvl-1], 1);
                }
                else if (!xmlStrcmp(value, "false")) {
                    ret = cli_jsonbool(wrkptr, stack[rlvl-1], 0);
                }
                else {
                    ret = cli_jsonstr(wrkptr, stack[rlvl-1], value);
                }

                if (ret != CL_SUCCESS)
                    goto ooxml_basic_exit;
            }
            break;
        case XML_READER_TYPE_END_ELEMENT:
            rlvl--;
            break;
        default:
            cli_dbgmsg("ooxml_content_cb: unhandled xml node %s [%i]: %s\n", name, type, value);
            ret = CL_EFORMAT;
            goto ooxml_basic_exit;
        }
    }

    json_object_object_add(ctx->wrkproperty, key, summary);

    if (rlvl != 0) {
        cli_warnmsg("ooxml_basic_json: office property file has unbalanced tags\n");
        /* FAIL */
    }

 ooxml_basic_exit:
    xmlTextReaderClose(reader);
    xmlFreeTextReader(reader);
    return ret;
}
Esempio n. 3
0
int cli_jsonint_array(json_object *obj, int32_t val)
{
    return cli_jsonint(obj, NULL, val);
}
Esempio n. 4
0
static int ooxml_parse_element(xmlTextReaderPtr reader, json_object *wrkptr, int rlvl, int skip)
{
    const char *element_tag = NULL, *end_tag = NULL;
    const xmlChar *node_name = NULL, *node_value = NULL;
    json_object *njptr;
    int node_type, ret = CL_SUCCESS;
    int32_t val2;

    cli_dbgmsg("in ooxml_parse_element @ layer %d\n", rlvl);

    /* check recursion level */
    if (rlvl >= OOXML_JSON_RECLEVEL_MAX) {
        return CL_EMAXREC;
    }

    if (wrkptr == NULL) {
        skip = 1;
    }

    /* acquire element type */
    node_type = xmlTextReaderNodeType(reader);
    if (node_type != XML_READER_TYPE_ELEMENT) {
        cli_dbgmsg("ooxml_parse_element: first node typed %d, not %d\n", node_type, XML_READER_TYPE_ELEMENT);
        return CL_EPARSE; /* first type is not an element */
    }

    /* acquire element tag */
    node_name = xmlTextReaderConstLocalName(reader);
    if (!node_name) {
        cli_dbgmsg("ooxml_parse_element: element tag node nameless\n");
        return CL_EPARSE; /* no name, nameless */
    }
    element_tag = ooxml_check_key(node_name, xmlStrlen(node_name));
    if (!element_tag) {
        cli_dbgmsg("ooxml_parse_element: invalid element tag [%s]\n", node_name);
        skip = 1; /* skipping element */
        //return CL_EFORMAT; /* REMOVE */
    }

    /* handle attributes if you want */

    /* loop across all element contents */
    while (xmlTextReaderRead(reader) == 1) {
        node_type = xmlTextReaderNodeType(reader);
        switch (node_type) {
        case XML_READER_TYPE_ELEMENT:
            if (!skip) {
                njptr = json_object_object_get(wrkptr, element_tag);
                if (!njptr) {
                    njptr = json_object_new_object();
                    if (NULL == njptr) {
                        cli_errmsg("ooxml_basic_json: no memory for json object.\n");
                        return CL_EMEM;
                    }
                    cli_dbgmsg("ooxml_basic_json: added json object [%s]\n", element_tag);
                    json_object_object_add(wrkptr, element_tag, njptr);
                }
                else {
                    if (!json_object_is_type(njptr, json_type_object)) {
                        cli_warnmsg("ooxml_content_cb: json object [%s] already exists as not an object\n", element_tag);
                        return CL_EFORMAT;
                    }
                }
            }
            else {
                njptr = NULL;
            } 

            ret = ooxml_parse_element(reader, njptr, rlvl+1, skip);
            if (ret != CL_SUCCESS) {
                return ret;
            }
            break;
        case XML_READER_TYPE_END_ELEMENT:
            cli_dbgmsg("in ooxml_parse_element @ layer %d closed\n", rlvl);
            node_name = xmlTextReaderConstLocalName(reader);
            if (!node_name) {
                cli_dbgmsg("ooxml_parse_element: element end tag node nameless\n");
                return CL_EPARSE; /* no name, nameless */
            }
            if (!skip) {
                end_tag = ooxml_check_key(node_name, xmlStrlen(node_name));
                if (!end_tag) {
                    cli_dbgmsg("ooxml_parse_element: invalid element end tag [%s]\n", node_name);
                    return CL_EFORMAT; /* unrecognized element tag */
                }
                if (strncmp(element_tag, end_tag, strlen(element_tag))) {
                    cli_dbgmsg("ooxml_parse_element: element tag does not match end tag\n");
                    return CL_EFORMAT;
                }
            }
            return CL_SUCCESS;
        case XML_READER_TYPE_TEXT:
            if (!skip) {
                node_value = xmlTextReaderConstValue(reader);
                njptr = json_object_object_get(wrkptr, element_tag);
                if (njptr) {
                    cli_warnmsg("ooxml_parse_element: json object [%s] already exists\n", element_tag);
                }

                if (ooxml_is_int(node_value, xmlStrlen(node_value), &val2)) {
                    ret = cli_jsonint(wrkptr, element_tag, val2);
                }
                else if (!xmlStrcmp(node_value, "true")) {
                    ret = cli_jsonbool(wrkptr, element_tag, 1);
                }
                else if (!xmlStrcmp(node_value, "false")) {
                    ret = cli_jsonbool(wrkptr, element_tag, 0);
                }
                else {
                    ret = cli_jsonstr(wrkptr, element_tag, node_value);
                }

                if (ret != CL_SUCCESS)
                    return ret;

                cli_dbgmsg("ooxml_basic_json: added json value [%s: %s]\n", element_tag, node_value);
            }
            else {
                node_name = xmlTextReaderConstLocalName(reader);
                node_value = xmlTextReaderConstValue(reader);

                cli_dbgmsg("ooxml_parse_element: not adding xml node %s [%d]: %s\n", node_name, node_type, node_value);
            }
            break;
        default:
            node_name = xmlTextReaderConstLocalName(reader);
            node_value = xmlTextReaderConstValue(reader);

            cli_dbgmsg("ooxml_parse_element: unhandled xml node %s [%d]: %s\n", node_name, node_type, node_value);
            return CL_EPARSE;
        }
    }

    return CL_SUCCESS;
}