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 "syscheck-config.h"
15 int dump_syscheck_entry(syscheck_config *syscheck, const char *entry, int vals, int reg, const char *restrictfile)
21 if (syscheck->registry == NULL) {
22 os_calloc(2, sizeof(char *), syscheck->registry);
23 syscheck->registry[pl + 1] = NULL;
24 os_strdup(entry, syscheck->registry[pl]);
26 while (syscheck->registry[pl] != NULL) {
29 os_realloc(syscheck->registry, (pl + 2) * sizeof(char *),
31 syscheck->registry[pl + 1] = NULL;
32 os_strdup(entry, syscheck->registry[pl]);
38 if (syscheck->dir == NULL) {
39 os_calloc(2, sizeof(char *), syscheck->dir);
40 syscheck->dir[pl + 1] = NULL;
41 os_strdup(entry, syscheck->dir[pl]);
43 os_calloc(2, sizeof(int), syscheck->opts);
44 syscheck->opts[pl + 1] = 0;
45 syscheck->opts[pl] = vals;
47 os_calloc(2, sizeof(OSMatch *), syscheck->filerestrict);
48 syscheck->filerestrict[pl] = NULL;
49 syscheck->filerestrict[pl + 1] = NULL;
51 while (syscheck->dir[pl] != NULL) {
54 os_realloc(syscheck->dir, (pl + 2) * sizeof(char *),
56 syscheck->dir[pl + 1] = NULL;
57 os_strdup(entry, syscheck->dir[pl]);
59 os_realloc(syscheck->opts, (pl + 2) * sizeof(int),
61 syscheck->opts[pl + 1] = 0;
62 syscheck->opts[pl] = vals;
64 os_realloc(syscheck->filerestrict, (pl + 2) * sizeof(OSMatch *),
65 syscheck->filerestrict);
66 syscheck->filerestrict[pl] = NULL;
67 syscheck->filerestrict[pl + 1] = NULL;
70 os_calloc(1, sizeof(OSMatch), syscheck->filerestrict[pl]);
71 if (!OSMatch_Compile(restrictfile, syscheck->filerestrict[pl], 0)) {
74 ptm = syscheck->filerestrict[pl];
76 merror(REGEX_COMPILE, __local_name, restrictfile,
78 free(syscheck->filerestrict[pl]);
79 syscheck->filerestrict[pl] = NULL;
88 /* Read Windows registry configuration */
89 int read_reg(syscheck_config *syscheck, char *entries)
95 /* Get each entry separately */
96 entry = OS_StrBreak(',', entries, MAX_DIR_SIZE); /* Max number */
107 /* Remove spaces at the beginning */
108 while (*tmp_entry == ' ') {
112 /* Remove spaces at the end */
113 tmp_str = strchr(tmp_entry, ' ');
117 /* Check if it is really at the end */
118 if ((*tmp_str == '\0') || (*tmp_str == ' ')) {
124 /* Add entries - look for the last available */
126 while (syscheck->registry && syscheck->registry[i]) {
130 str_len_dir = strlen(tmp_entry);
131 str_len_i = strlen(syscheck->registry[i]);
133 if (str_len_dir > str_len_i) {
134 str_len_dir = str_len_i;
137 /* Duplicated entry */
138 if (strcmp(syscheck->registry[i], tmp_entry) == 0) {
139 merror(SK_DUP, __local_name, tmp_entry);
146 dump_syscheck_entry(syscheck, tmp_entry, 0, 1, NULL);
156 /* Read directories attributes */
157 static int read_attr(syscheck_config *syscheck, const char *dirs, char **g_attrs, char **g_values)
159 const char *xml_check_all = "check_all";
160 const char *xml_check_sum = "check_sum";
161 const char *xml_check_sha1sum = "check_sha1sum";
162 const char *xml_check_md5sum = "check_md5sum";
163 const char *xml_check_size = "check_size";
164 const char *xml_check_owner = "check_owner";
165 const char *xml_check_group = "check_group";
166 const char *xml_check_perm = "check_perm";
167 const char *xml_real_time = "realtime";
168 const char *xml_report_changes = "report_changes";
169 const char *xml_restrict = "restrict";
170 const char *xml_no_recurse = "no_recurse";
172 char *restrictfile = NULL;
175 dir = OS_StrBreak(',', dirs, MAX_DIR_SIZE); /* Max number */
176 char **dir_org = dir;
180 /* Dir can not be null */
191 char **values = NULL;
196 /* Remove spaces at the beginning */
197 while (*tmp_dir == ' ') {
201 /* Remove spaces at the end */
202 tmp_str = strchr(tmp_dir, ' ');
206 /* Check if it is really at the end */
207 if ((*tmp_str == '\0') || (*tmp_str == ' ')) {
213 /* Get the options */
214 if (!g_attrs || !g_values) {
215 merror(SYSCHECK_NO_OPT, __local_name, dirs);
223 while (*attrs && *values) {
225 if (strcmp(*attrs, xml_check_all) == 0) {
226 if (strcmp(*values, "yes") == 0) {
227 opts |= CHECK_MD5SUM;
228 opts |= CHECK_SHA1SUM;
233 } else if (strcmp(*values, "no") == 0) {
234 opts &= ~ ( CHECK_MD5SUM | CHECK_SHA1SUM | CHECK_PERM
235 | CHECK_SIZE | CHECK_OWNER | CHECK_GROUP );
237 merror(SK_INV_OPT, __local_name, *values, *attrs);
243 else if (strcmp(*attrs, xml_check_sum) == 0) {
244 if (strcmp(*values, "yes") == 0) {
245 opts |= CHECK_MD5SUM;
246 opts |= CHECK_SHA1SUM;
247 } else if (strcmp(*values, "no") == 0) {
248 opts &= ~ ( CHECK_MD5SUM | CHECK_SHA1SUM );
250 merror(SK_INV_OPT, __local_name, *values, *attrs);
256 else if (strcmp(*attrs, xml_check_md5sum) == 0) {
257 if (strcmp(*values, "yes") == 0) {
258 opts |= CHECK_MD5SUM;
259 } else if (strcmp(*values, "no") == 0) {
260 opts &= ~ CHECK_MD5SUM;
262 merror(SK_INV_OPT, __local_name, *values, *attrs);
268 else if (strcmp(*attrs, xml_check_sha1sum) == 0) {
269 if (strcmp(*values, "yes") == 0) {
270 opts |= CHECK_SHA1SUM;
271 } else if (strcmp(*values, "no") == 0) {
272 opts &= ~ CHECK_SHA1SUM;
274 merror(SK_INV_OPT, __local_name, *values, *attrs);
279 /* Check permission */
280 else if (strcmp(*attrs, xml_check_perm) == 0) {
281 if (strcmp(*values, "yes") == 0) {
283 } else if (strcmp(*values, "no") == 0) {
284 opts &= ~ CHECK_PERM;
286 merror(SK_INV_OPT, __local_name, *values, *attrs);
292 else if (strcmp(*attrs, xml_check_size) == 0) {
293 if (strcmp(*values, "yes") == 0) {
295 } else if (strcmp(*values, "no") == 0) {
296 opts &= ~ CHECK_SIZE;
298 merror(SK_INV_OPT, __local_name, *values, *attrs);
304 else if (strcmp(*attrs, xml_check_owner) == 0) {
305 if (strcmp(*values, "yes") == 0) {
307 } else if (strcmp(*values, "no") == 0) {
308 opts &= ~ CHECK_OWNER;
310 merror(SK_INV_OPT, __local_name, *values, *attrs);
316 else if (strcmp(*attrs, xml_check_group) == 0) {
317 if (strcmp(*values, "yes") == 0) {
319 } else if (strcmp(*values, "no") == 0) {
320 opts &= ~ CHECK_GROUP;
322 merror(SK_INV_OPT, __local_name, *values, *attrs);
326 } else if (strcmp(*attrs, xml_real_time) == 0) {
327 if (strcmp(*values, "yes") == 0) {
328 opts |= CHECK_REALTIME;
329 } else if (strcmp(*values, "no") == 0) {
330 opts &= ~ CHECK_REALTIME;
332 merror(SK_INV_OPT, __local_name, *values, *attrs);
336 } else if (strcmp(*attrs, xml_report_changes) == 0) {
337 if (strcmp(*values, "yes") == 0) {
338 opts |= CHECK_SEECHANGES;
339 } else if (strcmp(*values, "no") == 0) {
340 opts &= ~ CHECK_SEECHANGES;
342 merror(SK_INV_OPT, __local_name, *values, *attrs);
346 } else if (strcmp(*attrs, xml_restrict) == 0) {
351 os_strdup(*values, restrictfile);
352 } else if (strcmp(*attrs, xml_no_recurse) == 0) {
353 if(strcmp(*values, "yes") == 0) {
354 opts |= CHECK_NORECURSE;
356 merror(SK_INV_OPT, __local_name, *values, *attrs);
361 merror(SK_INV_ATTR, __local_name, *attrs);
369 /* You must have something set */
371 merror(SYSCHECK_NO_OPT, __local_name, dirs);
376 /* Add directory - look for the last available */
378 while (syscheck->dir && syscheck->dir[j]) {
379 /* Duplicate entry */
380 if (strcmp(syscheck->dir[j], tmp_dir) == 0) {
381 merror(SK_DUP, __local_name, tmp_dir);
390 /* The mingw32 builder used by travis.ci can't find glob.h
391 * Yet glob must work on actual win32.
394 if (strchr(tmp_dir, '*') ||
395 strchr(tmp_dir, '?') ||
396 strchr(tmp_dir, '[')) {
400 if (glob(tmp_dir, 0, NULL, &g) != 0) {
401 merror(GLOB_ERROR, __local_name, tmp_dir);
406 if (g.gl_pathv[0] == NULL) {
407 merror(GLOB_NFOUND, __local_name, tmp_dir);
412 while (g.gl_pathv[gindex]) {
413 dump_syscheck_entry(syscheck, g.gl_pathv[gindex], opts, 0, restrictfile);
421 dump_syscheck_entry(syscheck, tmp_dir, opts, 0, restrictfile);
424 dump_syscheck_entry(syscheck, tmp_dir, opts, 0, restrictfile);
451 int Read_Syscheck(XML_NODE node, void *configp, __attribute__((unused)) void *mailp)
455 /* XML Definitions */
456 const char *xml_directories = "directories";
457 const char *xml_registry = "windows_registry";
458 const char *xml_time = "frequency";
459 const char *xml_scanday = "scan_day";
460 const char *xml_scantime = "scan_time";
461 const char *xml_ignore = "ignore";
462 const char *xml_registry_ignore = "registry_ignore";
463 const char *xml_auto_ignore = "auto_ignore";
464 const char *xml_alert_new_files = "alert_new_files";
465 const char *xml_disabled = "disabled";
466 const char *xml_scan_on_start = "scan_on_start";
467 const char *xml_prefilter_cmd = "prefilter_cmd";
468 const char *xml_skip_nfs = "skip_nfs";
469 const char *xml_nodiff = "nodiff";
471 /* Configuration example
472 <directories check_all="yes">/etc,/usr/bin</directories>
473 <directories check_owner="yes" check_group="yes" check_perm="yes"
474 check_sum="yes">/var/log</directories>
477 syscheck_config *syscheck;
478 syscheck = (syscheck_config *)configp;
479 unsigned int nodiff_size = 0;
482 if (!node[i]->element) {
483 merror(XML_ELEMNULL, __local_name);
485 } else if (!node[i]->content) {
486 merror(XML_VALUENULL, __local_name, node[i]->element);
490 /* Get directories */
491 else if (strcmp(node[i]->element, xml_directories) == 0) {
492 char dirs[OS_MAXSTR];
495 ExpandEnvironmentStrings(node[i]->content, dirs, sizeof(dirs) - 1);
497 strncpy(dirs, node[i]->content, sizeof(dirs) - 1);
500 if (!read_attr(syscheck,
507 /* Get Windows registry */
508 else if (strcmp(node[i]->element, xml_registry) == 0) {
510 if (!read_reg(syscheck, node[i]->content)) {
516 else if (strcmp(node[i]->element, xml_time) == 0) {
517 if (!OS_StrIsNum(node[i]->content)) {
518 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
522 syscheck->time = atoi(node[i]->content);
525 else if (strcmp(node[i]->element, xml_scantime) == 0) {
526 syscheck->scan_time = OS_IsValidUniqueTime(node[i]->content);
527 if (!syscheck->scan_time) {
528 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
534 else if (strcmp(node[i]->element, xml_scanday) == 0) {
535 syscheck->scan_day = OS_IsValidDay(node[i]->content);
536 if (!syscheck->scan_day) {
537 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
542 /* Get if xml_scan_on_start */
543 else if (strcmp(node[i]->element, xml_scan_on_start) == 0) {
544 if (strcmp(node[i]->content, "yes") == 0) {
545 syscheck->scan_on_start = 1;
546 } else if (strcmp(node[i]->content, "no") == 0) {
547 syscheck->scan_on_start = 0;
549 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
554 /* Get if disabled */
555 else if (strcmp(node[i]->element, xml_disabled) == 0) {
556 if (strcmp(node[i]->content, "yes") == 0) {
557 syscheck->disabled = 1;
558 } else if (strcmp(node[i]->content, "no") == 0) {
559 syscheck->disabled = 0;
561 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
566 /* Getting if skip_nfs. */
567 else if (strcmp(node[i]->element,xml_skip_nfs) == 0)
569 if(strcmp(node[i]->content, "yes") == 0)
570 syscheck->skip_nfs = 1;
571 else if(strcmp(node[i]->content, "no") == 0)
572 syscheck->skip_nfs = 0;
575 merror(XML_VALUEERR,__local_name,node[i]->element,node[i]->content);
580 /* Getting file/dir ignore */
581 else if (strcmp(node[i]->element,xml_ignore) == 0)
583 unsigned int ign_size = 0;
586 /* For Windows, we attempt to expand environment variables */
588 os_calloc(2048, sizeof(char), new_ig);
590 ExpandEnvironmentStrings(node[i]->content, new_ig, 2047);
592 free(node[i]->content);
593 node[i]->content = new_ig;
596 if (node[i]->attributes && node[i]->values) {
597 if (node[i]->attributes[0] && node[i]->values[0] &&
598 (strcmp(node[i]->attributes[0], "type") == 0) &&
599 (strcmp(node[i]->values[0], "sregex") == 0)) {
602 if (!syscheck->ignore_regex) {
603 os_calloc(2, sizeof(OSMatch *), syscheck->ignore_regex);
604 syscheck->ignore_regex[0] = NULL;
605 syscheck->ignore_regex[1] = NULL;
607 while (syscheck->ignore_regex[ign_size] != NULL) {
611 os_realloc(syscheck->ignore_regex,
612 sizeof(OSMatch *) * (ign_size + 2),
613 syscheck->ignore_regex);
614 syscheck->ignore_regex[ign_size + 1] = NULL;
616 os_calloc(1, sizeof(OSMatch),
617 syscheck->ignore_regex[ign_size]);
619 if (!OSMatch_Compile(node[i]->content,
620 syscheck->ignore_regex[ign_size], 0)) {
621 mt_pt = (OSMatch *)syscheck->ignore_regex[ign_size];
622 merror(REGEX_COMPILE, __local_name, node[i]->content,
627 merror(SK_INV_ATTR, __local_name, node[i]->attributes[0]);
632 /* Add if simple entry -- check for duplicates */
633 else if (!os_IsStrOnArray(node[i]->content, syscheck->ignore)) {
634 if (!syscheck->ignore) {
635 os_calloc(2, sizeof(char *), syscheck->ignore);
636 syscheck->ignore[0] = NULL;
637 syscheck->ignore[1] = NULL;
639 while (syscheck->ignore[ign_size] != NULL) {
643 os_realloc(syscheck->ignore,
644 sizeof(char *) * (ign_size + 2),
646 syscheck->ignore[ign_size + 1] = NULL;
648 os_strdup(node[i]->content, syscheck->ignore[ign_size]);
652 /* Get registry ignore list */
653 else if (strcmp(node[i]->element, xml_registry_ignore) == 0) {
658 if (node[i]->attributes && node[i]->values) {
659 if (node[i]->attributes[0] && node[i]->values[0] &&
660 (strcmp(node[i]->attributes[0], "type") == 0) &&
661 (strcmp(node[i]->values[0], "sregex") == 0)) {
664 if (!syscheck->registry_ignore_regex) {
665 os_calloc(2, sizeof(OSMatch *),
666 syscheck->registry_ignore_regex);
667 syscheck->registry_ignore_regex[0] = NULL;
668 syscheck->registry_ignore_regex[1] = NULL;
670 while (syscheck->registry_ignore_regex[ign_size] != NULL) {
674 os_realloc(syscheck->registry_ignore_regex,
675 sizeof(OSMatch *) * (ign_size + 2),
676 syscheck->registry_ignore_regex);
677 syscheck->registry_ignore_regex[ign_size + 1] = NULL;
680 os_calloc(1, sizeof(OSMatch),
681 syscheck->registry_ignore_regex[ign_size]);
683 if (!OSMatch_Compile(node[i]->content,
684 syscheck->registry_ignore_regex[ign_size], 0)) {
686 syscheck->registry_ignore_regex[ign_size];
687 merror(REGEX_COMPILE, __local_name, node[i]->content,
692 merror(SK_INV_ATTR, __local_name, node[i]->attributes[0]);
696 /* We do not add duplicated entries */
697 else if (!os_IsStrOnArray(node[i]->content,
698 syscheck->registry_ignore)) {
699 if (!syscheck->registry_ignore) {
700 os_calloc(2, sizeof(char *), syscheck->registry_ignore);
701 syscheck->registry_ignore[0] = NULL;
702 syscheck->registry_ignore[1] = NULL;
704 while (syscheck->registry_ignore[ign_size] != NULL) {
708 os_realloc(syscheck->registry_ignore,
709 sizeof(char *) * (ign_size + 2),
710 syscheck->registry_ignore);
711 syscheck->registry_ignore[ign_size + 1] = NULL;
713 os_strdup(node[i]->content, syscheck->registry_ignore[ign_size]);
716 /* Getting file/dir nodiff */
717 } else if (strcmp(node[i]->element,xml_nodiff) == 0) {
719 /* For Windows, we attempt to expand environment variables */
720 char *new_nodiff = NULL;
721 os_calloc(2048, sizeof(char), new_nodiff);
723 ExpandEnvironmentStrings(node[i]->content, new_nodiff, 2047);
725 free(node[i]->content);
726 node[i]->content = new_nodiff;
729 if (node[i]->attributes && node[i]->values) {
730 if (node[i]->attributes[0] && node[i]->values[0] &&
731 (strcmp(node[i]->attributes[0], "type") == 0) &&
732 (strcmp(node[i]->values[0], "sregex") == 0)) {
734 if (!syscheck->nodiff_regex) {
735 os_calloc(2, sizeof(OSMatch *), syscheck->nodiff_regex);
736 syscheck->nodiff_regex[0] = NULL;
737 syscheck->nodiff_regex[1] = NULL;
739 while (syscheck->nodiff_regex[nodiff_size] != NULL) {
743 os_realloc(syscheck->nodiff_regex,
744 sizeof(OSMatch *) * (nodiff_size + 2),
745 syscheck->nodiff_regex);
746 syscheck->nodiff_regex[nodiff_size + 1] = NULL;
748 os_calloc(1, sizeof(OSMatch),
749 syscheck->nodiff_regex[nodiff_size]);
750 debug1("Found nodiff regex node %s", node[i]->content);
751 if (!OSMatch_Compile(node[i]->content,
752 syscheck->nodiff_regex[nodiff_size], 0)) {
753 mt_pt = (OSMatch *)syscheck->nodiff_regex[nodiff_size];
754 merror(REGEX_COMPILE, __local_name, node[i]->content,
758 debug1("Found nodiff regex node %s OK?", node[i]->content);
759 debug1("Found nodiff regex size %d", nodiff_size);
761 merror(SK_INV_ATTR, __local_name, node[i]->attributes[0]);
766 /* Add if simple entry -- check for duplicates */
767 else if (!os_IsStrOnArray(node[i]->content, syscheck->nodiff)) {
768 if (!syscheck->nodiff) {
769 os_calloc(2, sizeof(char *), syscheck->nodiff);
770 syscheck->nodiff[0] = NULL;
771 syscheck->nodiff[1] = NULL;
773 while (syscheck->nodiff[nodiff_size] != NULL) {
777 os_realloc(syscheck->nodiff,
778 sizeof(char *) * (nodiff_size + 2),
780 syscheck->nodiff[nodiff_size + 1] = NULL;
782 os_strdup(node[i]->content, syscheck->nodiff[nodiff_size]);
784 } else if (strcmp(node[i]->element, xml_auto_ignore) == 0) {
785 /* auto_ignore is not read here */
786 } else if (strcmp(node[i]->element, xml_alert_new_files) == 0) {
787 /* alert_new_files option is not read here */
788 } else if (strcmp(node[i]->element, xml_prefilter_cmd) == 0) {
793 ExpandEnvironmentStrings(node[i]->content, cmd, sizeof(cmd) - 1);
795 strncpy(cmd, node[i]->content, sizeof(cmd) - 1);
798 if (strlen(cmd) > 0) {
799 char statcmd[OS_MAXSTR];
801 strncpy(statcmd, cmd, sizeof(statcmd) - 1);
802 if (NULL != (ix = strchr(statcmd, ' '))) {
805 if (stat(statcmd, &statbuf) == 0) {
806 /* More checks needed (perms, owner, etc.) */
807 os_calloc(1, strlen(cmd) + 1, syscheck->prefilter_cmd);
808 strncpy(syscheck->prefilter_cmd, cmd, strlen(cmd));
810 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
815 merror(XML_INVELEM, __local_name, node[i]->element);
825 /* return a text version of the directory check option bits,
826 * in a provided string buffer
828 char *syscheck_opts2str(char *buf, int buflen, int opts) {
843 char *check_strings[] = {
857 for ( i = 0; check_bits[ i ]; i++ ) {
858 if ( opts & check_bits[ i ] ) {
859 if ( left < buflen ) {
860 strncat( buf, " | ", left );
863 strncat( buf, check_strings[ i ], left );
864 left = buflen - strlen( buf );