1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
11 #include "os_regex/os_regex.h"
12 #include "os_xml/os_xml.h"
13 #include "analysisd.h"
14 #include "eventinfo.h"
16 #include "plugin_decoders.h"
22 #define XML_LDECODER "etc/local_decoder.xml"
25 /* Internal functions */
26 static char *_loadmemory(char *at, char *str);
27 static int addDecoder2list(const char *name);
28 static int os_setdecoderids(const char *p_name);
29 static int ReadDecodeAttrs(char *const *names, char *const *values);
30 static OSStore *os_decoder_store = NULL;
33 int getDecoderfromlist(const char *name)
35 if (os_decoder_store) {
36 return (OSStore_GetPosition(os_decoder_store, name));
42 static int addDecoder2list(const char *name)
44 if (os_decoder_store == NULL) {
45 os_decoder_store = OSStore_Create();
46 if (os_decoder_store == NULL) {
47 merror(LIST_ERROR, ARGV0);
53 if (!OSStore_Put(os_decoder_store, name, NULL)) {
54 merror(LIST_ADD_ERROR, ARGV0);
61 static int os_setdecoderids(const char *p_name)
64 OSDecoderNode *child_node;
67 node = OS_GetFirstOSDecoder(p_name);
77 nnode = node->osdecoder;
78 nnode->id = getDecoderfromlist(nnode->name);
85 child_node = node->child;
93 tmp_name = nnode->name;
95 /* Also set on the child nodes */
97 nnode = child_node->osdecoder;
99 if (nnode->use_own_name) {
100 nnode->id = getDecoderfromlist(nnode->name);
104 /* Set parent name */
106 nnode->name = strdup(tmp_name);
110 if (nnode->id == 0) {
113 child_node = child_node->next;
115 } while ((node = node->next) != NULL);
120 static int ReadDecodeAttrs(char *const *names, char *const *values)
122 if (!names || !values) {
126 if (!names[0] || !values[0]) {
130 if (strcmp(names[0], "offset") == 0) {
133 /* Offsets can be: after_parent, after_prematch
136 if (strcmp(values[0], "after_parent") == 0) {
137 offset |= AFTER_PARENT;
138 } else if (strcmp(values[0], "after_prematch") == 0) {
139 offset |= AFTER_PREMATCH;
140 } else if (strcmp(values[0], "after_regex") == 0) {
141 offset |= AFTER_PREVREGEX;
143 merror(INV_OFFSET, ARGV0, values[0]);
144 offset |= AFTER_ERROR;
150 /* Invalid attribute */
151 merror(INV_ATTR, ARGV0, names[0]);
152 return (AFTER_ERROR);
155 int ReadDecodeXML(const char *file)
158 XML_NODE node = NULL;
161 /* These are the available options for the rule configuration */
163 const char *xml_plugindecoder = "plugin_decoder";
164 const char *xml_decoder = "decoder";
165 const char *xml_decoder_name = "name";
166 const char *xml_decoder_status = "status";
167 const char *xml_usename = "use_own_name";
168 const char *xml_parent = "parent";
169 const char *xml_program_name = "program_name";
170 const char *xml_prematch = "prematch";
171 const char *xml_regex = "regex";
172 const char *xml_program_name_pcre2 = "program_name_pcre2";
173 const char *xml_prematch_pcre2 = "prematch_pcre2";
174 const char *xml_pcre2 = "pcre2";
175 const char *xml_order = "order";
176 const char *xml_type = "type";
177 const char *xml_fts = "fts";
178 const char *xml_ftscomment = "ftscomment";
179 const char *xml_accumulate = "accumulate";
182 OSDecoderInfo *NULL_Decoder_tmp = NULL;
185 if ((i = OS_ReadXML(file, &xml)) < 0) {
186 if ((i == -2) && (strcmp(file, XML_LDECODER) == 0)) {
190 merror(XML_ERROR, ARGV0, file, xml.err, xml.err_line);
194 /* Apply any variables found */
195 if (OS_ApplyVariables(&xml) != 0) {
196 merror(XML_ERROR_VAR, ARGV0, file, xml.err);
200 /* Get the root elements */
201 node = OS_GetElementsbyNode(&xml, NULL);
203 if (strcmp(file, XML_LDECODER) != 0) {
204 merror(XML_ELEMNULL, ARGV0);
211 /* Zero NULL_decoder */
213 os_calloc(1, sizeof(OSDecoderInfo), NULL_Decoder_tmp);
214 NULL_Decoder_tmp->id = 0;
215 NULL_Decoder_tmp->type = SYSLOG;
216 NULL_Decoder_tmp->name = NULL;
217 NULL_Decoder_tmp->fts = 0;
218 NULL_Decoder = NULL_Decoder_tmp;
223 XML_NODE elements = NULL;
231 char *prematch_pcre2;
234 if (!node[i]->element ||
235 strcasecmp(node[i]->element, xml_decoder) != 0) {
236 merror(XML_INVELEM, ARGV0, node[i]->element);
241 if ((!node[i]->attributes) || (!node[i]->values) ||
242 (!node[i]->values[0]) || (!node[i]->attributes[0]) ||
243 (strcasecmp(node[i]->attributes[0], xml_decoder_name) != 0)) {
244 merror(XML_INVELEM, ARGV0, node[i]->element);
248 /* Check for additional entries */
249 if (node[i]->attributes[1] && node[i]->values[1]) {
250 if (strcasecmp(node[i]->attributes[0], xml_decoder_status) != 0) {
251 merror(XML_INVELEM, ARGV0, node[i]->element);
255 if (node[i]->attributes[2]) {
256 merror(XML_INVELEM, ARGV0, node[i]->element);
261 /* Get decoder options */
262 elements = OS_GetElementsbyNode(&xml, node[i]);
263 if (elements == NULL) {
264 merror(XML_ELEMNULL, ARGV0);
268 /* Create the OSDecoderInfo */
269 pi = (OSDecoderInfo *)calloc(1, sizeof(OSDecoderInfo));
271 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
275 /* Default values to the list */
278 pi->name = strdup(node[i]->values[0]);
280 pi->plugindecoder = NULL;
285 pi->program_name = NULL;
287 pi->prematch_pcre2 = NULL;
288 pi->program_name_pcre2 = NULL;
290 pi->use_own_name = 0;
292 pi->regex_offset = 0;
293 pi->prematch_offset = 0;
299 prematch_pcre2 = NULL;
302 /* Check if strdup worked */
304 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
309 if (!addDecoder2list(pi->name)) {
310 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
316 /* Loop over all the elements */
317 while (elements[j]) {
318 if (!elements[j]->element) {
319 merror(XML_ELEMNULL, ARGV0);
321 } else if (!elements[j]->content) {
322 merror(XML_VALUENULL, ARGV0, elements[j]->element);
326 /* Check if it is a child of a rule */
327 else if (strcasecmp(elements[j]->element, xml_parent) == 0) {
328 pi->parent = _loadmemory(pi->parent, elements[j]->content);
332 else if (strcasecmp(elements[j]->element, xml_regex) == 0) {
334 r_offset = ReadDecodeAttrs(elements[j]->attributes,
335 elements[j]->values);
337 if (r_offset & AFTER_ERROR) {
338 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
342 /* Only the first regex entry may have an offset */
343 if (regex && r_offset) {
344 merror(DUP_REGEX, ARGV0, pi->name);
345 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
351 pi->regex_offset = r_offset;
357 elements[j]->content);
361 else if (strcasecmp(elements[j]->element, xml_pcre2) == 0) {
363 r_offset = ReadDecodeAttrs(elements[j]->attributes,
364 elements[j]->values);
366 if (r_offset & AFTER_ERROR) {
367 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
371 /* Only the first regex entry may have an offset */
372 if (pcre2 && r_offset) {
373 merror(DUP_REGEX, ARGV0, pi->name);
374 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
380 pi->regex_offset = r_offset;
386 elements[j]->content);
389 /* Get the pre match */
390 else if (strcasecmp(elements[j]->element, xml_prematch) == 0) {
393 r_offset = ReadDecodeAttrs(
394 elements[j]->attributes,
395 elements[j]->values);
397 if (r_offset & AFTER_ERROR) {
398 ErrorExit(DEC_REGEX_ERROR, ARGV0, pi->name);
401 /* Only the first prematch entry may have an offset */
402 if (prematch && r_offset) {
403 merror(DUP_REGEX, ARGV0, pi->name);
404 ErrorExit(DEC_REGEX_ERROR, ARGV0, pi->name);
408 pi->prematch_offset = r_offset;
412 _loadmemory(prematch,
413 elements[j]->content);
415 else if (strcasecmp(elements[j]->element, xml_prematch_pcre2) == 0) {
418 r_offset = ReadDecodeAttrs(
419 elements[j]->attributes,
420 elements[j]->values);
422 if (r_offset & AFTER_ERROR) {
423 ErrorExit(DEC_REGEX_ERROR, ARGV0, pi->name);
426 /* Only the first prematch entry may have an offset */
427 if (prematch_pcre2 && r_offset) {
428 merror(DUP_REGEX, ARGV0, pi->name);
429 ErrorExit(DEC_REGEX_ERROR, ARGV0, pi->name);
433 pi->prematch_offset = r_offset;
437 _loadmemory(prematch_pcre2,
438 elements[j]->content);
441 /* Get program name */
442 else if (strcasecmp(elements[j]->element, xml_program_name) == 0) {
443 p_name = _loadmemory(p_name, elements[j]->content);
445 else if (strcasecmp(elements[j]->element, xml_program_name_pcre2) == 0) {
446 p_name_pcre2 = _loadmemory(p_name_pcre2, elements[j]->content);
449 /* Get the FTS comment */
450 else if (strcasecmp(elements[j]->element, xml_ftscomment) == 0) {
453 else if (strcasecmp(elements[j]->element, xml_usename) == 0) {
454 if (strcmp(elements[j]->content, "true") == 0) {
455 pi->use_own_name = 1;
459 else if (strcasecmp(elements[j]->element, xml_plugindecoder) == 0) {
461 for (ed_c = 0; plugin_decoders[ed_c] != NULL; ed_c++) {
462 if (strcmp(plugin_decoders[ed_c],
463 elements[j]->content) == 0) {
464 /* Initialize plugin */
465 void (*dec_init)(void) = (void (*)(void)) plugin_decoders_init[ed_c];
467 pi->plugindecoder = (void (*)(void *)) plugin_decoders_exec[ed_c];
472 /* Decoder not found */
473 if (pi->plugindecoder == NULL) {
474 merror(INV_DECOPTION, ARGV0, elements[j]->element,
475 elements[j]->content);
481 else if (strcmp(elements[j]->element, xml_type) == 0) {
482 if (strcmp(elements[j]->content, "firewall") == 0) {
484 } else if (strcmp(elements[j]->content, "ids") == 0) {
486 } else if (strcmp(elements[j]->content, "web-log") == 0) {
488 } else if (strcmp(elements[j]->content, "syslog") == 0) {
490 } else if (strcmp(elements[j]->content, "squid") == 0) {
492 } else if (strcmp(elements[j]->content, "windows") == 0) {
493 pi->type = DECODER_WINDOWS;
494 } else if (strcmp(elements[j]->content, "host-information") == 0) {
495 pi->type = HOST_INFO;
496 } else if (strcmp(elements[j]->content, "ossec") == 0) {
499 merror("%s: Invalid decoder type '%s'.",
500 ARGV0, elements[j]->content);
506 else if (strcasecmp(elements[j]->element, xml_order) == 0) {
507 char **norder, **s_norder;
510 /* Maximum number for the order is limited by decoder_order_size */
511 norder = OS_StrBreak(',', elements[j]->content, MAX_DECODER_ORDER_SIZE);
513 os_calloc(Config.decoder_order_size, sizeof(void *), pi->order);
514 os_calloc(Config.decoder_order_size, sizeof(char *), pi->fields);
518 /* Check the values from the order */
520 if (order_int >= Config.decoder_order_size) {
521 ErrorExit("%s: ERROR: Order has too many fields.", ARGV0);
524 char *word = &(*norder)[strspn(*norder, " ")];
525 word[strcspn(word, " ")] = '\0';
527 if (strlen(word) == 0) {
528 ErrorExit("decode-xml: Wrong field '%s' in the order"
529 " of decoder '%s'", *norder, pi->name);
532 if (!strcmp(word, "dstuser")) {
533 pi->order[order_int] = DstUser_FP;
534 } else if (!strcmp(word, "srcuser")) {
535 pi->order[order_int] = SrcUser_FP;
537 /* User is an alias to dstuser */
538 else if (!strcmp(word, "user")) {
539 pi->order[order_int] = DstUser_FP;
540 } else if (!strcmp(word, "srcip")) {
541 pi->order[order_int] = SrcIP_FP;
542 } else if (!strcmp(word, "dstip")) {
543 pi->order[order_int] = DstIP_FP;
544 } else if (!strcmp(word, "srcport")) {
545 pi->order[order_int] = SrcPort_FP;
546 } else if (!strcmp(word, "dstport")) {
547 pi->order[order_int] = DstPort_FP;
548 } else if (!strcmp(word, "protocol")) {
549 pi->order[order_int] = Protocol_FP;
550 } else if (!strcmp(word, "action")) {
551 pi->order[order_int] = Action_FP;
552 } else if (!strcmp(word, "id")) {
553 pi->order[order_int] = ID_FP;
554 } else if (!strcmp(word, "url")) {
555 pi->order[order_int] = Url_FP;
556 } else if (!strcmp(word, "data")) {
557 pi->order[order_int] = Data_FP;
558 } else if (!strcmp(word, "extra_data")) {
559 pi->order[order_int] = Data_FP;
560 } else if (!strcmp(word, "status")) {
561 pi->order[order_int] = Status_FP;
562 } else if (!strcmp(word, "system_name")) {
563 pi->order[order_int] = SystemName_FP;
564 } else if (strstr(*norder, "filename") != NULL) {
565 pi->order[order_int] = FileName_FP;
567 pi->order[order_int] = DynamicField_FP;
568 pi->fields[order_int] = strdup(*norder);
581 else if (strcasecmp(elements[j]->element, xml_accumulate) == 0) {
582 /* Enable Accumulator */
586 /* Get the FTS order */
587 else if (strcasecmp(elements[j]->element, xml_fts) == 0) {
591 /* Maximum number is 8 for the FTS */
592 norder = OS_StrBreak(',', elements[j]->content, 8);
593 if (norder == NULL) {
594 ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
597 /* Save the initial point to free later */
600 /* Check the values from the FTS */
602 if (strstr(*norder, "dstuser") != NULL) {
603 pi->fts |= FTS_DSTUSER;
605 if (strstr(*norder, "user") != NULL) {
606 pi->fts |= FTS_DSTUSER;
607 } else if (strstr(*norder, "srcuser") != NULL) {
608 pi->fts |= FTS_SRCUSER;
609 } else if (strstr(*norder, "srcip") != NULL) {
610 pi->fts |= FTS_SRCIP;
611 } else if (strstr(*norder, "dstip") != NULL) {
612 pi->fts |= FTS_DSTIP;
613 } else if (strstr(*norder, "id") != NULL) {
615 } else if (strstr(*norder, "location") != NULL) {
616 pi->fts |= FTS_LOCATION;
617 } else if (strstr(*norder, "data") != NULL) {
619 } else if (strstr(*norder, "extra_data") != NULL) {
621 } else if (strstr(*norder, "system_name") != NULL) {
622 pi->fts |= FTS_SYSTEMNAME;
623 } else if (strstr(*norder, "name") != NULL) {
626 ErrorExit("decode-xml: Wrong field '%s' in the fts"
627 " decoder '%s'", *norder, pi->name);
634 /* Clear memory here */
637 merror("%s: Invalid element '%s' for "
640 elements[j]->element,
648 } /* while(elements[j]) */
650 OS_ClearNode(elements);
653 /* Prematch must be set */
654 if (!(prematch || prematch_pcre2) && !pi->parent && !(p_name || p_name_pcre2)) {
655 merror(DECODE_NOPRE, ARGV0, pi->name);
656 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
660 /* If pi->regex is not set, fts must not be set too */
661 if ((!(regex || pcre2) && (pi->fts || pi->order)) || ((regex || pcre2) && !pi->order)) {
662 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
666 /* For the offsets */
667 if ((pi->regex_offset & AFTER_PARENT) && !pi->parent) {
668 merror(INV_OFFSET, ARGV0, "after_parent");
669 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
673 if (pi->regex_offset & AFTER_PREMATCH) {
674 /* If after_prematch is set, but rule have
675 * no parent, set AFTER_PARENT and unset
679 pi->regex_offset = 0;
680 pi->regex_offset |= AFTER_PARENT;
681 } else if (!(prematch || prematch_pcre2)) {
682 merror(INV_OFFSET, ARGV0, "after_prematch");
683 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
688 /* For the after_regex offset */
689 if (pi->regex_offset & AFTER_PREVREGEX) {
690 if (!pi->parent || !(regex || pcre2)) {
691 merror(INV_OFFSET, ARGV0, "after_regex");
692 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
697 /* Check the prematch offset */
698 if (pi->prematch_offset) {
699 /* Only the after parent is allowed */
700 if (pi->prematch_offset & AFTER_PARENT) {
702 merror(INV_OFFSET, ARGV0, "after_parent");
703 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
707 merror(DEC_REGEX_ERROR, ARGV0, pi->name);
712 /* Compile the regex/prematch */
714 os_calloc(1, sizeof(OSRegex), pi->prematch);
715 if (!OSRegex_Compile(prematch, pi->prematch, 0)) {
716 merror(REGEX_COMPILE, ARGV0, prematch, pi->prematch->error);
722 else if (prematch_pcre2) {
723 os_calloc(1, sizeof(OSPcre2), pi->prematch_pcre2);
724 if (!OSPcre2_Compile(prematch_pcre2, pi->prematch_pcre2, PCRE2_CASELESS)) {
725 merror(REGEX_COMPILE, ARGV0, prematch_pcre2, pi->prematch_pcre2->error);
729 free(prematch_pcre2);
732 /* Compile the p_name */
734 os_calloc(1, sizeof(OSMatch), pi->program_name);
735 if (!OSMatch_Compile(p_name, pi->program_name, 0)) {
736 merror(REGEX_COMPILE, ARGV0, p_name, pi->program_name->error);
742 else if (p_name_pcre2) {
743 os_calloc(1, sizeof(OSPcre2), pi->program_name_pcre2);
744 if (!OSPcre2_Compile(p_name_pcre2, pi->program_name_pcre2, PCRE2_CASELESS)) {
745 merror(REGEX_COMPILE, ARGV0, p_name_pcre2, pi->program_name_pcre2->error);
752 /* We may not have the pi->regex */
754 os_calloc(1, sizeof(OSRegex), pi->regex);
755 if (!OSRegex_Compile(regex, pi->regex, OS_RETURN_SUBSTRING)) {
756 merror(REGEX_COMPILE, ARGV0, regex, pi->regex->error);
760 /* We must have the sub_strings to retrieve the nodes */
761 if (!pi->regex->sub_strings) {
762 merror(REGEX_SUBS, ARGV0, regex);
769 os_calloc(1, sizeof(OSPcre2), pi->pcre2);
770 if (!OSPcre2_Compile(pcre2, pi->pcre2, PCRE2_CASELESS)) {
771 merror(REGEX_COMPILE, ARGV0, pcre2, pi->pcre2->error);
778 /* Validate arguments */
779 if (pi->plugindecoder && (pi->regex || pi->order)) {
780 merror(DECODE_ADD, ARGV0, pi->name);
784 /* Add osdecoder to the list */
785 if (!OS_AddOSDecoder(pi)) {
786 merror(DECODER_ERROR, ARGV0);
791 } /* while (node[i]) */
794 /* Clean node and XML structures */
803 /* Add rootcheck decoder to list */
804 addDecoder2list(ROOTCHECK_MOD);
805 addDecoder2list(SYSCHECK_MOD);
806 addDecoder2list(SYSCHECK_MOD2);
807 addDecoder2list(SYSCHECK_MOD3);
808 addDecoder2list(SYSCHECK_NEW);
809 addDecoder2list(SYSCHECK_DEL);
810 addDecoder2list(HOSTINFO_NEW);
811 addDecoder2list(HOSTINFO_MOD);
813 /* Set ids - for our two lists */
814 if (!os_setdecoderids(NULL)) {
815 merror(DECODER_ERROR, ARGV0);
818 if (!os_setdecoderids(ARGV0)) {
819 merror(DECODER_ERROR, ARGV0);
826 /* Allocate memory at "*at" and copy *str to it
827 * If *at already exist, realloc the memory and cat str on it
828 * Returns the new string
830 char *_loadmemory(char *at, char *str)
834 if ((strsize = strlen(str)) < OS_SIZE_8192) {
835 at = (char *) calloc(strsize + 1, sizeof(char));
837 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
840 strncpy(at, str, strsize);
843 merror(SIZE_ERROR, ARGV0, str);
847 /* At is not null. Need to reallocate its memory and copy str to it */
849 size_t strsize = strlen(str);
850 size_t atsize = strlen(at);
851 size_t finalsize = atsize + strsize + 1;
852 if (finalsize > OS_SIZE_8192) {
853 merror(SIZE_ERROR, ARGV0, str);
856 at = (char *) realloc(at, (finalsize + 1) * sizeof(char));
858 merror(MEM_ERROR, ARGV0, errno, strerror(errno));
861 strncat(at, str, strsize);
862 at[finalsize - 1] = '\0';