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; }