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 cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern) { struct cli_ac_node *pt, *next; struct cli_ac_patt *ph; void *newtable; struct cli_ac_alt *a1, *a2; uint8_t i, match; uint16_t len = MIN(root->ac_maxdepth, pattern->length); for(i = 0; i < len; i++) { if(pattern->pattern[i] & CLI_MATCH_WILDCARD) { len = i; break; } } if(len < root->ac_mindepth) { /* cli_errmsg("cli_ac_addpatt: Signature for %s is too short\n", pattern->virname); */ return CL_EMALFDB; } pt = root->ac_root; for(i = 0; i < len; i++) { if(!pt->trans) { pt->trans = (struct cli_ac_node **) mpool_calloc(root->mempool, 256, sizeof(struct cli_ac_node *)); if(!pt->trans) { cli_errmsg("cli_ac_addpatt: Can't allocate memory for pt->trans\n"); return CL_EMEM; } } next = pt->trans[(unsigned char) (pattern->pattern[i] & 0xff)]; if(!next) { next = (struct cli_ac_node *) mpool_calloc(root->mempool, 1, sizeof(struct cli_ac_node)); if(!next) { cli_errmsg("cli_ac_addpatt: Can't allocate memory for AC node\n"); return CL_EMEM; } if(i != len - 1) { next->trans = (struct cli_ac_node **) mpool_calloc(root->mempool, 256, sizeof(struct cli_ac_node *)); if(!next->trans) { cli_errmsg("cli_ac_addpatt: Can't allocate memory for next->trans\n"); mpool_free(root->mempool, next); return CL_EMEM; } } root->ac_nodes++; newtable = mpool_realloc(root->mempool, root->ac_nodetable, root->ac_nodes * sizeof(struct cli_ac_node *)); if(!newtable) { root->ac_nodes--; cli_errmsg("cli_ac_addpatt: Can't realloc ac_nodetable\n"); if(next->trans) mpool_free(root->mempool, next->trans); mpool_free(root->mempool, next); return CL_EMEM; } root->ac_nodetable = (struct cli_ac_node **) newtable; root->ac_nodetable[root->ac_nodes - 1] = next; pt->trans[(unsigned char) (pattern->pattern[i] & 0xff)] = next; } pt = next; } root->ac_patterns++; newtable = mpool_realloc(root->mempool, root->ac_pattable, root->ac_patterns * sizeof(struct cli_ac_patt *)); if(!newtable) { root->ac_patterns--; cli_errmsg("cli_ac_addpatt: Can't realloc ac_pattable\n"); return CL_EMEM; } root->ac_pattable = (struct cli_ac_patt **) newtable; root->ac_pattable[root->ac_patterns - 1] = pattern; pattern->depth = i; ph = pt->list; while(ph) { if((ph->length == pattern->length) && (ph->prefix_length == pattern->prefix_length) && (ph->ch[0] == pattern->ch[0]) && (ph->ch[1] == pattern->ch[1])) { if(!memcmp(ph->pattern, pattern->pattern, ph->length * sizeof(uint16_t)) && !memcmp(ph->prefix, pattern->prefix, ph->prefix_length * sizeof(uint16_t))) { if(!ph->alt && !pattern->alt) { match = 1; } else if(ph->alt == pattern->alt) { match = 1; for(i = 0; i < ph->alt; i++) { a1 = ph->alttable[i]; a2 = pattern->alttable[i]; if(a1->num != a2->num) { match = 0; break; } if(a1->chmode != a2->chmode) { match = 0; break; } else if(a1->chmode) { if(memcmp(a1->str, a2->str, a1->num)) { match = 0; break; } } else { while(a1 && a2) { if((a1->len != a2->len) || memcmp(a1->str, a2->str, a1->len)) break; a1 = a1->next; a2 = a2->next; } if(a1 || a2) { match = 0; break; } } } } else { match = 0; } if(match) { pattern->next_same = ph->next_same; ph->next_same = pattern; return CL_SUCCESS; } } } ph = ph->next; } pattern->next = pt->list; pt->list = pattern; return CL_SUCCESS; }