Exemple #1
0
int cli_pcre_addpatt(struct cli_matcher *root, const char *virname, const char *trigger, const char *pattern, const char *cflags, const char *offset, const uint32_t *lsigid, unsigned int options)
{
    struct cli_pcre_meta **newmetatable = NULL, *pm = NULL;
    uint32_t pcre_count;
    const char *opt;
    int ret = CL_SUCCESS, rssigs;

    if (!root || !trigger || !pattern || !offset) {
        cli_errmsg("cli_pcre_addpatt: NULL root or NULL trigger or NULL pattern or NULL offset\n");
        return CL_ENULLARG;
    }

    /* TODO: trigger and regex checking (backreference limitations?) (control pattern limitations?) */
    /* cli_ac_chklsig will fail a empty trigger; empty patterns can cause an infinite loop */
    if (*trigger == '\0' || *pattern == '\0') {
        cli_errmsg("cli_pcre_addpatt: trigger or pattern cannot be an empty string\n");
        return CL_EMALFDB;
    }
    if (cflags && *cflags == '\0') {
        cflags = NULL;
    }

    if (lsigid)
        pm_dbgmsg("cli_pcre_addpatt: Adding /%s/%s%s triggered on (%s) as subsig %d for lsigid %d\n", 
                  pattern, cflags ? " with flags " : "", cflags ? cflags : "", trigger, lsigid[1], lsigid[0]);
    else
        pm_dbgmsg("cli_pcre_addpatt: Adding /%s/%s%s triggered on (%s) [no lsigid]\n",
                  pattern, cflags ? " with flags " : "", cflags ? cflags : "", trigger);

#ifdef PCRE_BYPASS
    /* check for trigger bypass */
    if (strcmp(trigger, PCRE_BYPASS)) {
#endif
        /* validate the lsig trigger */
        rssigs = cli_ac_chklsig(trigger, trigger + strlen(trigger), NULL, NULL, NULL, 1);
        if(rssigs == -1) {
            cli_errmsg("cli_pcre_addpatt: regex subsig /%s/ is missing a valid logical trigger\n", pattern);
            return CL_EMALFDB;
        }

        if (lsigid) {
            if (rssigs > lsigid[1]) {
                cli_errmsg("cli_pcre_addpatt: regex subsig %d logical trigger refers to subsequent subsig %d\n", lsigid[1], rssigs);
                return CL_EMALFDB;
            }
            if (rssigs == lsigid[1]) {
                cli_errmsg("cli_pcre_addpatt: regex subsig %d logical trigger is self-referential\n", lsigid[1]);
                return CL_EMALFDB;
            }
        }
        else {
            cli_dbgmsg("cli_pcre_addpatt: regex subsig is missing lsigid data\n");
        }
#ifdef PCRE_BYPASS
    }
#endif

    /* allocating entries */
    pm = (struct cli_pcre_meta *)mpool_calloc(root->mempool, 1, sizeof(*pm));
    if (!pm) {
        cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for new pcre meta\n");
        return CL_EMEM;
    }

    pm->trigger = cli_mpool_strdup(root->mempool, trigger);
    if (!pm->trigger) {
        cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for trigger string\n");
        cli_pcre_freemeta(root, pm);
        mpool_free(root->mempool, pm);
        return CL_EMEM;
    }

    pm->virname = (char *)cli_mpool_virname(root->mempool, virname, options & CL_DB_OFFICIAL);
    if(!pm->virname) {
        cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for virname or NULL virname\n");
        cli_pcre_freemeta(root, pm);
        mpool_free(root->mempool, pm);
        return CL_EMEM;
    }

    if (lsigid) {
        root->ac_lsigtable[lsigid[0]]->virname = pm->virname;

        pm->lsigid[0] = 1;
        pm->lsigid[1] = lsigid[0];
        pm->lsigid[2] = lsigid[1];
    }
    else {
        /* sigtool */
        pm->lsigid[0] = 0;
    }

    pm->pdata.expression = strdup(pattern);
    if (!pm->pdata.expression) {
        cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for expression\n");
        cli_pcre_freemeta(root, pm);
        mpool_free(root->mempool, pm);
        return CL_EMEM;
    }

    /* offset parsing and usage, similar to cli_ac_addsig */
    /* relative and type-specific offsets handled during scan */
    ret = cli_caloff(offset, NULL, root->type, pm->offdata, &(pm->offset_min), &(pm->offset_max));
    if (ret != CL_SUCCESS) {
        cli_errmsg("cli_pcre_addpatt: cannot calculate offset data: %s for pattern: %s\n", offset, pattern);
        cli_pcre_freemeta(root, pm);
        mpool_free(root->mempool, pm);
        return ret;
    }
    if(pm->offdata[0] != CLI_OFF_ANY) {
        if(pm->offdata[0] == CLI_OFF_ABSOLUTE)
            root->pcre_absoff_num++;
        else
            root->pcre_reloff_num++;
    }

    /* parse and add options, also totally not from snort */
    if (cflags) {
        opt = cflags;

        /* cli_pcre_addoptions handles pcre specific options */
        while (cli_pcre_addoptions(&(pm->pdata), &opt, 0) != CL_SUCCESS) {
            /* handle matcher specific options here */
            switch (*opt) {
            case 'g':  pm->flags |= CLI_PCRE_GLOBAL;            break;
            case 'r':  pm->flags |= CLI_PCRE_ROLLING;           break;
            case 'e':  pm->flags |= CLI_PCRE_ENCOMPASS;         break;
            default:
                cli_errmsg("cli_pcre_addpatt: unknown/extra pcre option encountered %c\n", *opt);
                cli_pcre_freemeta(root, pm);
                mpool_free(root->mempool, pm);
                return CL_EMALFDB;
            }
            opt++;
        }

        if (pm->flags) {
            pm_dbgmsg("Matcher:  %s%s%s\n",
                      pm->flags & CLI_PCRE_GLOBAL ? "CLAMAV_GLOBAL " : "",
                      pm->flags & CLI_PCRE_ROLLING ? "CLAMAV_ROLLING " : "",
                      pm->flags & CLI_PCRE_ENCOMPASS ? "CLAMAV_ENCOMPASS " : "");
        }
        else
            pm_dbgmsg("Matcher:  NONE\n");

        if (pm->pdata.options) {
#if USING_PCRE2
            pm_dbgmsg("Compiler: %s%s%s%s%s%s%s\n",
                      pm->pdata.options & PCRE2_CASELESS ? "PCRE2_CASELESS " : "",
                      pm->pdata.options & PCRE2_DOTALL ? "PCRE2_DOTALL " : "",
                      pm->pdata.options & PCRE2_MULTILINE ? "PCRE2_MULTILINE " : "",
                      pm->pdata.options & PCRE2_EXTENDED ? "PCRE2_EXTENDED " : "",

                      pm->pdata.options & PCRE2_ANCHORED ? "PCRE2_ANCHORED " : "",
                      pm->pdata.options & PCRE2_DOLLAR_ENDONLY ? "PCRE2_DOLLAR_ENDONLY " : "",
                      pm->pdata.options & PCRE2_UNGREEDY ? "PCRE2_UNGREEDY " : "");
#else
            pm_dbgmsg("Compiler: %s%s%s%s%s%s%s\n",
                      pm->pdata.options & PCRE_CASELESS ? "PCRE_CASELESS " : "",
                      pm->pdata.options & PCRE_DOTALL ? "PCRE_DOTALL " : "",
                      pm->pdata.options & PCRE_MULTILINE ? "PCRE_MULTILINE " : "",
                      pm->pdata.options & PCRE_EXTENDED ? "PCRE_EXTENDED " : "",

                      pm->pdata.options & PCRE_ANCHORED ? "PCRE_ANCHORED " : "",
                      pm->pdata.options & PCRE_DOLLAR_ENDONLY ? "PCRE_DOLLAR_ENDONLY " : "",
                      pm->pdata.options & PCRE_UNGREEDY ? "PCRE_UNGREEDY " : "");
#endif
        }
        else
            pm_dbgmsg("Compiler: NONE\n");
    }

    /* add metadata to the performance tracker */
    if (options & CL_DB_PCRE_STATS)
        pcre_perf_events_init(pm, virname);

    /* add pcre data to root after reallocation */
    pcre_count = root->pcre_metas+1;
    newmetatable = (struct cli_pcre_meta **)mpool_realloc(root->mempool, root->pcre_metatable,
                                         pcre_count * sizeof(struct cli_pcre_meta *));
    if (!newmetatable) {
        cli_errmsg("cli_pcre_addpatt: Unable to allocate memory for new pcre meta table\n");
        cli_pcre_freemeta(root, pm);
        mpool_free(root->mempool, pm);
        return CL_EMEM;
    }

    newmetatable[pcre_count-1] = pm;
    root->pcre_metatable = newmetatable;

    root->pcre_metas = pcre_count;

    return CL_SUCCESS;
}
int openioc_parse(const char * fname, int fd, struct cl_engine *engine, unsigned int options)
{
    int rc;
    xmlTextReaderPtr reader = NULL;
    const xmlChar * name;
    struct openioc_hash * elems = NULL, * elem = NULL;
    const char * iocp = NULL;
    uint16_t ioclen;
    char * virusname;
    int hash_count = 0;
    
    if (fname == NULL)
        return CL_ENULLARG;

    if (fd < 0)
        return CL_EARG;

    cli_dbgmsg("openioc_parse: XML parsing file %s\n", fname);

    reader = xmlReaderForFd(fd, NULL, NULL, CLAMAV_MIN_XMLREADER_FLAGS);
    if (reader == NULL) {
        cli_dbgmsg("openioc_parse: xmlReaderForFd error\n");
        return CL_EOPEN;
    }
    rc = xmlTextReaderRead(reader);
    while (rc == 1) {
        name = xmlTextReaderConstLocalName(reader);
        cli_dbgmsg("openioc_parse: xmlTextReaderRead read %s\n", name);
        if (xmlStrEqual(name, (const xmlChar *)"Indicator") && 
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
            rc = openioc_parse_indicator(reader, &elems);
            if (rc != CL_SUCCESS) {
                xmlTextReaderClose(reader);
                xmlFreeTextReader(reader);
                return rc;
            }
        }
        if (xmlStrEqual(name, (const xmlChar *)"ioc") &&
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
            break;
        }
        rc = xmlTextReaderRead(reader);
    }

    iocp = strrchr(fname, *PATHSEP);

    if (NULL == iocp)
        iocp = fname;
    else
        iocp++;

    ioclen = strlen(fname);

    if (elems != NULL) {
        if (NULL == engine->hm_hdb) {
            engine->hm_hdb = mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher));
            if (NULL == engine->hm_hdb) {            
                xmlTextReaderClose(reader);
                xmlFreeTextReader(reader);
                return CL_EMEM;
            }
#ifdef USE_MPOOL
            engine->hm_hdb->mempool = engine->mempool;
#endif
        }
    }

    while (elems != NULL) {
        const char * sp;
        char * hash, * vp;
        int i, hashlen;

        elem = elems;
        elems = elems->next;
        hash = (char *)(elem->hash);
        while (isspace(*hash))
            hash++;
        hashlen = strlen(hash);
        if (hashlen == 0) {
            xmlFree(elem->hash);
            free(elem);
            continue;
        }
        vp = hash+hashlen-1;
        while (isspace(*vp) && vp > hash) {
            *vp-- = '\0';
            hashlen--;
        }
        virusname = calloc(1, ioclen+hashlen+2);
        if (NULL == virusname) {
            cli_dbgmsg("openioc_parse: mpool_malloc for virname memory failed.\n");
            xmlTextReaderClose(reader);
            xmlFreeTextReader(reader);
            return CL_EMEM;
        }
        sp = fname;
        vp = virusname;
        for (i=0; i<ioclen; i++, sp++, vp++) {
            switch (*sp) {
            case '\\':
            case '/':
            case '?':
            case '%':
            case '*':
            case ':':
            case '|':
            case '"':
            case '<':
            case '>':
                *vp = '_';
                break;
            default:
                if (isspace(*sp))
                    *vp = '_';
                else
                    *vp = *sp;
            }
        }
        *vp++ = '.';
        sp = hash;
        for (i=0; i<hashlen; i++, sp++) {
            if (isxdigit(*sp)) {
                *vp++ = *sp;
            }
        }

        vp = virusname;
        virusname = cli_mpool_virname(engine->mempool, virusname, options & CL_DB_OFFICIAL);
        if (!(virusname)) {
            cli_dbgmsg("openioc_parse: mpool_malloc for virname memory failed.\n");
            xmlTextReaderClose(reader);
            xmlFreeTextReader(reader);
            free(vp);
            return CL_EMEM;
        }

        free(vp);

        rc = hm_addhash_str(engine->hm_hdb, hash, 0, virusname);
        if (rc != CL_SUCCESS)
            cli_dbgmsg("openioc_parse: hm_addhash_str failed with %i hash len %i for %s.\n",
                       rc, hashlen, virusname);
        else
            hash_count++;

        xmlFree(elem->hash);
        free(elem);
    }

    if (hash_count == 0)
        cli_warnmsg("openioc_parse: No hash signatures extracted from %s.\n", fname);
    else
        cli_dbgmsg("openioc_parse: %i hash signature%s extracted from %s.\n",
                   hash_count, hash_count==1?"":"s", fname);

    xmlTextReaderClose(reader);
    xmlFreeTextReader(reader);

    return CL_SUCCESS;
}