2
** Copyright (C) 2009-2011 Softwink, Inc.
3
** Copyright (C) 2009-2011 Champ Clark III <champ@softwink.com>
5
** This program is free software; you can redistribute it and/or modify
6
** it under the terms of the GNU General Public License Version 2 as
7
** published by the Free Software Foundation. You may not use, modify or
8
** distribute this program under any other version of the GNU General
11
** This program is distributed in the hope that it will be useful,
12
** but WITHOUT ANY WARRANTY; without even the implied warranty of
13
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
** GNU General Public License for more details.
16
** You should have received a copy of the GNU General Public License
17
** along with this program; if not, write to the Free Software
18
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
* Threaded output for the Prelude framework. For more information about
24
* Prelude, please see: http://www.prelude-technologies.com
26
* Some of this code is based off Snort's Prelude output plug in
27
* (spo_alert_prelude.c).
33
#include "config.h" /* From autoconf */
36
#ifdef HAVE_LIBPRELUDE
40
#include <libprelude/prelude.h>
46
#include "sagan-prelude.h"
48
struct _SaganConfig *config;
49
struct _SaganCounters *counters;
51
#define ANALYZER_CLASS "Log Analyzer"
52
#define ANALYZER_MODEL "Sagan"
53
#define ANALYZER_MANUFACTURER "http://sagan.softwink.com"
54
#define ANALYZER_SID_URL "https://wiki.softwink.com/bin/view/Main/"
55
#define DEFAULT_ANALYZER_NAME "sagan"
56
#define ANALYZER_INTERFACE "syslog"
58
prelude_client_t *preludeclient;
60
struct rule_struct *rulestruct;
62
/* Init the Prelude sub system. */
64
void PreludeInit(void)
69
prelude_client_flags_t flags;
71
ret = prelude_thread_init(NULL);
75
sagan_log(1, "[%s, line %d] %s: Unable to init the Prelude thread subsystem: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
78
ret = prelude_init(NULL, NULL);
81
sagan_log(1, "[%s, line %d] %s: Unable to init the Prelude library: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
84
ret = prelude_client_new(&preludeclient, config->sagan_prelude_profile ? config->sagan_prelude_profile : DEFAULT_ANALYZER_NAME);
88
sagan_log(1, "[%s, line %d] %s: Unable to create a Prelude client object: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
91
flags = PRELUDE_CLIENT_FLAGS_ASYNC_SEND|PRELUDE_CLIENT_FLAGS_ASYNC_TIMER;
92
ret = prelude_client_set_flags(preludeclient, prelude_client_get_flags(preludeclient) | flags);
96
sagan_log(1, "[%s, line %d] %s: Unable to set asynchronous send and timer: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
99
setup_analyzer(prelude_client_get_analyzer(preludeclient));
101
ret = prelude_client_start(preludeclient);
104
sagan_log(1, "[%s, line %d] %s: Unable to initialize Prelude client: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
110
/* Setup's up the Prelude analyzer. This is information like model,
113
int setup_analyzer(idmef_analyzer_t *analyzer)
116
prelude_string_t *string;
118
ret = idmef_analyzer_new_model(analyzer, &string);
121
prelude_string_set_constant(string, ANALYZER_MODEL);
123
ret = idmef_analyzer_new_class(analyzer, &string);
126
prelude_string_set_constant(string, ANALYZER_CLASS);
128
ret = idmef_analyzer_new_manufacturer(analyzer, &string);
131
prelude_string_set_constant(string, ANALYZER_MANUFACTURER);
133
ret = idmef_analyzer_new_version(analyzer, &string);
136
prelude_string_set_constant(string, VERSION);
142
int add_int_data(idmef_alert_t *alert, const char *meaning, uint32_t data)
145
prelude_string_t *str;
146
idmef_additional_data_t *ad;
148
ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND);
152
idmef_additional_data_set_integer(ad, data);
154
ret = idmef_additional_data_new_meaning(ad, &str);
156
sagan_log(0,"%s: error creating additional-data meaning: %s.\n",
157
prelude_strsource(ret), prelude_strerror(ret));
161
ret = prelude_string_set_ref(str, meaning);
163
sagan_log(0, "%s: error setting integer data meaning: %s.\n",
164
prelude_strsource(ret), prelude_strerror(ret));
172
/****************************************************************************/
173
/* sagan_prelude() - This is the sub/thread called from the main process */
174
/****************************************************************************/
176
void sagan_prelude( SaganEvent *Event )
179
pthread_mutex_t prelude_mutex = PTHREAD_MUTEX_INITIALIZER;
186
idmef_message_t *idmef;
187
idmef_alert_t *alert;
188
idmef_classification_t *class;
189
prelude_string_t *str;
191
/* IDMEF message init */
193
ret = idmef_message_new(&idmef);
195
prelude_client_destroy(preludeclient, PRELUDE_CLIENT_EXIT_STATUS_FAILURE);
196
sagan_log(1, "[%s, line %d] Error in idmef_message_new(). Aborting", __FILE__, __LINE__);
199
ret = idmef_message_new_alert(idmef, &alert);
201
sagan_log(0, "[%s, line %d] Error in idmef_message_new_alert()", __FILE__, __LINE__);
205
ret = idmef_alert_new_classification(alert, &class);
207
sagan_log(0, "[%s, line %d] Error in idmef_alert_new_classification()", __FILE__, __LINE__);
210
ret = idmef_classification_new_text(class, &str);
212
sagan_log(0, "[%s, line %d] Error in idmef_classification_new_text()", __FILE__, __LINE__);
216
prelude_string_set_ref(str, rulestruct[Event->found].s_msg );
218
ret = event_to_impact(rulestruct[Event->found].s_pri, alert);
220
sagan_log(0, "[%s, line %d] event_to_impact() failed", __FILE__, __LINE__);
224
ret = event_to_reference(rulestruct[Event->found].s_sid, class);
226
sagan_log(0, "[%s, line %d] event_to_reference() failed", __FILE__, __LINE__);
230
ret = event_to_source_target(Event->ip_src, Event->ip_dst, Event->src_port, Event->dst_port, rulestruct[Event->found].ip_proto, alert);
232
sagan_log(0, "[%s, line %d] event_to_source_target() failed", __FILE__, __LINE__);
236
sid = atoi(rulestruct[Event->found].s_sid);
237
rev = atoi(rulestruct[Event->found].s_rev);
239
ret = syslog_to_data(rulestruct[Event->found].s_sid, rulestruct[Event->found].s_rev, rulestruct[Event->found].ip_proto, Event->message, alert);
241
sagan_log(0, "[%s, line %d] syslog_to_data() failed", __FILE__, __LINE__);
245
prelude_client_send_idmef(preludeclient, idmef);
248
idmef_message_destroy(idmef);
250
pthread_mutex_lock ( &prelude_mutex );
251
counters->threadpreludec--;
252
pthread_mutex_unlock ( &prelude_mutex );
257
/* Assigns severity to an event. For example, priority 1 == High */
259
int event_to_impact(int pri, idmef_alert_t *alert)
263
idmef_impact_t *impact;
264
idmef_impact_severity_t severity;
265
idmef_assessment_t *assessment;
267
ret = idmef_alert_new_assessment(alert, &assessment);
268
if ( ret < 0 ) sagan_log(1, "[%s, line %d] Error in idmef_alert_new_assessment(). Abort.", __FILE__, __LINE__);
270
ret = idmef_assessment_new_impact(assessment, &impact);
271
if ( ret < 0 ) sagan_log(1,"[%s, line %d] Error in idmef_assessment_new_impact(). Abort.", __FILE__, __LINE__);
273
if ( pri == 1 ) severity = IDMEF_IMPACT_SEVERITY_HIGH;
274
else if ( pri == 2 ) severity = IDMEF_IMPACT_SEVERITY_MEDIUM;
275
else if ( pri == 3 ) severity = IDMEF_IMPACT_SEVERITY_LOW;
276
else severity = IDMEF_IMPACT_SEVERITY_INFO;
278
idmef_impact_set_severity(impact, severity);
284
int event_to_reference(char *sid , idmef_classification_t *class)
287
prelude_string_t *str;
289
ret = idmef_classification_new_ident(class, &str);
290
if ( ret < 0 ) return ret;
292
ret = prelude_string_sprintf(str, "%s", sid);
293
if ( ret < 0 ) return ret;
295
ret = add_sagan_reference(class, sid);
300
/* Supply target/source/port information */
302
int event_to_source_target(char *ip_src, char *ip_dst, int src_port, int dst_port, int proto, idmef_alert_t *alert)
306
idmef_source_t *source;
307
idmef_service_t *service;
308
prelude_string_t *string;
310
idmef_address_t *address;
311
idmef_target_t *target;
314
ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND);
315
if ( ret < 0 ) return ret;
317
ret = idmef_source_new_interface(source, &string);
318
if ( ret < 0 ) return ret;
320
prelude_string_set_ref(string, config->sagan_interface);
322
ret = idmef_source_new_service(source, &service);
323
if ( ret < 0 ) return ret;
325
idmef_service_set_port(service, src_port );
326
if ( ret < 0 ) return ret;
328
idmef_service_set_ip_version(service, 4);
329
idmef_service_set_iana_protocol_number(service, proto);
331
ret = idmef_source_new_node(source, &node);
332
if ( ret < 0 ) return ret;
334
ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND);
335
if ( ret < 0 ) return ret;
337
ret = idmef_address_new_address(address, &string);
338
if ( ret < 0 ) return ret;
340
prelude_string_set_ref(string, ip_src);
342
ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND);
343
if ( ret < 0 ) return ret;
345
ret = idmef_target_new_interface(target, &string);
346
if ( ret < 0 ) return ret;
348
ret = idmef_target_new_service(target, &service);
349
if ( ret < 0 ) return ret;
352
idmef_service_set_port(service, dst_port);
353
if ( ret < 0 ) return ret;
355
idmef_service_set_ip_version(service, 4);
356
idmef_service_set_iana_protocol_number(service, proto );
358
ret = idmef_target_new_node(target, &node);
359
if ( ret < 0 ) return ret;
361
ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND);
362
if ( ret < 0 ) return ret;
364
ret = idmef_address_new_address(address, &string);
365
if ( ret < 0 ) return ret;
367
prelude_string_set_ref(string, ip_dst);
372
int syslog_to_data ( char *sid, char *rev, int proto, char *message, idmef_alert_t *alert )
378
add_int_data(alert, "sagan_rule_sid", i);
380
add_int_data(alert, "sagan_rule_rev", i );
382
add_int_data(alert, "ip_ver", 4);
384
add_int_data(alert, "ip_proto", proto);
387
add_byte_data(alert, "payload", message, strlen(message));
393
/* Setup for the payload information */
395
int add_byte_data(idmef_alert_t *alert, const char *meaning, const unsigned char *data, size_t size)
399
prelude_string_t *str;
400
idmef_additional_data_t *ad;
402
ret = idmef_alert_new_additional_data(alert, &ad, IDMEF_LIST_APPEND);
403
if ( ret < 0 ) return ret;
405
ret = idmef_additional_data_set_byte_string_ref(ad, data, size);
407
sagan_log(0, "[%s, line %d] %s Error setting byte string data: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
411
ret = idmef_additional_data_new_meaning(ad, &str);
413
sagan_log(0, "[%s, line %d] %s Error creating additional-data meaning: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
417
ret = prelude_string_set_ref(str, meaning);
419
sagan_log(0, "[%s, line %d] %s Error setting byte string data meaning: %s", __FILE__, __LINE__, prelude_strsource(ret), prelude_strerror(ret));
426
int add_sagan_reference(idmef_classification_t *class, char *sid)
431
prelude_string_t *str;
432
idmef_reference_t *ref;
438
ret = idmef_classification_new_reference(class, &ref, IDMEF_LIST_APPEND);
439
if ( ret < 0 ) return ret;
441
ret = idmef_reference_new_name(ref, &str);
442
if ( ret < 0 ) return ret;
444
idmef_reference_set_origin(ref, IDMEF_REFERENCE_ORIGIN_VENDOR_SPECIFIC);
445
ret = prelude_string_sprintf(str, "%s", sid);
446
if ( ret < 0 ) return ret;
448
ret = idmef_reference_new_meaning(ref, &str);
449
if ( ret < 0 ) return ret;
451
ret = prelude_string_sprintf(str, "Sagan Signature ID");
452
if ( ret < 0 ) return ret;
454
ret = idmef_reference_new_url(ref, &str);
455
if ( ret < 0 ) return ret;
457
ret = prelude_string_sprintf(str, ANALYZER_SID_URL "%s", sid);