new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / config / syscheck-config.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All right reserved.
3  *
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
7  * Foundation
8  */
9
10 #include "shared.h"
11 #include "syscheck-config.h"
12 #include "config.h"
13
14
15 int dump_syscheck_entry(syscheck_config *syscheck, const char *entry, int vals, int reg, const char *restrictfile)
16 {
17     unsigned int pl = 0;
18
19     if (reg == 1) {
20 #ifdef WIN32
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]);
25         } else {
26             while (syscheck->registry[pl] != NULL) {
27                 pl++;
28             }
29             os_realloc(syscheck->registry, (pl + 2) * sizeof(char *),
30                        syscheck->registry);
31             syscheck->registry[pl + 1] = NULL;
32             os_strdup(entry, syscheck->registry[pl]);
33         }
34 #endif
35     }
36
37     else {
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]);
42
43             os_calloc(2, sizeof(int), syscheck->opts);
44             syscheck->opts[pl + 1] = 0;
45             syscheck->opts[pl] = vals;
46
47             os_calloc(2, sizeof(OSMatch *), syscheck->filerestrict);
48             syscheck->filerestrict[pl] = NULL;
49             syscheck->filerestrict[pl + 1] = NULL;
50         } else {
51             while (syscheck->dir[pl] != NULL) {
52                 pl++;
53             }
54             os_realloc(syscheck->dir, (pl + 2) * sizeof(char *),
55                        syscheck->dir);
56             syscheck->dir[pl + 1] = NULL;
57             os_strdup(entry, syscheck->dir[pl]);
58
59             os_realloc(syscheck->opts, (pl + 2) * sizeof(int),
60                        syscheck->opts);
61             syscheck->opts[pl + 1] = 0;
62             syscheck->opts[pl] = vals;
63
64             os_realloc(syscheck->filerestrict, (pl + 2) * sizeof(OSMatch *),
65                        syscheck->filerestrict);
66             syscheck->filerestrict[pl] = NULL;
67             syscheck->filerestrict[pl + 1] = NULL;
68         }
69         if (restrictfile) {
70             os_calloc(1, sizeof(OSMatch), syscheck->filerestrict[pl]);
71             if (!OSMatch_Compile(restrictfile, syscheck->filerestrict[pl], 0)) {
72                 OSMatch *ptm;
73
74                 ptm = syscheck->filerestrict[pl];
75
76                 merror(REGEX_COMPILE, __local_name, restrictfile,
77                        ptm->error);
78                 free(syscheck->filerestrict[pl]);
79                 syscheck->filerestrict[pl] = NULL;
80             }
81         }
82     }
83
84     return (1);
85 }
86
87 #ifdef WIN32
88 /* Read Windows registry configuration */
89 int read_reg(syscheck_config *syscheck, char *entries)
90 {
91     int i;
92     char **entry;
93     char *tmp_str;
94
95     /* Get each entry separately */
96     entry = OS_StrBreak(',', entries, MAX_DIR_SIZE); /* Max number */
97
98     if (entry == NULL) {
99         return (0);
100     }
101
102     while (*entry) {
103         char *tmp_entry;
104
105         tmp_entry = *entry;
106
107         /* Remove spaces at the beginning */
108         while (*tmp_entry == ' ') {
109             tmp_entry++;
110         }
111
112         /* Remove spaces at the end */
113         tmp_str = strchr(tmp_entry, ' ');
114         if (tmp_str) {
115             tmp_str++;
116
117             /* Check if it is really at the end */
118             if ((*tmp_str == '\0') || (*tmp_str == ' ')) {
119                 tmp_str--;
120                 *tmp_str = '\0';
121             }
122         }
123
124         /* Add entries - look for the last available */
125         i = 0;
126         while (syscheck->registry && syscheck->registry[i]) {
127             int str_len_i;
128             int str_len_dir;
129
130             str_len_dir = strlen(tmp_entry);
131             str_len_i = strlen(syscheck->registry[i]);
132
133             if (str_len_dir > str_len_i) {
134                 str_len_dir = str_len_i;
135             }
136
137             /* Duplicated entry */
138             if (strcmp(syscheck->registry[i], tmp_entry) == 0) {
139                 merror(SK_DUP, __local_name, tmp_entry);
140                 return (1);
141             }
142             i++;
143         }
144
145         /* Add new entry */
146         dump_syscheck_entry(syscheck, tmp_entry, 0, 1, NULL);
147
148         /* Next entry */
149         entry++;
150     }
151
152     return (1);
153 }
154 #endif /* WIN32 */
155
156 /* Read directories attributes */
157 static int read_attr(syscheck_config *syscheck, const char *dirs, char **g_attrs, char **g_values)
158 {
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";
171
172     char *restrictfile = NULL;
173     char **dir;
174     char *tmp_str;
175     dir = OS_StrBreak(',', dirs, MAX_DIR_SIZE); /* Max number */
176     char **dir_org = dir;
177
178     int ret = 0, i;
179
180     /* Dir can not be null */
181     if (dir == NULL) {
182         return (0);
183     }
184
185     while (*dir) {
186         int j = 0;
187         int opts = 0;
188         char *tmp_dir;
189
190         char **attrs = NULL;
191         char **values = NULL;
192
193         tmp_dir = *dir;
194         restrictfile = NULL;
195
196         /* Remove spaces at the beginning */
197         while (*tmp_dir == ' ') {
198             tmp_dir++;
199         }
200
201         /* Remove spaces at the end */
202         tmp_str = strchr(tmp_dir, ' ');
203         if (tmp_str) {
204             tmp_str++;
205
206             /* Check if it is really at the end */
207             if ((*tmp_str == '\0') || (*tmp_str == ' ')) {
208                 tmp_str--;
209                 *tmp_str = '\0';
210             }
211         }
212
213         /* Get the options */
214         if (!g_attrs || !g_values) {
215             merror(SYSCHECK_NO_OPT, __local_name, dirs);
216             ret = 0;
217             goto out_free;
218         }
219
220         attrs = g_attrs;
221         values = g_values;
222
223         while (*attrs && *values) {
224             /* Check all */
225             if (strcmp(*attrs, xml_check_all) == 0) {
226                 if (strcmp(*values, "yes") == 0) {
227                     opts |= CHECK_MD5SUM;
228                     opts |= CHECK_SHA1SUM;
229                     opts |= CHECK_PERM;
230                     opts |= CHECK_SIZE;
231                     opts |= CHECK_OWNER;
232                     opts |= CHECK_GROUP;
233                 } else if (strcmp(*values, "no") == 0) {
234                     opts &= ~ ( CHECK_MD5SUM | CHECK_SHA1SUM | CHECK_PERM
235                        | CHECK_SIZE | CHECK_OWNER | CHECK_GROUP );
236                 } else {
237                     merror(SK_INV_OPT, __local_name, *values, *attrs);
238                     ret = 0;
239                     goto out_free;
240                 }
241             }
242             /* Check sum */
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 );
249                 } else {
250                     merror(SK_INV_OPT, __local_name, *values, *attrs);
251                     ret = 0;
252                     goto out_free;
253                 }
254             }
255             /* Check md5sum */
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;
261                 } else {
262                     merror(SK_INV_OPT, __local_name, *values, *attrs);
263                     ret = 0;
264                     goto out_free;
265                 }
266             }
267             /* Check sha1sum */
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;
273                 } else {
274                     merror(SK_INV_OPT, __local_name, *values, *attrs);
275                     ret = 0;
276                     goto out_free;
277                 }
278             }
279             /* Check permission */
280             else if (strcmp(*attrs, xml_check_perm) == 0) {
281                 if (strcmp(*values, "yes") == 0) {
282                     opts |= CHECK_PERM;
283                 } else if (strcmp(*values, "no") == 0) {
284                     opts &= ~ CHECK_PERM;
285                 } else {
286                     merror(SK_INV_OPT, __local_name, *values, *attrs);
287                     ret = 0;
288                     goto out_free;
289                 }
290             }
291             /* Check size */
292             else if (strcmp(*attrs, xml_check_size) == 0) {
293                 if (strcmp(*values, "yes") == 0) {
294                     opts |= CHECK_SIZE;
295                 } else if (strcmp(*values, "no") == 0) {
296                     opts &= ~ CHECK_SIZE;
297                 } else {
298                     merror(SK_INV_OPT, __local_name, *values, *attrs);
299                     ret = 0;
300                     goto out_free;
301                 }
302             }
303             /* Check owner */
304             else if (strcmp(*attrs, xml_check_owner) == 0) {
305                 if (strcmp(*values, "yes") == 0) {
306                     opts |= CHECK_OWNER;
307                 } else if (strcmp(*values, "no") == 0) {
308                     opts &= ~ CHECK_OWNER;
309                 } else {
310                     merror(SK_INV_OPT, __local_name, *values, *attrs);
311                     ret = 0;
312                     goto out_free;
313                 }
314             }
315             /* Check group */
316             else if (strcmp(*attrs, xml_check_group) == 0) {
317                 if (strcmp(*values, "yes") == 0) {
318                     opts |= CHECK_GROUP;
319                 } else if (strcmp(*values, "no") == 0) {
320                     opts &= ~ CHECK_GROUP;
321                 } else {
322                     merror(SK_INV_OPT, __local_name, *values, *attrs);
323                     ret = 0;
324                     goto out_free;
325                 }
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;
331                 } else {
332                     merror(SK_INV_OPT, __local_name, *values, *attrs);
333                     ret = 0;
334                     goto out_free;
335                 }
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;
341                 } else {
342                     merror(SK_INV_OPT, __local_name, *values, *attrs);
343                     ret = 0;
344                     goto out_free;
345                 }
346             } else if (strcmp(*attrs, xml_restrict) == 0) {
347                 if (restrictfile) {
348                     free(restrictfile);
349                     restrictfile = NULL;
350                 }
351                 os_strdup(*values, restrictfile);
352             } else if (strcmp(*attrs, xml_no_recurse) == 0) {
353                 if(strcmp(*values, "yes") == 0) {
354                     opts |= CHECK_NORECURSE;
355                 } else {
356                     merror(SK_INV_OPT, __local_name, *values, *attrs);
357                     ret = 0;
358                     goto out_free;
359                 }
360             } else {
361                 merror(SK_INV_ATTR, __local_name, *attrs);
362                 ret = 0;
363                 goto out_free;
364             }
365             attrs++;
366             values++;
367         }
368
369         /* You must have something set */
370         if (opts == 0) {
371             merror(SYSCHECK_NO_OPT, __local_name, dirs);
372             ret = 0;
373             goto out_free;
374         }
375
376         /* Add directory - look for the last available */
377         j = 0;
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);
382                 ret = 1;
383                 goto out_free;
384             }
385
386             j++;
387         }
388
389         /* Check for glob */
390         /* The mingw32 builder used by travis.ci can't find glob.h 
391          * Yet glob must work on actual win32.  
392          */
393 #ifndef __MINGW32__ 
394         if (strchr(tmp_dir, '*') ||
395                 strchr(tmp_dir, '?') ||
396                 strchr(tmp_dir, '[')) {
397             int gindex = 0;
398             glob_t g;
399
400             if (glob(tmp_dir, 0, NULL, &g) != 0) {
401                 merror(GLOB_ERROR, __local_name, tmp_dir);
402                 ret = 1;
403                 goto out_free;
404             }
405
406             if (g.gl_pathv[0] == NULL) {
407                 merror(GLOB_NFOUND, __local_name, tmp_dir);
408                 ret = 1;
409                 goto out_free;
410             }
411
412             while (g.gl_pathv[gindex]) {
413                 dump_syscheck_entry(syscheck, g.gl_pathv[gindex], opts, 0, restrictfile);
414                 gindex++;
415             }
416
417             globfree(&g);
418         }
419
420         else {
421             dump_syscheck_entry(syscheck, tmp_dir, opts, 0, restrictfile);
422         }
423 #else
424         dump_syscheck_entry(syscheck, tmp_dir, opts, 0, restrictfile);
425 #endif
426
427         if (restrictfile) {
428             free(restrictfile);
429             restrictfile = NULL;
430         }
431
432         /* Next entry */
433         dir++;
434     }
435
436     ret = 1;
437
438 out_free:
439
440     i = 0;
441     while (dir_org[i]) {
442         free(dir_org[i++]);
443     }
444
445     free(dir_org);
446     free(restrictfile);
447
448     return ret;
449 }
450
451 int Read_Syscheck(XML_NODE node, void *configp, __attribute__((unused)) void *mailp)
452 {
453     int i = 0;
454
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";
470
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>
475     */
476
477     syscheck_config *syscheck;
478     syscheck = (syscheck_config *)configp;
479     unsigned int nodiff_size = 0;
480
481     while (node[i]) {
482         if (!node[i]->element) {
483             merror(XML_ELEMNULL, __local_name);
484             return (OS_INVALID);
485         } else if (!node[i]->content) {
486             merror(XML_VALUENULL, __local_name, node[i]->element);
487             return (OS_INVALID);
488         }
489
490         /* Get directories */
491         else if (strcmp(node[i]->element, xml_directories) == 0) {
492             char dirs[OS_MAXSTR];
493
494 #ifdef WIN32
495             ExpandEnvironmentStrings(node[i]->content, dirs, sizeof(dirs) - 1);
496 #else
497             strncpy(dirs, node[i]->content, sizeof(dirs) - 1);
498 #endif
499
500             if (!read_attr(syscheck,
501                            dirs,
502                            node[i]->attributes,
503                            node[i]->values)) {
504                 return (OS_INVALID);
505             }
506         }
507         /* Get Windows registry */
508         else if (strcmp(node[i]->element, xml_registry) == 0) {
509 #ifdef WIN32
510             if (!read_reg(syscheck, node[i]->content)) {
511                 return (OS_INVALID);
512             }
513 #endif
514         }
515         /* Get frequency */
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);
519                 return (OS_INVALID);
520             }
521
522             syscheck->time = atoi(node[i]->content);
523         }
524         /* Get scan time */
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);
529                 return (OS_INVALID);
530             }
531         }
532
533         /* Get scan day */
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);
538                 return (OS_INVALID);
539             }
540         }
541
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;
548             } else {
549                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
550                 return (OS_INVALID);
551             }
552         }
553
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;
560             } else {
561                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
562                 return (OS_INVALID);
563             }
564         }
565
566         /* Getting if skip_nfs. */
567         else if (strcmp(node[i]->element,xml_skip_nfs) == 0)
568         {
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;
573             else
574             {
575                 merror(XML_VALUEERR,__local_name,node[i]->element,node[i]->content);
576                 return(OS_INVALID);
577             }
578         }
579
580         /* Getting file/dir ignore */
581         else if (strcmp(node[i]->element,xml_ignore) == 0)
582         {
583             unsigned int ign_size = 0;
584
585 #ifdef WIN32
586             /* For Windows, we attempt to expand environment variables */
587             char *new_ig = NULL;
588             os_calloc(2048, sizeof(char), new_ig);
589
590             ExpandEnvironmentStrings(node[i]->content, new_ig, 2047);
591
592             free(node[i]->content);
593             node[i]->content = new_ig;
594 #endif
595             /* Add if regex */
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)) {
600                     OSMatch *mt_pt;
601
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;
606                     } else {
607                         while (syscheck->ignore_regex[ign_size] != NULL) {
608                             ign_size++;
609                         }
610
611                         os_realloc(syscheck->ignore_regex,
612                                    sizeof(OSMatch *) * (ign_size + 2),
613                                    syscheck->ignore_regex);
614                         syscheck->ignore_regex[ign_size + 1] = NULL;
615                     }
616                     os_calloc(1, sizeof(OSMatch),
617                               syscheck->ignore_regex[ign_size]);
618
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,
623                                mt_pt->error);
624                         return (0);
625                     }
626                 } else {
627                     merror(SK_INV_ATTR, __local_name, node[i]->attributes[0]);
628                     return (OS_INVALID);
629                 }
630             }
631
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;
638                 } else {
639                     while (syscheck->ignore[ign_size] != NULL) {
640                         ign_size++;
641                     }
642
643                     os_realloc(syscheck->ignore,
644                                sizeof(char *) * (ign_size + 2),
645                                syscheck->ignore);
646                     syscheck->ignore[ign_size + 1] = NULL;
647                 }
648                 os_strdup(node[i]->content, syscheck->ignore[ign_size]);
649             }
650         }
651
652         /* Get registry ignore list */
653         else if (strcmp(node[i]->element, xml_registry_ignore) == 0) {
654 #ifdef WIN32
655             int ign_size = 0;
656
657             /* Add if regex */
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)) {
662                     OSMatch *mt_pt;
663
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;
669                     } else {
670                         while (syscheck->registry_ignore_regex[ign_size] != NULL) {
671                             ign_size++;
672                         }
673
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;
678                     }
679
680                     os_calloc(1, sizeof(OSMatch),
681                               syscheck->registry_ignore_regex[ign_size]);
682
683                     if (!OSMatch_Compile(node[i]->content,
684                                          syscheck->registry_ignore_regex[ign_size], 0)) {
685                         mt_pt = (OSMatch *)
686                                 syscheck->registry_ignore_regex[ign_size];
687                         merror(REGEX_COMPILE, __local_name, node[i]->content,
688                                mt_pt->error);
689                         return (0);
690                     }
691                 } else {
692                     merror(SK_INV_ATTR, __local_name, node[i]->attributes[0]);
693                     return (OS_INVALID);
694                 }
695             }
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;
703                 } else {
704                     while (syscheck->registry_ignore[ign_size] != NULL) {
705                         ign_size++;
706                     }
707
708                     os_realloc(syscheck->registry_ignore,
709                                sizeof(char *) * (ign_size + 2),
710                                syscheck->registry_ignore);
711                     syscheck->registry_ignore[ign_size + 1] = NULL;
712                 }
713                 os_strdup(node[i]->content, syscheck->registry_ignore[ign_size]);
714             }
715 #endif
716         /* Getting file/dir nodiff */
717         } else if (strcmp(node[i]->element,xml_nodiff) == 0) {
718 #ifdef WIN32
719             /* For Windows, we attempt to expand environment variables */
720             char *new_nodiff = NULL;
721             os_calloc(2048, sizeof(char), new_nodiff);
722
723             ExpandEnvironmentStrings(node[i]->content, new_nodiff, 2047);
724
725             free(node[i]->content);
726             node[i]->content = new_nodiff;
727 #endif
728             /* Add if regex */
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)) {
733                     OSMatch *mt_pt;
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;
738                     } else {
739                         while (syscheck->nodiff_regex[nodiff_size] != NULL) {
740                             nodiff_size++;
741                         }
742
743                         os_realloc(syscheck->nodiff_regex,
744                                    sizeof(OSMatch *) * (nodiff_size + 2),
745                                    syscheck->nodiff_regex);
746                         syscheck->nodiff_regex[nodiff_size + 1] = NULL;
747                     }
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,
755                                mt_pt->error);
756                         return (0);
757                     }
758                     debug1("Found nodiff regex node %s OK?", node[i]->content);
759                     debug1("Found nodiff regex size %d", nodiff_size);
760                 } else {
761                     merror(SK_INV_ATTR, __local_name, node[i]->attributes[0]);
762                     return (OS_INVALID);
763                 }
764             }
765
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;
772                 } else {
773                     while (syscheck->nodiff[nodiff_size] != NULL) {
774                         nodiff_size++;
775                     }
776
777                     os_realloc(syscheck->nodiff,
778                                sizeof(char *) * (nodiff_size + 2),
779                                syscheck->nodiff);
780                     syscheck->nodiff[nodiff_size + 1] = NULL;
781                 }
782                 os_strdup(node[i]->content, syscheck->nodiff[nodiff_size]);
783             }
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) {
789             char cmd[OS_MAXSTR];
790             struct stat statbuf;
791
792 #ifdef WIN32
793             ExpandEnvironmentStrings(node[i]->content, cmd, sizeof(cmd) - 1);
794 #else
795             strncpy(cmd, node[i]->content, sizeof(cmd) - 1);
796 #endif
797
798             if (strlen(cmd) > 0) {
799                 char statcmd[OS_MAXSTR];
800                 char *ix;
801                 strncpy(statcmd, cmd, sizeof(statcmd) - 1);
802                 if (NULL != (ix = strchr(statcmd, ' '))) {
803                     *ix = '\0';
804                 }
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));
809                 } else {
810                     merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
811                     return (OS_INVALID);
812                 }
813             }
814         } else {
815             merror(XML_INVELEM, __local_name, node[i]->element);
816             return (OS_INVALID);
817         }
818         i++;
819     }
820
821     return (0);
822 }
823
824
825 /* return a text version of the directory check option bits,
826  * in a provided string buffer
827  */
828 char *syscheck_opts2str(char *buf, int buflen, int opts) {
829     int left = buflen;
830     int i;
831     int check_bits[] = {
832         CHECK_PERM,
833         CHECK_SIZE,
834         CHECK_OWNER,
835         CHECK_GROUP,
836         CHECK_MD5SUM,
837         CHECK_SHA1SUM,
838         CHECK_REALTIME,
839         CHECK_SEECHANGES,
840         CHECK_NORECURSE,
841         0
842         };
843     char *check_strings[] = {
844         "perm",
845         "size",
846         "owner",
847         "group",
848         "md5sum",
849         "sha1sum",
850         "realtime",
851         "report_changes",
852         "no_recurse",
853         NULL
854         };
855
856     buf[0] = '\0';
857     for ( i = 0; check_bits[ i ]; i++ ) {
858         if ( opts & check_bits[ i ] ) {
859             if ( left < buflen )  {
860                 strncat( buf, " | ", left );
861                 left -= 3;
862                 }
863             strncat( buf, check_strings[ i ], left );
864             left = buflen - strlen( buf );
865             }
866         }
867
868     return buf;
869     }
870