new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / analysisd / output / prelude.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 /*
11  * OSSEC to Prelude
12  */
13
14 #ifdef PRELUDE_OUTPUT_ENABLED
15
16 #include <libprelude/prelude.h>
17 #include <libprelude/prelude-log.h>
18 #include <libprelude/idmef-message-print.h>
19
20 #include "prelude.h"
21
22 #include "shared.h"
23 #include "rules.h"
24
25 #define DEFAULT_ANALYZER_NAME "OSSEC"
26 #define ANALYZER_CLASS "Host IDS, File Integrity Checker, Log Analyzer"
27 #define ANALYZER_MODEL "Ossec"
28 #define ANALYZER_MANUFACTURER __site
29 #define ANALYZER_VERSION __version
30
31 /** OSSEC to prelude severity mapping. **/
32 static const char *(ossec2prelude_sev[]) = {"info", "info", "info", "info",
33                                "low", "low", "low", "low",
34                                "medium", "medium", "medium", "medium",
35                                "high", "high", "high", "high", "high"
36                               };
37
38 /* Prelude client */
39 static prelude_client_t *prelude_client;
40
41
42 /*void prelude_idmef_debug(idmef_message_t *idmef)
43 {
44     prelude_io_t *pio;
45
46     prelude_io_new(&pio);
47     prelude_io_set_file_io(pio, stderr);
48     idmef_message_print(idmef, pio);
49     prelude_io_destroy(pio);
50 }*/
51
52 static int
53 add_idmef_object(idmef_message_t *msg, const char *object, const char *value)
54 {
55     int ret = 0;
56     idmef_value_t *val;
57     idmef_path_t *path;
58
59     if (value == NULL) {
60         return (0);
61     }
62
63     ret = idmef_path_new_fast(&path, object);
64     if (ret < 0) {
65         return (-1);
66     }
67
68     ret = idmef_value_new_from_path(&val, path, value);
69     if (ret < 0) {
70         idmef_path_destroy(path);
71         return (-1);
72     }
73
74     ret = idmef_path_set(path, msg, val);
75     if (ret < 0) {
76         merror("%s: OSSEC2Prelude: IDMEF: Cannot add object '%s': %s.",
77                ARGV0, object, prelude_strerror(ret));
78     }
79
80     idmef_value_destroy(val);
81     idmef_path_destroy(path);
82
83     return (ret);
84 }
85
86 static int
87 setup_analyzer(idmef_analyzer_t *analyzer)
88 {
89     int ret;
90     prelude_string_t *string;
91
92     ret = idmef_analyzer_new_model(analyzer, &string);
93     if ( ret < 0 ) {
94         goto err;
95     }
96     prelude_string_set_constant(string, ANALYZER_MODEL);
97
98     ret = idmef_analyzer_new_class(analyzer, &string);
99     if ( ret < 0 ) {
100         goto err;
101     }
102     prelude_string_set_constant(string, ANALYZER_CLASS);
103
104     ret = idmef_analyzer_new_manufacturer(analyzer, &string);
105     if ( ret < 0 ) {
106         goto err;
107     }
108     prelude_string_set_constant(string, ANALYZER_MANUFACTURER);
109
110     ret = idmef_analyzer_new_version(analyzer, &string);
111     if ( ret < 0 ) {
112         goto err;
113     }
114     prelude_string_set_constant(string, ANALYZER_VERSION);
115
116     return 0;
117
118 err:
119     merror("%s: OSSEC2Prelude: %s: IDMEF error: %s.",
120            ARGV0, prelude_strsource(ret), prelude_strerror(ret));
121
122     return -1;
123 }
124
125 void prelude_start(const char *profile, int argc, char **argv)
126 {
127     int ret;
128     prelude_client = NULL;
129
130     ret = prelude_init(&argc, argv);
131     if (ret < 0) {
132         merror("%s: %s: Unable to initialize the Prelude library: %s.",
133                ARGV0, prelude_strsource(ret), prelude_strerror(ret));
134         return;
135     }
136
137     ret = prelude_client_new(&prelude_client,
138                              profile != NULL ? profile : DEFAULT_ANALYZER_NAME);
139     if (!prelude_client) {
140         merror("%s: %s: Unable to create a prelude client object: %s.",
141                ARGV0, prelude_strsource(ret), prelude_strerror(ret));
142
143         return;
144     }
145
146     ret = setup_analyzer(prelude_client_get_analyzer(prelude_client));
147     if (ret < 0) {
148         merror("%s: %s: Unable to setup analyzer: %s",
149                ARGV0, prelude_strsource(ret), prelude_strerror(ret));
150
151         prelude_client_destroy(prelude_client,
152                                PRELUDE_CLIENT_EXIT_STATUS_FAILURE);
153
154         return;
155     }
156
157     ret = prelude_client_set_flags(prelude_client,
158                                    prelude_client_get_flags(prelude_client)
159                                    | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER);
160     if (ret < 0) {
161         merror("%s: %s: Unable to set prelude client flags: %s.",
162                ARGV0, prelude_strsource(ret), prelude_strerror(ret));
163     }
164
165     /* Set uid and gid of ossec */
166     prelude_client_profile_set_uid(prelude_client_get_profile(prelude_client),
167                                    Privsep_GetUser(USER));
168     prelude_client_profile_set_gid(prelude_client_get_profile(prelude_client),
169                                    Privsep_GetGroup(GROUPGLOBAL));
170
171     ret = prelude_client_start(prelude_client);
172     if (ret < 0) {
173         merror("%s: %s: Unable to initialize prelude client: %s.",
174                ARGV0, prelude_strsource(ret), prelude_strerror(ret));
175
176         prelude_client_destroy(prelude_client,
177                                PRELUDE_CLIENT_EXIT_STATUS_FAILURE);
178
179         return;
180     }
181
182     return;
183 }
184
185 static void FileAccess_PreludeLog(idmef_message_t *idmef,
186                            const char *category,
187                            const char *filename,
188                            const char *md5,
189                            const char *sha1,
190                            const char *owner,
191                            const char *gowner,
192                            int perm)
193 {
194
195     debug1("%s: DEBUG: filename = %s.", ARGV0, filename);
196     debug1("%s: DEBUG: category = %s.", ARGV0, category);
197     add_idmef_object(idmef, "alert.target(0).file(>>).name", filename);
198     add_idmef_object(idmef, "alert.target(0).file(-1).category", category);
199
200     /* Add the hashes */
201     if (md5) {
202         add_idmef_object(idmef, "alert.target(0).file(-1).checksum(>>).algorithm", "MD5");
203         add_idmef_object(idmef, "alert.target(0).file(-1).checksum(-1).value", md5);
204     }
205     if (sha1) {
206         add_idmef_object(idmef, "alert.target(0).file(-1).checksum(>>).algorithm", "SHA1");
207         add_idmef_object(idmef, "alert.target(0).file(-1).checksum(-1).value", sha1);
208     }
209
210     /* Add the owner */
211     if (owner) {
212         debug1("%s: DEBUG: owner = %s.", ARGV0, owner);
213         add_idmef_object(idmef, "alert.target(0).file(-1).file_access(>>).user_id.number", owner);
214         add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).user_id.type", "user-privs");
215
216         if (perm) {
217             /* Add the permissions */
218             if (perm & S_IWUSR) {
219                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "write");
220                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "delete");
221             }
222             if (perm & S_IXUSR) {
223                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "execute");
224             }
225             if (perm & S_IRUSR ) {
226                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "read");
227             }
228             if (perm & S_ISUID) {
229                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "executeAs");
230             }
231         }
232     }
233
234     /* Add the group owner */
235     if (gowner) {
236         debug1("%s: DEBUG: gowner = %s.", ARGV0, gowner);
237         add_idmef_object(idmef, "alert.target(0).file(-1).file_access(>>).user_id.number", gowner);
238         add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).user_id.type", "group-privs");
239
240         if (perm) {
241             /* Add the permissions */
242             if (perm & S_IWGRP) {
243                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "write");
244                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "delete");
245             }
246             if (perm & S_IXGRP) {
247                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "execute");
248             }
249             if (perm & S_IRGRP ) {
250                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "read");
251             }
252             if (perm & S_ISGID) {
253                 add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "executeAs");
254             }
255         }
256     }
257
258     add_idmef_object(idmef, "alert.target(0).file(-1).file_access(>>).user_id.type", "other-privs");
259
260     if (perm) {
261         /* Add the permissions */
262         if (perm & S_IWOTH) {
263             add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "write");
264             add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "delete");
265         }
266         if (perm & S_IXOTH) {
267             add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "execute");
268         }
269         if (perm & S_IROTH ) {
270             add_idmef_object(idmef, "alert.target(0).file(-1).file_access(-1).permission(>>)", "read");
271         }
272     }
273     return;
274 }
275
276 void OS_PreludeLog(const Eventinfo *lf)
277 {
278     int ret;
279     char _prelude_data[256];
280     char *origin;
281     idmef_message_t *idmef;
282     RuleInfoDetail *last_info_detail;
283
284     /* Generate prelude alert */
285     ret = idmef_message_new(&idmef);
286     if ( ret < 0 ) {
287         merror("%s: OSSEC2Prelude: Cannot create IDMEF message", ARGV0);
288         return;
289     }
290
291     add_idmef_object(idmef, "alert.assessment.impact.description",
292                      lf->generated_rule->comment);
293
294     add_idmef_object(idmef, "alert.assessment.impact.severity",
295                      (lf->generated_rule->level > 15) ? "high" :
296                      ossec2prelude_sev[lf->generated_rule->level]);
297
298     add_idmef_object(idmef, "alert.assessment.impact.completion", "succeeded");
299
300     if (lf->action) {
301         switch (*lf->action) {
302             /* discard, drop, deny, */
303             case 'd':
304             case 'D':
305             /* reject, */
306             case 'r':
307             case 'R':
308             /* block */
309             case 'b':
310             case 'B':
311                 snprintf(_prelude_data, 256, "DROP: %s", lf->action);
312                 break;
313             /* Closed */
314             case 'c':
315             case 'C':
316             /* Teardown */
317             case 't':
318             case 'T':
319                 snprintf(_prelude_data, 256, "CLOSED: %s", lf->action);
320                 break;
321             /* allow, accept, */
322             case 'a':
323             case 'A':
324             /* pass/permitted */
325             case 'p':
326             case 'P':
327             /* open */
328             case 'o':
329             case 'O':
330                 snprintf(_prelude_data, 256, "ALLOW: %s", lf->action);
331                 break;
332             default:
333                 snprintf(_prelude_data, 256, "%s", lf->action);
334                 break;
335         }
336         add_idmef_object(idmef, "alert.assessment.action(0).category", "3");
337         add_idmef_object(idmef, "alert.assessment.action(0).description", _prelude_data);
338     }
339
340     /* Begin Classification Infomations */
341     {
342         add_idmef_object(idmef, "alert.classification.text",
343                          lf->generated_rule->comment);
344
345         /* The Common Vulnerabilities and Exposures (CVE) (http://www.cve.mitre.org/)
346          * infomation if present in the triggering rule
347          */
348         if (lf->generated_rule->cve) {
349             add_idmef_object(idmef, "alert.classification.reference(>>).origin", "cve");
350             add_idmef_object(idmef, "alert.classification.reference(-1).name", lf->generated_rule->cve);
351
352             snprintf(_prelude_data, 256, "CVE:%s", lf->generated_rule->cve);
353             add_idmef_object(idmef, "alert.classification.reference(-1).meaning", _prelude_data);
354         }
355
356         /* Rule sid is used to create a link to the rule on the OSSEC wiki */
357         if (lf->generated_rule->sigid) {
358             add_idmef_object(idmef, "alert.classification.reference(>>).origin", "vendor-specific");
359
360             snprintf(_prelude_data, 256, "Rule:%d", lf->generated_rule->sigid);
361             add_idmef_object(idmef, "alert.classification.reference(-1).name", _prelude_data);
362             add_idmef_object(idmef, "alert.classification.reference(-1).meaning", "OSSEC Rule Wiki Documentation");
363
364             snprintf(_prelude_data, 256, "http://www.ossec.net/wiki/Rule:%d",
365                      lf->generated_rule->sigid);
366             add_idmef_object(idmef, "alert.classification.reference(-1).url", _prelude_data);
367         }
368
369         /* Extended Info Details */
370         for (last_info_detail = lf->generated_rule->info_details;
371                 last_info_detail != NULL;
372                 last_info_detail = last_info_detail->next) {
373             if (last_info_detail->type == RULEINFODETAIL_LINK) {
374                 add_idmef_object(idmef, "alert.classification.reference(>>).origin", "vendor-specific");
375
376                 snprintf(_prelude_data, 256, "Rule:%d link", lf->generated_rule->sigid);
377                 add_idmef_object(idmef, "alert.classification.reference(-1).name", _prelude_data);
378                 add_idmef_object(idmef, "alert.classification.reference(-1).url", last_info_detail->data);
379
380             } else if (last_info_detail->type == RULEINFODETAIL_TEXT) {
381                 add_idmef_object(idmef, "alert.classification.reference(>>).origin", "vendor-specific");
382
383                 snprintf(_prelude_data, 256, "Rule:%d info", lf->generated_rule->sigid);
384                 add_idmef_object(idmef, "alert.classification.reference(-1).name", _prelude_data);
385
386                 add_idmef_object(idmef, "alert.classification.reference(-1).meaning", last_info_detail->data);
387
388             } else {
389                 switch (last_info_detail->type) {
390                     case RULEINFODETAIL_CVE:
391                         origin = "cve";
392                         break;
393                     case RULEINFODETAIL_OSVDB:
394                         origin = "osvdb";
395                         break;
396                     case RULEINFODETAIL_BUGTRACK:
397                         origin = "bugtraqid";
398                         break;
399                     default:
400                         origin = "vendor-specific";
401                         break;
402                 }
403                 add_idmef_object(idmef, "alert.classification.reference(>>).origin", origin);
404                 add_idmef_object(idmef, "alert.classification.reference(-1).name", last_info_detail->data);
405             }
406         }
407
408         /* Break up the list of groups on the "," boundary
409          * For each section create a prelude reference classification
410          * that points back to the the OSSEC wiki for more infomation.
411          */
412         if (lf->generated_rule->group) {
413             char *copy_group;
414             char new_generated_rule_group[256];
415             new_generated_rule_group[255] = '\0';
416             strncpy(new_generated_rule_group, lf->generated_rule->group, 255);
417             copy_group = strtok(new_generated_rule_group, ",");
418             while (copy_group) {
419                 add_idmef_object(idmef, "alert.classification.reference(>>).origin", "vendor-specific");
420
421                 snprintf(_prelude_data, 256, "Group:%s", copy_group);
422                 add_idmef_object(idmef, "alert.classification.reference(-1).name", _prelude_data);
423
424                 add_idmef_object(idmef, "alert.classification.reference(-1).meaning", "OSSEC Group Wiki Documentation");
425
426                 snprintf(_prelude_data, 256, "http://www.ossec.net/wiki/Group:%s",
427                          copy_group);
428                 add_idmef_object(idmef, "alert.classification.reference(-1).url", _prelude_data);
429
430                 copy_group = strtok(NULL, ",");
431             }
432         }
433     } /* end classification block */
434
435     /* Begin Node infomation block */
436     {
437         /* Set source info */
438         add_idmef_object(idmef, "alert.source(0).spoofed", "no");
439         add_idmef_object(idmef, "alert.source(0).node.address(0).address",
440                          lf->srcip);
441         add_idmef_object(idmef, "alert.source(0).service.port", lf->srcport);
442
443         if (lf->srcuser) {
444             add_idmef_object(idmef, "alert.source(0).user.user_id(0).name", lf->srcuser);
445         }
446
447         /* Set target */
448         add_idmef_object(idmef, "alert.target(0).service.name", lf->program_name);
449         add_idmef_object(idmef, "alert.target(0).spoofed", "no");
450
451         if (lf->dstip) {
452             add_idmef_object(idmef, "alert.target(0).node.address(0).address",
453                              lf->dstip);
454         } else {
455             char *tmp_str;
456             char new_prelude_target[256];
457
458             new_prelude_target[255] = '\0';
459             strncpy(new_prelude_target, lf->hostname, 255);
460
461             /* The messages can have the file, so we need to remove it
462              * Formats can be:
463              *   enigma->/var/log/authlog
464              *   (esqueleto2) 192.168.2.99->/var/log/squid/access.log
465              */
466             tmp_str = strstr(new_prelude_target, "->");
467             if (tmp_str) {
468                 *tmp_str = '\0';
469             }
470             add_idmef_object(idmef, "alert.target(0).node.address(0).address",
471                              new_prelude_target);
472         }
473         add_idmef_object(idmef, "alert.target(0).service.name", lf->hostname);
474         add_idmef_object(idmef, "alert.target(0).service.port", lf->dstport);
475
476         if (lf->dstuser) {
477             add_idmef_object(idmef, "alert.target(0).user.category", "2");
478             add_idmef_object(idmef, "alert.target(0).user.user_id(0).name", lf->dstuser);
479         }
480     } /* end Node infomation block */
481
482     /* Set source file */
483     add_idmef_object(idmef, "alert.additional_data(0).type", "string");
484     add_idmef_object(idmef, "alert.additional_data(0).meaning", "Source file");
485     add_idmef_object(idmef, "alert.additional_data(0).data", lf->location);
486
487     /* Set full log */
488     add_idmef_object(idmef, "alert.additional_data(1).type", "string");
489     add_idmef_object(idmef, "alert.additional_data(1).meaning", "Full Log");
490     add_idmef_object(idmef, "alert.additional_data(1).data", lf->full_log);
491
492     idmef_alert_set_analyzer(idmef_message_get_alert(idmef),
493                              idmef_analyzer_ref
494                              (prelude_client_get_analyzer(prelude_client)),
495                              IDMEF_LIST_PREPEND);
496     debug1("%s: DEBUG: lf->filename = %s.", ARGV0, lf->filename);
497     if (lf->filename) {
498         FileAccess_PreludeLog(idmef,
499                               "original",
500                               lf->filename,
501                               lf->md5_before,
502                               lf->sha1_before,
503                               lf->owner_before,
504                               lf->gowner_before,
505                               lf->perm_before);
506         FileAccess_PreludeLog(idmef,
507                               "current",
508                               lf->filename,
509                               lf->md5_after,
510                               lf->sha1_after,
511                               lf->owner_after,
512                               lf->gowner_after,
513                               lf->perm_after);
514         debug1("%s: DEBUG: done with alert.target(0).file(1)", ARGV0);
515     }
516
517     debug1("%s: DEBUG: Sending IDMEF alert", ARGV0);
518     prelude_client_send_idmef(prelude_client, idmef);
519     debug1("%s: DEBUG: destroying IDMEF alert", ARGV0);
520     idmef_message_destroy(idmef);
521 }
522
523 #endif /* PRELUDE_OUTPUT_ENABLED */
524