new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / config / active-response.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 #ifndef WIN32
11 #include <sys/types.h>
12 #include <grp.h>
13 #endif
14
15 #include "shared.h"
16 #include "os_xml/os_xml.h"
17 #include "os_regex/os_regex.h"
18 #include "active-response.h"
19 #include "config.h"
20
21 /* Global variables */
22 int ar_flag = 0;
23
24
25 /* Generate a list with all active responses */
26 int ReadActiveResponses(XML_NODE node, void *d1, void *d2)
27 {
28     OSList *l1 = (OSList *) d1;
29     OSList *l2 = (OSList *) d2;
30     FILE *fp;
31     int i = 0;
32     int r_ar = 0;
33     int l_ar = 0;
34     int rpt = 0;
35
36     /* Xml options */
37     const char *xml_ar_command = "command";
38     const char *xml_ar_location = "location";
39     const char *xml_ar_agent_id = "agent_id";
40     const char *xml_ar_rules_id = "rules_id";
41     const char *xml_ar_rules_group = "rules_group";
42     const char *xml_ar_level = "level";
43     const char *xml_ar_timeout = "timeout";
44     const char *xml_ar_disabled = "disabled";
45     const char *xml_ar_repeated = "repeated_offenders";
46
47     char *tmp_location;
48
49     /* Currently active response */
50     active_response *tmp_ar;
51
52     /* Open shared ar file */
53     fp = fopen(DEFAULTARPATH, "a");
54     if (!fp) {
55         merror(FOPEN_ERROR, __local_name, DEFAULTARPATH, errno, strerror(errno));
56         return (-1);
57     }
58
59 #ifndef WIN32
60     struct group *os_group;
61     if ((os_group = getgrnam(USER)) == NULL) {
62         merror("Could not get ossec gid.");
63         fclose(fp);
64         return (-1);
65     }
66
67     if ((chown(DEFAULTARPATH, (uid_t) - 1, os_group->gr_gid)) == -1) {
68         merror("Could not change the group to ossec: %d", errno);
69         fclose(fp);
70         return (-1);
71     }
72 #endif
73
74     if ((chmod(DEFAULTARPATH, 0440)) == -1) {
75         merror("Could not chmod to 0440: %d", errno);
76         fclose(fp);
77         return (-1);
78     }
79
80     /* Allocate for the active-response */
81     tmp_ar = (active_response *) calloc(1, sizeof(active_response));
82     if (!tmp_ar) {
83         merror(MEM_ERROR, __local_name, errno, strerror(errno));
84         fclose(fp);
85         return (-1);
86     }
87
88     /* Initialize variables */
89     tmp_ar->name = NULL;
90     tmp_ar->command = NULL;
91     tmp_ar->location = 0;
92     tmp_ar->timeout = 0;
93     tmp_ar->level = 0;
94     tmp_ar->agent_id = NULL;
95     tmp_ar->rules_id = NULL;
96     tmp_ar->rules_group = NULL;
97     tmp_ar->ar_cmd = NULL;
98     tmp_location = NULL;
99
100     /* Search for the commands */
101     while (node[i]) {
102         if (!node[i]->element) {
103             merror(XML_ELEMNULL, __local_name);
104             goto error_invalid;
105         } else if (!node[i]->content) {
106             merror(XML_VALUENULL, __local_name, node[i]->element);
107             goto error_invalid;
108         }
109
110         /* Command */
111         if (strcmp(node[i]->element, xml_ar_command) == 0) {
112             tmp_ar->command = strdup(node[i]->content);
113         }
114         /* Target */
115         else if (strcmp(node[i]->element, xml_ar_location) == 0) {
116             free(tmp_location);
117             tmp_location = strdup(node[i]->content);
118         } else if (strcmp(node[i]->element, xml_ar_agent_id) == 0) {
119             tmp_ar->agent_id = strdup(node[i]->content);
120         } else if (strcmp(node[i]->element, xml_ar_rules_id) == 0) {
121             tmp_ar->rules_id = strdup(node[i]->content);
122         } else if (strcmp(node[i]->element, xml_ar_rules_group) == 0) {
123             tmp_ar->rules_group = strdup(node[i]->content);
124         } else if (strcmp(node[i]->element, xml_ar_level) == 0) {
125             /* Level must be numeric */
126             if (!OS_StrIsNum(node[i]->content)) {
127                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
128                 goto error_invalid;
129             }
130
131             tmp_ar->level = atoi(node[i]->content);
132
133             /* Make sure the level is valid */
134             if ((tmp_ar->level < 0) || (tmp_ar->level > 20)) {
135                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
136                 goto error_invalid;
137             }
138         } else if (strcmp(node[i]->element, xml_ar_timeout) == 0) {
139             tmp_ar->timeout = atoi(node[i]->content);
140         } else if (strcmp(node[i]->element, xml_ar_disabled) == 0) {
141             if (strcmp(node[i]->content, "yes") == 0) {
142                 ar_flag = -1;
143             } else if (strcmp(node[i]->content, "no") == 0) {
144                 /* Don't do anything if disabled is set to "no" */
145             } else {
146                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
147                 goto error_invalid;
148             }
149         } else if (strcmp(node[i]->element, xml_ar_repeated) == 0) {
150             /* Nothing - we deal with it on execd */
151             rpt = 1;
152         } else {
153             merror(XML_INVELEM, __local_name, node[i]->element);
154             goto error_invalid;
155         }
156         i++;
157     }
158
159     /* Check if ar is disabled */
160     if (ar_flag == -1) {
161         /* reset ar_flag, the next ar command may not be disabled */
162         ar_flag = 0;
163         debug1("active response command '%s' is disabled", tmp_ar->command);
164         fclose(fp);
165         free(tmp_ar);
166         free(tmp_location);
167         return (0);
168     }
169
170     /* Command and location must be there */
171     if (!tmp_ar->command || !tmp_location) {
172         debug1("command or location missing");
173         fclose(fp);
174         free(tmp_ar);
175         free(tmp_location);
176
177         if (rpt == 1) {
178             return (0);
179         }
180         merror(AR_MISS, __local_name);
181         return (-1);
182     }
183
184     /* analysisd */
185     if (OS_Regex("AS|analysisd|analysis-server|server", tmp_location)) {
186         tmp_ar->location |= AS_ONLY;
187     }
188
189     if (OS_Regex("local", tmp_location)) {
190         tmp_ar->location |= REMOTE_AGENT;
191     }
192
193     if (OS_Regex("defined-agent", tmp_location)) {
194         if (!tmp_ar->agent_id) {
195             debug1("'defined-agent' agent_id not defined");
196             merror(AR_DEF_AGENT, __local_name);
197             fclose(fp);
198             free(tmp_ar);
199             free(tmp_location);
200             return (-1);
201         }
202
203         tmp_ar->location |= SPECIFIC_AGENT;
204
205     }
206     if (OS_Regex("all|any", tmp_location)) {
207         tmp_ar->location |= ALL_AGENTS;
208     }
209
210     /* If we didn't set any value for the location */
211     if (tmp_ar->location == 0) {
212         debug1("no location defined");
213         merror(AR_INV_LOC, __local_name, tmp_location);
214         fclose(fp);
215         free(tmp_ar);
216         free(tmp_location);
217         return (-1);
218     }
219
220     /* Clean tmp_location */
221     free(tmp_location);
222     tmp_location = NULL;
223
224     /* Check if command name is valid */
225     {
226         OSListNode *my_commands_node;
227
228         my_commands_node = OSList_GetFirstNode(l1);
229         while (my_commands_node) {
230             ar_command *my_command;
231             my_command = (ar_command *)my_commands_node->data;
232
233             if (strcmp(my_command->name, tmp_ar->command) == 0) {
234                 tmp_ar->ar_cmd = my_command;
235                 break;
236             }
237
238             my_commands_node = OSList_GetNextNode(l1);
239         }
240
241         /* Didn't find a valid command */
242         if (tmp_ar->ar_cmd == NULL) {
243             debug1("invalid command");
244             merror(AR_INV_CMD, __local_name, tmp_ar->command);
245             fclose(fp);
246             free(tmp_ar);
247             return (-1);
248         }
249     }
250
251     /* Check if timeout is allowed */
252     if (tmp_ar->timeout && !tmp_ar->ar_cmd->timeout_allowed) {
253         debug1("timeout is not allowed");
254         merror(AR_NO_TIMEOUT, __local_name, tmp_ar->ar_cmd->name);
255         fclose(fp);
256         free(tmp_ar);
257         return (-1);
258     }
259
260     /* d1 is the active response list */
261     if (!OSList_AddData(l2, (void *)tmp_ar)) {
262         merror(LIST_ADD_ERROR, __local_name);
263         fclose(fp);
264         free(tmp_ar);
265         return (-1);
266     }
267
268     /* Set a unique active response name */
269     tmp_ar->name = (char *) calloc(OS_FLSIZE + 1, sizeof(char));
270     if (!tmp_ar->name) {
271         ErrorExit(MEM_ERROR, __local_name, errno, strerror(errno));
272     }
273     snprintf(tmp_ar->name, OS_FLSIZE, "%s%d",
274              tmp_ar->ar_cmd->name,
275              tmp_ar->timeout);
276
277     /* Add to shared file */
278     debug1("writing command '%s' to '%s'", tmp_ar->command, DEFAULTARPATH);
279     fprintf(fp, "%s - %s - %d\n",
280             tmp_ar->name,
281             tmp_ar->ar_cmd->executable,
282             tmp_ar->timeout);
283
284     /* Set the configs to start the right queues */
285     if (tmp_ar->location & AS_ONLY) {
286         l_ar = 1;
287     }
288     if (tmp_ar->location & ALL_AGENTS) {
289         r_ar = 1;
290     }
291     if (tmp_ar->location & REMOTE_AGENT) {
292         r_ar = 1;
293         l_ar = 1;
294     }
295     if (tmp_ar->location & SPECIFIC_AGENT) {
296         r_ar = 1;
297     }
298
299     /* Set the configuration for the active response */
300     if (r_ar && (!(ar_flag & REMOTE_AR))) {
301         ar_flag |= REMOTE_AR;
302     }
303     if (l_ar && (!(ar_flag & LOCAL_AR))) {
304         ar_flag |= LOCAL_AR;
305     }
306
307     /* Close shared file for active response */
308     fclose(fp);
309
310     /* Done over here */
311     return (0);
312
313 error_invalid:
314     /* In case of an error clean up first*/
315     fclose(fp);
316     free(tmp_ar);
317     free(tmp_location);
318
319     return (OS_INVALID);
320 }
321
322 int ReadActiveCommands(XML_NODE node, void *d1, __attribute__((unused)) void *d2)
323 {
324     OSList *l1 = (OSList *) d1;
325     int i = 0;
326     char *tmp_str = NULL;
327
328     /* Xml values */
329     const char *command_name = "name";
330     const char *command_expect = "expect";
331     const char *command_executable = "executable";
332     const char *timeout_allowed = "timeout_allowed";
333
334     ar_command *tmp_command;
335
336     /* Allocate the active-response command */
337     tmp_command = (ar_command *) calloc(1, sizeof(ar_command));
338     if (!tmp_command) {
339         merror(MEM_ERROR, __local_name, errno, strerror(errno));
340         return (-1);
341     }
342
343     tmp_command->name = NULL;
344     tmp_command->expect = 0;
345     tmp_command->executable = NULL;
346     tmp_command->timeout_allowed = 0;
347
348     /* Search for the commands */
349     while (node[i]) {
350         if (!node[i]->element) {
351             merror(XML_ELEMNULL, __local_name);
352             free(tmp_str);
353             free(tmp_command);
354             return (OS_INVALID);
355         } else if (!node[i]->content) {
356             merror(XML_VALUENULL, __local_name, node[i]->element);
357             free(tmp_str);
358             free(tmp_command);
359             return (OS_INVALID);
360         }
361         if (strcmp(node[i]->element, command_name) == 0) {
362             tmp_command->name = strdup(node[i]->content);
363         } else if (strcmp(node[i]->element, command_expect) == 0) {
364             free(tmp_str);
365             tmp_str = strdup(node[i]->content);
366         } else if (strcmp(node[i]->element, command_executable) == 0) {
367             tmp_command->executable = strdup(node[i]->content);
368         } else if (strcmp(node[i]->element, timeout_allowed) == 0) {
369             if (strcmp(node[i]->content, "yes") == 0) {
370                 tmp_command->timeout_allowed = 1;
371             } else if (strcmp(node[i]->content, "no") == 0) {
372                 tmp_command->timeout_allowed = 0;
373             } else {
374                 merror(XML_VALUEERR, __local_name, node[i]->element, node[i]->content);
375                 free(tmp_str);
376                 free(tmp_command);
377                 return (OS_INVALID);
378             }
379         } else {
380             merror(XML_INVELEM, __local_name, node[i]->element);
381             free(tmp_str);
382             free(tmp_command);
383             return (OS_INVALID);
384         }
385         i++;
386     }
387
388     if (!tmp_command->name || !tmp_str || !tmp_command->executable) {
389         merror(AR_CMD_MISS, __local_name);
390         free(tmp_str);
391         free(tmp_command);
392         return (-1);
393     }
394
395     /* Get the expect */
396     if (strlen(tmp_str) >= 4) {
397         if (OS_Regex("user", tmp_str)) {
398             tmp_command->expect |= USERNAME;
399         }
400         if (OS_Regex("srcip", tmp_str)) {
401             tmp_command->expect |= SRCIP;
402         }
403         if (OS_Regex("filename", tmp_str)) {
404             tmp_command->expect |= FILENAME;
405         }
406     }
407
408     free(tmp_str);
409     tmp_str = NULL;
410
411     /* Add command to the list */
412     if (!OSList_AddData(l1, (void *)tmp_command)) {
413         merror(LIST_ADD_ERROR, __local_name);
414         free(tmp_command);
415         return (-1);
416     }
417
418     return (0);
419 }
420