new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / syscheckd / syscheck.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights 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 /* Syscheck
11  * Copyright (C) 2003 Daniel B. Cid <daniel@underlinux.com.br>
12  */
13
14 #include "shared.h"
15 #include "syscheck.h"
16 #include "rootcheck/rootcheck.h"
17
18 /* Prototypes */
19 static void read_internal(int debug_level);
20 #ifndef WIN32
21 static void help_syscheckd(void) __attribute__((noreturn));
22 #endif
23
24 syscheck_config syscheck;
25
26 #ifdef USE_MAGIC
27 #include <magic.h>
28 magic_t magic_cookie = 0;
29
30
31 void init_magic(magic_t *cookie_ptr)
32 {
33     if (!cookie_ptr || *cookie_ptr) {
34         return;
35     }
36
37     *cookie_ptr = magic_open(MAGIC_MIME_TYPE);
38
39     if (!*cookie_ptr) {
40         const char *err = magic_error(*cookie_ptr);
41         merror("%s: ERROR: Can't init libmagic: %s", ARGV0, err ? err : "unknown");
42     } else if (magic_load(*cookie_ptr, NULL) < 0) {
43         const char *err = magic_error(*cookie_ptr);
44         merror("%s: ERROR: Can't load magic file: %s", ARGV0, err ? err : "unknown");
45         magic_close(*cookie_ptr);
46         *cookie_ptr = 0;
47     }
48 }
49 #endif /* USE_MAGIC */
50
51 /* Read syscheck internal options */
52 static void read_internal(int debug_level)
53 {
54     syscheck.tsleep = (unsigned int) getDefine_Int("syscheck", "sleep", 0, 64);
55     syscheck.sleep_after = getDefine_Int("syscheck", "sleep_after", 1, 9999);
56
57     /* Check current debug_level
58      * Command line setting takes precedence
59      */
60     if (debug_level == 0) {
61         debug_level = getDefine_Int("syscheck", "debug", 0, 2);
62         while (debug_level != 0) {
63             nowDebug();
64             debug_level--;
65         }
66     }
67
68     return;
69 }
70
71 #ifdef WIN32
72 /* syscheck main for Windows */
73 int Start_win32_Syscheck()
74 {
75     int debug_level = 0;
76     int r = 0;
77     char *cfg = DEFAULTCPATH;
78
79     /* Read internal options */
80     read_internal(debug_level);
81
82     debug1(STARTED_MSG, ARGV0);
83
84     /* Check if the configuration is present */
85     if (File_DateofChange(cfg) < 0) {
86         ErrorExit(NO_CONFIG, ARGV0, cfg);
87     }
88
89     /* Read syscheck config */
90     if ((r = Read_Syscheck_Config(cfg)) < 0) {
91         ErrorExit(CONFIG_ERROR, ARGV0, cfg);
92     } else if ((r == 1) || (syscheck.disabled == 1)) {
93         /* Disabled */
94         if (!syscheck.dir) {
95             merror(SK_NO_DIR, ARGV0);
96             dump_syscheck_entry(&syscheck, "", 0, 0, NULL);
97         } else if (!syscheck.dir[0]) {
98             merror(SK_NO_DIR, ARGV0);
99         }
100         syscheck.dir[0] = NULL;
101
102         if (!syscheck.registry) {
103             dump_syscheck_entry(&syscheck, "", 0, 1, NULL);
104         }
105         syscheck.registry[0] = NULL;
106
107         merror("%s: WARN: Syscheck disabled.", ARGV0);
108     }
109
110     /* Rootcheck config */
111     if (rootcheck_init(0) == 0) {
112         syscheck.rootcheck = 1;
113     } else {
114         syscheck.rootcheck = 0;
115         merror("%s: WARN: Rootcheck module disabled.", ARGV0);
116     }
117
118     /* Print options */
119     r = 0;
120     while (syscheck.registry[r] != NULL) {
121         verbose("%s: INFO: Monitoring registry entry: '%s'.",
122                 ARGV0, syscheck.registry[r]);
123         r++;
124     }
125
126     /* Print directories to be monitored */
127     r = 0;
128     while (syscheck.dir[r] != NULL) {
129         char optstr[ 100 ];
130         verbose("%s: INFO: Monitoring directory: '%s', with options %s.",
131             ARGV0, syscheck.dir[r],
132             syscheck_opts2str(optstr, sizeof( optstr ), syscheck.opts[r]));
133         r++;
134     }
135
136     /* Print ignores. */
137     if(syscheck.ignore)
138         for (r = 0; syscheck.ignore[r] != NULL; r++)
139             verbose("%s: INFO: ignoring: '%s'",
140                 ARGV0, syscheck.ignore[r]);
141
142
143     /* Print files with no diff. */
144     if (syscheck.nodiff){
145         r = 0;
146         while (syscheck.nodiff[r] != NULL) {
147             verbose("%s: INFO: No diff for file: '%s'",
148                     ARGV0, syscheck.nodiff[r]);
149             r++;
150         }
151     }
152
153     /* Start up message */
154     verbose(STARTUP_MSG, ARGV0, getpid());
155
156     /* Some sync time */
157     sleep(syscheck.tsleep + 10);
158
159     /* Wait if agent started properly */
160     os_wait();
161
162     start_daemon();
163
164     exit(0);
165 }
166 #endif /* WIN32 */
167
168 #ifndef WIN32
169 /* Print help statement */
170 static void help_syscheckd()
171 {
172     print_header();
173     print_out("  %s: -[Vhdtf] [-c config]", ARGV0);
174     print_out("    -V          Version and license message");
175     print_out("    -h          This help message");
176     print_out("    -d          Execute in debug mode. This parameter");
177     print_out("                can be specified multiple times");
178     print_out("                to increase the debug level.");
179     print_out("    -t          Test configuration");
180     print_out("    -f          Run in foreground");
181     print_out("    -c <config> Configuration file to use (default: %s)", DEFAULTCPATH);
182     print_out(" ");
183     exit(1);
184 }
185
186 /* Syscheck unix main */
187 int main(int argc, char **argv)
188 {
189     int c, r;
190     int debug_level = 0;
191     int test_config = 0, run_foreground = 0;
192     const char *cfg = DEFAULTCPATH;
193
194     /* Set the name */
195     OS_SetName(ARGV0);
196
197     while ((c = getopt(argc, argv, "Vtdhfc:")) != -1) {
198         switch (c) {
199             case 'V':
200                 print_version();
201                 break;
202             case 'h':
203                 help_syscheckd();
204                 break;
205             case 'd':
206                 nowDebug();
207                 debug_level ++;
208                 break;
209             case 'f':
210                 run_foreground = 1;
211                 break;
212             case 'c':
213                 if (!optarg) {
214                     ErrorExit("%s: -c needs an argument", ARGV0);
215                 }
216                 cfg = optarg;
217                 break;
218             case 't':
219                 test_config = 1;
220                 break;
221             default:
222                 help_syscheckd();
223                 break;
224         }
225     }
226
227     /* Read internal options */
228     read_internal(debug_level);
229
230     debug1(STARTED_MSG, ARGV0);
231
232     /* Check if the configuration is present */
233     if (File_DateofChange(cfg) < 0) {
234         ErrorExit(NO_CONFIG, ARGV0, cfg);
235     }
236
237     /* Read syscheck config */
238     if ((r = Read_Syscheck_Config(cfg)) < 0) {
239         ErrorExit(CONFIG_ERROR, ARGV0, cfg);
240     } else if ((r == 1) || (syscheck.disabled == 1)) {
241         if (!syscheck.dir) {
242             if (!test_config) {
243                 merror(SK_NO_DIR, ARGV0);
244             }
245             dump_syscheck_entry(&syscheck, "", 0, 0, NULL);
246         } else if (!syscheck.dir[0]) {
247             if (!test_config) {
248                 merror(SK_NO_DIR, ARGV0);
249             }
250         }
251         syscheck.dir[0] = NULL;
252         if (!test_config) {
253             merror("%s: WARN: Syscheck disabled.", ARGV0);
254         }
255     }
256
257     /* Rootcheck config */
258     if (rootcheck_init(test_config) == 0) {
259         syscheck.rootcheck = 1;
260     } else {
261         syscheck.rootcheck = 0;
262         merror("%s: WARN: Rootcheck module disabled.", ARGV0);
263     }
264
265     /* Exit if testing config */
266     if (test_config) {
267         exit(0);
268     }
269
270     /* Setup libmagic */
271 #ifdef USE_MAGIC
272     init_magic(&magic_cookie);
273 #endif
274
275     if (!run_foreground) {
276         nowDaemon();
277         goDaemon();
278     }
279
280     /* Initial time to settle */
281     sleep(syscheck.tsleep + 2);
282
283     /* Connect to the queue */
284     if ((syscheck.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
285         merror(QUEUE_ERROR, ARGV0, DEFAULTQPATH, strerror(errno));
286
287         sleep(5);
288         if ((syscheck.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
289             /* more 10 seconds of wait */
290             merror(QUEUE_ERROR, ARGV0, DEFAULTQPATH, strerror(errno));
291             sleep(10);
292             if ((syscheck.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
293                 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
294             }
295         }
296     }
297
298     /* Start signal handling */
299     StartSIG(ARGV0);
300
301     /* Create pid */
302     if (CreatePID(ARGV0, getpid()) < 0) {
303         merror(PID_ERROR, ARGV0);
304     }
305
306     /* Start up message */
307     verbose(STARTUP_MSG, ARGV0, (int)getpid());
308
309     if (syscheck.rootcheck) {
310         verbose(STARTUP_MSG, "ossec-rootcheck", (int)getpid());
311     }
312
313     /* Print directories to be monitored */
314     r = 0;
315     while (syscheck.dir[r] != NULL) {
316         char optstr[ 100 ];
317         verbose("%s: INFO: Monitoring directory: '%s', with options %s.",
318             ARGV0, syscheck.dir[r],
319             syscheck_opts2str(optstr, sizeof( optstr ), syscheck.opts[r]));
320         r++;
321     }
322
323     /* Print ignores. */
324     if(syscheck.ignore)
325         for (r = 0; syscheck.ignore[r] != NULL; r++)
326             verbose("%s: INFO: ignoring: '%s'",
327                 ARGV0, syscheck.ignore[r]);
328
329     /* Print files with no diff. */
330     if (syscheck.nodiff){
331         r = 0;
332         while (syscheck.nodiff[r] != NULL) {
333             verbose("%s: INFO: No diff for file: '%s'",
334                     ARGV0, syscheck.nodiff[r]);
335             r++;
336         }
337     }
338
339     /* Check directories set for real time */
340     r = 0;
341     while (syscheck.dir[r] != NULL) {
342         if (syscheck.opts[r] & CHECK_REALTIME) {
343 #ifdef INOTIFY_ENABLED
344             verbose("%s: INFO: Directory set for real time monitoring: "
345                     "'%s'.", ARGV0, syscheck.dir[r]);
346 #elif defined(WIN32)
347             verbose("%s: INFO: Directory set for real time monitoring: "
348                     "'%s'.", ARGV0, syscheck.dir[r]);
349 #else
350             verbose("%s: WARN: Ignoring flag for real time monitoring on "
351                     "directory: '%s'.", ARGV0, syscheck.dir[r]);
352 #endif
353         }
354         r++;
355     }
356
357     /* Some sync time */
358     sleep(syscheck.tsleep + 10);
359
360     /* Start the daemon */
361     start_daemon();
362 }
363
364 #endif /* !WIN32 */
365