From df5afa4fcd9725380f94ca6476248d4cc24f889a Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Sun, 29 Nov 2015 08:22:13 -0800 Subject: v2.4.4 audit sources Change-Id: I9315a7408817db51edf084fb4d27fbb492785084 Signed-off-by: Ashlee Young --- .../audit/audisp/plugins/prelude/audisp-prelude.c | 2250 ++++++++++++++++++++ 1 file changed, 2250 insertions(+) create mode 100644 framework/src/audit/audisp/plugins/prelude/audisp-prelude.c (limited to 'framework/src/audit/audisp/plugins/prelude/audisp-prelude.c') diff --git a/framework/src/audit/audisp/plugins/prelude/audisp-prelude.c b/framework/src/audit/audisp/plugins/prelude/audisp-prelude.c new file mode 100644 index 00000000..f3dc65a0 --- /dev/null +++ b/framework/src/audit/audisp/plugins/prelude/audisp-prelude.c @@ -0,0 +1,2250 @@ +/* audisp-prelude.c -- + * Copyright 2008-09,2011-12 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Steve Grubb + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBCAP_NG +#include +#endif +#include "libaudit.h" +#include "auparse.h" +#include "prelude-config.h" + +#define CONFIG_FILE "/etc/audisp/audisp-prelude.conf" +#define ANALYZER_MODEL "auditd" +#define ANALYZER_CLASS "HIDS" +#define ANALYZER_MANUFACTURER "Red Hat, http://people.redhat.com/sgrubb/audit/" +#define PRELUDE_FAIL_CHECK if (ret < 0) goto err; + +typedef enum { AS_LOGIN, AS_MAX_LOGIN_FAIL, AS_MAX_LOGIN_SESS, AS_ABEND, + AS_PROM, AS_MAC_STAT, AS_LOGIN_LOCATION, AS_LOGIN_TIME, AS_MAC, + AS_AUTH, AS_WATCHED_LOGIN, AS_WATCHED_FILE, AS_WATCHED_EXEC, AS_MK_EXE, + AS_MMAP0, AS_WATCHED_SYSCALL, AS_TTY, AS_TOTAL } as_description_t; +const char *assessment_description[AS_TOTAL] = { + "A user has attempted to login", + "The maximum allowed login failures for this account has been reached. This could be an attempt to gain access to the account by someone other than the real account holder.", + "The maximum allowed concurrent logins for this account has been reached.", + "An application terminated abnormally. An attacker may be trying to exploit a weakness in the program.", + "A program has opened or closed a promiscuous socket. If this is not expected, it could be an attacker trying to sniff traffic.", + "A program has changed SE Linux policy enforcement. If this is not expected, it could be an attempt to subvert the system.", + "A user attempted to login from a location that is not allowed. This could be an attempt to gain access to the account by someone other than the real account holder.", + "A user attempted to login during a time that the user should not be logging into the system. This could be an attempt to gain access to the account by someone other than the real account holder.", + "A program has tried to access something that is not allowed in the MAC policy. This could indicate an attacker trying to exploit a weakness in the program.", + "A user has attempted to use an authentication mechanism and failed. This could be an attempt to gain privileges that they are not supposed to have.", + "A user has logged in to an account that is being watched.", + "A user has attempted to access a file that is being watched.", + "A user has attempted to execute a program that is being watched.", + "A user has attempted to create an executable program", + "A program has attempted mmap a fixed memory page at an address sometimes used as part of a kernel exploit", + "A user has run a command that issued a watched syscall", + "A user has typed keystrokes on a terminal" +}; +typedef enum { M_NORMAL, M_TEST } output_t; +typedef enum { W_NO, W_FILE, W_EXEC, W_MK_EXE } watched_t; + +/* Global Data */ +static volatile int stop = 0; +static volatile int hup = 0; +static prelude_client_t *client = NULL; +static auparse_state_t *au = NULL; +static prelude_conf_t config; +static output_t mode = M_NORMAL; +static char *myhostname=NULL; + +/* Local declarations */ +static void handle_event(auparse_state_t *au, + auparse_cb_event_t cb_event_type, void *user_data); + +/* + * SIGTERM handler + */ +static void term_handler( int sig ) +{ + stop = 1; +} + +/* + * SIGHUP handler: re-read config + */ +static void hup_handler( int sig ) +{ + hup = 1; +} + +static void reload_config(void) +{ + hup = 0; +} + +static int setup_analyzer(idmef_analyzer_t *analyzer) +{ + int ret; + prelude_string_t *string; + + ret = idmef_analyzer_new_model(analyzer, &string); + PRELUDE_FAIL_CHECK; + prelude_string_set_dup(string, ANALYZER_MODEL); + + ret = idmef_analyzer_new_class(analyzer, &string); + PRELUDE_FAIL_CHECK; + prelude_string_set_dup(string, ANALYZER_CLASS); + + ret = idmef_analyzer_new_manufacturer(analyzer, &string); + PRELUDE_FAIL_CHECK; + prelude_string_set_dup(string, ANALYZER_MANUFACTURER); + + ret = idmef_analyzer_new_version(analyzer, &string); + PRELUDE_FAIL_CHECK; + prelude_string_set_dup(string, PACKAGE_VERSION); + + return 0; + + err: + syslog(LOG_ERR, "%s: IDMEF error: %s.\n", + prelude_strsource(ret), prelude_strerror(ret)); + + return -1; +} + +static int init_prelude(int argc, char *argv[]) +{ + int ret; + prelude_client_flags_t flags; + + ret = prelude_thread_init(NULL); + ret = prelude_init(&argc, argv); + if (ret < 0) { + syslog(LOG_ERR, + "Unable to initialize the Prelude library: %s.\n", + prelude_strerror(ret)); + return -1; + } + ret = prelude_client_new(&client, + config.profile ? config.profile : ANALYZER_MODEL); + if (! client) { + syslog(LOG_ERR, + "Unable to create a prelude client object: %s.\n", + prelude_strerror(ret)); + return -1; + } + ret = setup_analyzer(prelude_client_get_analyzer(client)); + if (ret < 0) { + syslog(LOG_ERR, "Unable to setup analyzer: %s\n", + prelude_strerror(ret)); + + prelude_client_destroy(client, + PRELUDE_CLIENT_EXIT_STATUS_FAILURE); + prelude_deinit(); + return -1; + } + if (mode == M_NORMAL) { + flags = prelude_client_get_flags(client); + flags |= PRELUDE_CLIENT_FLAGS_ASYNC_TIMER; + } else + flags = 0; // Debug mode + ret = prelude_client_set_flags(client, flags); + if (ret < 0) { + syslog(LOG_ERR, "Unable to set prelude client flags: %s\n", + prelude_strerror(ret)); + + prelude_client_destroy(client, + PRELUDE_CLIENT_EXIT_STATUS_FAILURE); + prelude_deinit(); + return -1; + } + ret = prelude_client_start(client); + if (ret < 0) { + syslog(LOG_ERR, "Unable to start prelude client: %s\n", + prelude_strerror(ret)); + + prelude_client_destroy(client, + PRELUDE_CLIENT_EXIT_STATUS_FAILURE); + prelude_deinit(); + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; + struct sigaction sa; + + if (argc > 1) { + if (argc == 2 && strcmp(argv[1], "--test") == 0) { + mode = M_TEST; + } else { + fprintf(stderr, "Usage: audisp-prelude [--test]\n"); + return 1; + } + } + + /* Register sighandlers */ + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + /* Set handler for the ones we care about */ + sa.sa_handler = term_handler; + sigaction(SIGTERM, &sa, NULL); + sa.sa_handler = hup_handler; + sigaction(SIGHUP, &sa, NULL); + if (load_config(&config, CONFIG_FILE)) { + if (mode == M_TEST) + puts("audisp-prelude is exiting on config load error"); + return 6; + } + + /* Initialize the auparse library */ + au = auparse_init(AUSOURCE_FEED, 0); + if (au == NULL) { + syslog(LOG_ERR, + "audisp-prelude is exiting due to auparse init errors"); + free_config(&config); + return -1; + } + auparse_add_callback(au, handle_event, NULL, NULL); + if (init_prelude(argc, argv)) { + if (mode == M_TEST) + puts("audisp-prelude is exiting due to init_prelude"); + else + syslog(LOG_ERR, + "audisp-prelude is exiting due to init_prelude failure"); + free_config(&config); + auparse_destroy(au); + return -1; + } +#ifdef HAVE_LIBCAP_NG + // Drop all capabilities + capng_clear(CAPNG_SELECT_BOTH); + capng_apply(CAPNG_SELECT_BOTH); +#endif + if (mode != M_TEST) + syslog(LOG_INFO, "audisp-prelude is ready for events"); + do { + fd_set read_mask; + struct timeval tv; + int retval; + + /* Load configuration */ + if (hup) { + reload_config(); + } + do { + tv.tv_sec = 5; + tv.tv_usec = 0; + FD_ZERO(&read_mask); + FD_SET(0, &read_mask); + if (auparse_feed_has_data(au)) + retval= select(1, &read_mask, NULL, NULL, &tv); + else + retval= select(1, &read_mask, NULL, NULL, NULL); } while (retval == -1 && errno == EINTR && !hup && !stop); + + /* Now the event loop */ + if (!stop && !hup && retval > 0) { + if (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH, + stdin)){ + auparse_feed(au, tmp, strnlen(tmp, + MAX_AUDIT_MESSAGE_LENGTH)); + } + } else if (retval == 0) + auparse_flush_feed(au); + if (feof(stdin)) + break; + } while (stop == 0); + + /* Flush any accumulated events from queue */ + auparse_flush_feed(au); + + if (stop) { + if (mode == M_TEST) + puts("audisp-prelude is exiting on stop request"); + else + syslog(LOG_INFO, + "audisp-prelude is exiting on stop request"); + } else { + if (mode == M_TEST) + puts("audisp-prelude is exiting due to end of file"); + else + syslog(LOG_INFO, + "audisp-prelude is exiting due to losing input source"); + } + + /* Cleanup subsystems */ + if (client) + prelude_client_destroy(client, + PRELUDE_CLIENT_EXIT_STATUS_SUCCESS); + prelude_deinit(); + auparse_destroy(au); + free_config(&config); + free(myhostname); + + return 0; +} + +static void print_test_message(idmef_message_t *idmef) +{ + int ret; + prelude_io_t *fd; + + ret = prelude_io_new(&fd); + if ( ret < 0 ) + return; + + prelude_io_set_file_io(fd, stdout); + idmef_message_print(idmef, fd); + + prelude_io_destroy(fd); +} + +static void send_idmef(prelude_client_t *client, idmef_message_t *idmef) +{ + if (mode == M_TEST) + print_test_message(idmef); + else + prelude_client_send_idmef(client, idmef); +} + +static int new_alert_common(auparse_state_t *au, idmef_message_t **idmef, + idmef_alert_t **alert) +{ + int ret; + idmef_time_t *dtime, *ctime; + time_t au_time; + + ret = idmef_message_new(idmef); + PRELUDE_FAIL_CHECK; + + ret = idmef_message_new_alert(*idmef, alert); + PRELUDE_FAIL_CHECK; + + idmef_alert_set_analyzer(*alert, + idmef_analyzer_ref(prelude_client_get_analyzer(client)), + IDMEF_LIST_PREPEND); + + // Put the audit time and message ID in the event + au_time = auparse_get_time(au); + ret = idmef_time_new_from_time(&dtime, &au_time); + PRELUDE_FAIL_CHECK; + idmef_alert_set_detect_time(*alert, dtime); + + // Set time this was created + ret = idmef_time_new_from_gettimeofday(&ctime); + PRELUDE_FAIL_CHECK; + idmef_alert_set_create_time(*alert, ctime); + + return 0; + err: + syslog(LOG_ERR, "%s: IDMEF error: %s.\n", + prelude_strsource(ret), prelude_strerror(ret)); + idmef_message_destroy(*idmef); + return -1; +} + +static int get_loginuid(auparse_state_t *au) +{ + int uid; + const char *auid; + + auparse_first_field(au); + auid = auparse_find_field(au, "auid"); + if (auid) + uid = auparse_get_field_int(au); + else + uid = -1; + return uid; +} + +static int get_new_gid(auparse_state_t *au) +{ + int gid; + const char *ngid; + + auparse_first_field(au); + ngid = auparse_find_field(au, "new_gid"); + if (ngid) + gid = auparse_get_field_int(au); + else + gid = -1; + return gid; +} + +/* + * This function seeks to the specified record returning its type on succees + */ +static int goto_record_type(auparse_state_t *au, int type) +{ + int cur_type; + + auparse_first_record(au); + do { + cur_type = auparse_get_type(au); + if (cur_type == type) { + auparse_first_field(au); + return type; // Normal exit + } + } while (auparse_next_record(au) > 0); + + return -1; +} + +static int get_loginuid_info(auparse_state_t *au, idmef_user_id_t *user_id) +{ + int ret, type, is_num = 0; + const char *auid; + + type = auparse_get_type(au); + auparse_first_field(au); + auid = auparse_find_field(au, "acct"); + if (auid == NULL) { + is_num = 1; + goto_record_type(au, type); + auid = auparse_find_field(au, "sauid"); + if (auid == NULL) { + goto_record_type(au, type); + if (type == AUDIT_USER_LOGIN) { + // login programs write auid at second uid + auparse_find_field(au, "uid"); + auparse_next_field(au); + auid = auparse_find_field(au, "uid"); + } else { + auid = auparse_find_field(au, "auid"); + } + } + } + if (auid) { + prelude_string_t *str; + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + if (is_num) { + int uid = auparse_get_field_int(au); + idmef_user_id_set_number(user_id, uid); + } else { + struct passwd *pw; + pw = getpwnam(auid); + if (pw) + idmef_user_id_set_number(user_id, pw->pw_uid); + } + + auid = auparse_interpret_field(au); + ret = prelude_string_set_ref(str, auid); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_name(user_id, str); + } + return 0; + + err: + return -1; +} + +static int get_tty_info(auparse_state_t *au, idmef_user_id_t *user_id) +{ + int ret, type; + const char *tty; + + type = auparse_get_type(au); + auparse_first_field(au); + tty = auparse_find_field(au, "terminal"); + if (tty == NULL) { + goto_record_type(au, type); + tty = auparse_find_field(au, "tty"); + } + if (tty) { + prelude_string_t *str; + + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + ret = prelude_string_set_ref(str, tty); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_tty(user_id, str); + } + return 0; + err: + return -1; +} + +static int is_ipv4(const char *addr) +{ + int i = 0; + while (addr[i]) { + if ((addr[i] != '.') && !isdigit(addr[i])) + return 0; + i++; + } + return 1; +} + +static int is_ipv6(const char *addr) +{ + int i = 0; + while (addr[i]) { + if ((addr[i] != '.') && addr[i] != ':' && !isdigit(addr[i])) + return 0; + i++; + } + return 1; +} + +static int fill_in_node(idmef_node_t *node, const char *addr) +{ + int ret; + prelude_string_t *str; + + /* Setup the address string */ + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_ref(str, addr); + PRELUDE_FAIL_CHECK; + + /* Now figure out the kind of address */ + if (is_ipv4(addr)) { + idmef_address_t *my_addr; + ret = idmef_address_new(&my_addr); + PRELUDE_FAIL_CHECK; + idmef_address_set_category(my_addr, + IDMEF_ADDRESS_CATEGORY_IPV4_ADDR); + idmef_address_set_address(my_addr, str); + idmef_node_set_address(node, my_addr, 0); + } else if (is_ipv6(addr)){ + idmef_address_t *my_addr; + ret = idmef_address_new(&my_addr); + PRELUDE_FAIL_CHECK; + idmef_address_set_category(my_addr, + IDMEF_ADDRESS_CATEGORY_IPV6_ADDR); + idmef_address_set_address(my_addr, str); + idmef_node_set_address(node, my_addr, 0); + } else { /* Just a host name */ + idmef_node_set_name(node, str); + } + + return 0; + err: + return -1; +} + +static int get_rhost_info(auparse_state_t *au, idmef_source_t *source) +{ + int ret; + idmef_node_t *node; + const char *hostname; + + auparse_first_field(au); + hostname = auparse_find_field(au, "hostname"); + if (hostname) { + if (strcmp(hostname, "?") == 0) { + auparse_next_field(au); + hostname = auparse_get_field_str(au); + } + } else { /* Some AVCs have the remote addr */ + auparse_first_field(au); + hostname = auparse_find_field(au, "laddr"); + } + + if (hostname) { + ret = idmef_source_new_node(source, &node); + PRELUDE_FAIL_CHECK; + idmef_node_set_category(node, IDMEF_NODE_CATEGORY_UNKNOWN); + + ret = fill_in_node(node, hostname); + PRELUDE_FAIL_CHECK; + } + + return 0; + err: + return -1; +} + +static int do_node_common(auparse_state_t *au, idmef_node_t *node) +{ + int ret; + const char *name; + + auparse_first_field(au); + name = auparse_find_field(au, "node"); + if (name == NULL) { + if (myhostname == NULL) { + char tmp_name[255]; + if (gethostname(tmp_name, sizeof(tmp_name)) == 0) + myhostname = strdup(tmp_name); + } + name = myhostname; + idmef_node_set_category(node, IDMEF_NODE_CATEGORY_HOSTS); + } else + idmef_node_set_category(node, IDMEF_NODE_CATEGORY_UNKNOWN); + + if (name) { + ret = fill_in_node(node, name); + PRELUDE_FAIL_CHECK; + } else + goto err; + + return 0; + err: + return -1; +} + +static int get_node_info(auparse_state_t *au, idmef_source_t *source, + idmef_target_t *target) +{ + int ret; + idmef_node_t *node; + + if (source) { + ret = idmef_source_new_node(source, &node); + PRELUDE_FAIL_CHECK; + + ret = do_node_common(au, node); + PRELUDE_FAIL_CHECK; + } + + if (target) { + ret = idmef_target_new_node(target, &node); + PRELUDE_FAIL_CHECK; + + ret = do_node_common(au, node); + PRELUDE_FAIL_CHECK; + } + + return 0; + err: + return -1; +} + +static int get_login_exe_info(auparse_state_t *au, idmef_target_t *target) +{ + int ret, type; + idmef_process_t *process; + const char *exe, *pid; + + ret = idmef_target_new_process(target, &process); + PRELUDE_FAIL_CHECK; + + type = auparse_get_type(au); + auparse_first_field(au); + pid = auparse_find_field(au, "pid"); + if (pid) + idmef_process_set_pid(process, auparse_get_field_int(au)); + + goto_record_type(au, type); + exe = auparse_find_field(au, "exe"); + if (exe) { + char *base; + prelude_string_t *str, *name_str; + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + exe = auparse_interpret_field(au); + ret = prelude_string_set_ref(str, exe); + PRELUDE_FAIL_CHECK; + idmef_process_set_path(process, str); + + /* Set process name, login events do not have comm fields */ + base = basename(exe); + ret = prelude_string_new(&name_str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_dup(name_str, base); + PRELUDE_FAIL_CHECK; + idmef_process_set_name(process, name_str); + } + + return 0; + err: + return -1; +} + +static int get_target_group_info(auparse_state_t *au, idmef_user_t *tuser) +{ + int ret; + const char *ngid; + + auparse_first_field(au); + ngid = auparse_find_field(au, "new_gid"); + if (ngid) { + int gid; + idmef_user_id_t *user_id; + prelude_string_t *str; + + ret = idmef_user_new_user_id(tuser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_GROUP_PRIVS); + + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + gid = auparse_get_field_int(au); + if (gid >= 0) + idmef_user_id_set_number(user_id, gid); + + ngid = auparse_interpret_field(au); + ret = prelude_string_set_ref(str, ngid); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_name(user_id, str); + } + + return 0; + err: + return -1; +} + +static int get_comm_info(auparse_state_t *au, idmef_source_t *source, + idmef_target_t *target) +{ + int ret, type, need_comm = 1; + idmef_process_t *process; + const char *exe, *pid; + + if (source) + ret = idmef_source_new_process(source, &process); + else if (target) + ret = idmef_target_new_process(target, &process); + else + return -1; + PRELUDE_FAIL_CHECK; + + type = auparse_get_type(au); + auparse_first_field(au); + pid = auparse_find_field(au, "pid"); + if (pid) + idmef_process_set_pid(process, auparse_get_field_int(au)); + + goto_record_type(au, type); + auparse_first_field(au); + exe = auparse_find_field(au, "comm"); + if (exe) { + prelude_string_t *str; + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + exe = auparse_interpret_field(au); + ret = prelude_string_set_ref(str, exe); + PRELUDE_FAIL_CHECK; + idmef_process_set_name(process, str); + need_comm = 0; + } + + goto_record_type(au, type); + exe = auparse_find_field(au, "exe"); + if (exe) { + prelude_string_t *str; + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + exe = auparse_interpret_field(au); + ret = prelude_string_set_ref(str, exe); + PRELUDE_FAIL_CHECK; + idmef_process_set_path(process, str); + + /* Set the process name if not set already */ + if (need_comm) { + prelude_string_t *name_str; + + char *base = basename(exe); + ret = prelude_string_new(&name_str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_dup(name_str, base); + idmef_process_set_name(process, name_str); + } + } + + return 0; + err: + return -1; +} + +/* + * Fill in a file record for idmef. Note that we always get the + * full path name unless we have an AVC. + */ +static int get_file_info(auparse_state_t *au, idmef_target_t *target, int full) +{ + int ret; + idmef_file_t *file; + const char *name; + char path[PATH_MAX+1]; + + ret = idmef_target_new_file(target, &file, 0); + PRELUDE_FAIL_CHECK; + + *path = 0; + if (full) { + const char *cwd; + auparse_first_field(au); + cwd = auparse_find_field(au, "cwd"); + if (cwd) { + if ((cwd = auparse_interpret_field(au))) + strcat(path, cwd); + } + // Loop across all PATH records in the event + goto_record_type(au, AUDIT_PATH); + name = NULL; + do { // Make sure that we have an actual file record + if (auparse_find_field(au, "mode")) { + int m = auparse_get_field_int(au); + if (S_ISREG(m)) { + // Now back up and get file name + auparse_first_field(au); + name = auparse_find_field(au, "name"); + break; + } + } + } while (auparse_next_record(au) > 0 && + auparse_get_type(au) == AUDIT_PATH); + } else { + // SE Linux AVC + int type = auparse_get_type(au); + auparse_first_field(au); + name = auparse_find_field(au, "path"); + if (name == NULL) { + goto_record_type(au, type); + name = auparse_find_field(au, "name"); + } + } + if (name) + name = auparse_interpret_field(au); + if (name) { + if (name[0] == '/') + strcpy(path, name); + else + strcat(path, name); + } + if (path[0] != 0) { + prelude_string_t *str; + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + + ret = prelude_string_set_dup(str, path); + PRELUDE_FAIL_CHECK; + if (path[0] == '/') { + char *base; + prelude_string_t *name_str; + + idmef_file_set_path(file, str); + base = basename(path); + if (base[0] == 0) + base = "/"; + ret = prelude_string_new(&name_str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_dup(name_str, base); + PRELUDE_FAIL_CHECK; + idmef_file_set_name(file, name_str); + } else + idmef_file_set_name(file, str); + } + idmef_file_set_category(file, IDMEF_FILE_CATEGORY_CURRENT); + + return 0; + err: + return -1; +} + +static int add_additional_data(idmef_alert_t *alert, const char *title, + const char *text) +{ + int ret; + idmef_additional_data_t *data; + prelude_string_t *str; + + ret = idmef_alert_new_additional_data(alert, &data, IDMEF_LIST_APPEND); + PRELUDE_FAIL_CHECK; + + ret = idmef_additional_data_new_meaning(data, &str); + PRELUDE_FAIL_CHECK; + + prelude_string_set_dup(str, title); + idmef_additional_data_set_type(data, IDMEF_ADDITIONAL_DATA_TYPE_STRING); + idmef_additional_data_set_string_ref(data, text); + return 0; + err: + return -1; +} + +static int add_serial_number_data(auparse_state_t *au, idmef_alert_t *alert) +{ + int ret; + idmef_additional_data_t *data; + prelude_string_t *str; + unsigned long serial; + char eid[24]; + + serial = auparse_get_serial(au); + snprintf(eid, sizeof(eid), "%lu", serial); + + ret = idmef_alert_new_additional_data(alert, &data, IDMEF_LIST_APPEND); + PRELUDE_FAIL_CHECK; + + ret = idmef_additional_data_new_meaning(data, &str); + PRELUDE_FAIL_CHECK; + + prelude_string_set_dup(str, "Audit event serial #"); + idmef_additional_data_set_type(data, IDMEF_ADDITIONAL_DATA_TYPE_STRING); + idmef_additional_data_set_string_dup(data, eid); + return 0; + err: + return -1; +} + +static int add_exit_data(auparse_state_t *au, idmef_alert_t *alert) +{ + const char *e_ptr; + + if (goto_record_type(au, AUDIT_SYSCALL) == -1) + goto err; + e_ptr = auparse_find_field(au, "exit"); + if (e_ptr) { + int ret; + idmef_additional_data_t *data; + prelude_string_t *str; + char exit_code[80]; + + snprintf(exit_code, sizeof(exit_code), "%d (%s)", + auparse_get_field_int(au), + auparse_interpret_field(au)); + + ret = idmef_alert_new_additional_data(alert, + &data, IDMEF_LIST_APPEND); + PRELUDE_FAIL_CHECK; + + ret = idmef_additional_data_new_meaning(data, &str); + PRELUDE_FAIL_CHECK; + + prelude_string_set_dup(str, "Audit syscall exit code:"); + idmef_additional_data_set_type(data, + IDMEF_ADDITIONAL_DATA_TYPE_STRING); + idmef_additional_data_set_string_dup(data, exit_code); + } + return 0; + err: + return -1; +} + +static int add_execve_data(auparse_state_t *au, idmef_alert_t *alert) +{ + int ret, i, len = 0; + idmef_additional_data_t *data; + prelude_string_t *str; + const char *msgptr; + char msg[256], var[16]; + + if (goto_record_type(au, AUDIT_EXECVE) != AUDIT_EXECVE) + return 0; + + msg[0] = 0; + for (i=0; i<8; i++) { + snprintf(var, sizeof(var), "a%d", i); + msgptr = auparse_find_field(au, var); + if (msgptr) { + char *ptr; + int len2; + len2 = asprintf(&ptr, "%s=%s ", var, + auparse_interpret_field(au)); + if (len2 < 0) { + ptr = NULL; + } else if (len2 > 0 && (len2 + len + 1) < sizeof(msg)) { + strcat(msg, ptr); + len += len2; + } + free(ptr); + } else + break; + } + + ret = idmef_alert_new_additional_data(alert, &data, IDMEF_LIST_APPEND); + PRELUDE_FAIL_CHECK; + + ret = idmef_additional_data_new_meaning(data, &str); + PRELUDE_FAIL_CHECK; + + prelude_string_set_dup(str, "Execve args"); + idmef_additional_data_set_type(data, IDMEF_ADDITIONAL_DATA_TYPE_STRING); + idmef_additional_data_set_string_dup(data, msg); + return 0; + err: + return -1; +} + +static int set_classification(idmef_alert_t *alert, const char *text) +{ + int ret; + idmef_classification_t *classification; + prelude_string_t *str; + + ret = idmef_alert_new_classification(alert, &classification); + PRELUDE_FAIL_CHECK; + ret = prelude_string_new(&str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_ref(str, text); + PRELUDE_FAIL_CHECK; + idmef_classification_set_text(classification, str); + + return 0; + err: + return -1; +} + +static int do_assessment(idmef_alert_t *alert, auparse_state_t *au, + idmef_impact_severity_t severity, idmef_impact_type_t type, + const char *descr) +{ + int ret; + idmef_assessment_t *assessment; + idmef_impact_t *impact; + idmef_impact_completion_t completion = IDMEF_IMPACT_COMPLETION_ERROR; + const char *result; + + auparse_first_record(au); + result = auparse_find_field(au, "res"); + if (result == NULL) { + auparse_first_record(au); + result = auparse_find_field(au, "success"); + } + if (result) { + if (strcmp(result, "yes") == 0) + completion = IDMEF_IMPACT_COMPLETION_SUCCEEDED; + else if (strcmp(result, "success") == 0) + completion = IDMEF_IMPACT_COMPLETION_SUCCEEDED; + else + completion = IDMEF_IMPACT_COMPLETION_FAILED; + } + + // Adjust the rating on AVC's based on if they succeeded or not + if (goto_record_type(au, AUDIT_AVC) == AUDIT_AVC) { + if (completion == IDMEF_IMPACT_COMPLETION_FAILED) + severity = IDMEF_IMPACT_SEVERITY_LOW; + } else if (goto_record_type(au, AUDIT_USER_AVC) == AUDIT_USER_AVC) { + if (completion == IDMEF_IMPACT_COMPLETION_FAILED) + severity = IDMEF_IMPACT_SEVERITY_LOW; + } + // If this is a segfault, they failed + if (goto_record_type(au, AUDIT_ANOM_ABEND) == AUDIT_ANOM_ABEND) + completion = IDMEF_IMPACT_COMPLETION_FAILED; + + ret = idmef_alert_new_assessment(alert, &assessment); + PRELUDE_FAIL_CHECK; + ret = idmef_assessment_new_impact(assessment, &impact); + PRELUDE_FAIL_CHECK; + idmef_impact_set_severity(impact, severity); + idmef_impact_set_type(impact, type); + if (descr) { + prelude_string_t *str; + ret = idmef_impact_new_description(impact, &str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_ref(str, descr); + PRELUDE_FAIL_CHECK; + } + + // FIXME: I think this is wrong. sb a way to express indeterminate + if (completion != IDMEF_IMPACT_COMPLETION_ERROR) + idmef_impact_set_completion(impact, completion); + + return 0; + err: + return -1; +} + +/* + * This is for login related alerts + */ +static int login_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert, const char *msg, + idmef_impact_severity_t severity, as_description_t num) +{ + int ret; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser, *tuser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_UNKNOWN); + + ret = get_rhost_info(au, source); + PRELUDE_FAIL_CHECK; + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + ret = idmef_target_new_user(target, &tuser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(tuser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(tuser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_TARGET_USER); + + auparse_first_record(au); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_login_exe_info(au, target); + PRELUDE_FAIL_CHECK; + + ret = get_node_info(au, NULL, target); + PRELUDE_FAIL_CHECK; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, msg); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + if (get_loginuid(au) == 0) + impact = IDMEF_IMPACT_TYPE_ADMIN; + else + impact = IDMEF_IMPACT_TYPE_USER; + ret = do_assessment(alert, au, severity, impact, + assessment_description[num]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "login_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for SE Linux AVC related alerts + */ +static int avc_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert) +{ + int ret, type; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact_type = IDMEF_IMPACT_TYPE_OTHER; + const char *seperm = NULL; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + if ((type = goto_record_type(au, AUDIT_SYSCALL)) == AUDIT_SYSCALL || + (type = goto_record_type(au, AUDIT_USER_AVC)) == AUDIT_USER_AVC) { + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, + IDMEF_USER_ID_TYPE_ORIGINAL_USER); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + ret = get_rhost_info(au, source); + PRELUDE_FAIL_CHECK; + } else if ((type = goto_record_type(au, AUDIT_AVC)) == AUDIT_AVC) { + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + } + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + + auparse_first_record(au); + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + type = goto_record_type(au, AUDIT_CWD); + if (type == AUDIT_CWD) { + ret = get_file_info(au, target, 1); + PRELUDE_FAIL_CHECK; + impact_type = IDMEF_IMPACT_TYPE_FILE; + } else if ((type = goto_record_type(au, AUDIT_AVC)) == AUDIT_AVC) { + seperm = auparse_find_field(au, "seperm"); + if (auparse_find_field(au, "path")) { + ret = get_file_info(au, target, 0); + impact_type = IDMEF_IMPACT_TYPE_FILE; + } else { + goto_record_type(au, AUDIT_AVC); + if (auparse_find_field(au, "name")) { + ret = get_file_info(au, target, 0); + impact_type = IDMEF_IMPACT_TYPE_FILE; + } + } + } + + /* Add AVC info for reference */ + if ((goto_record_type(au, AUDIT_AVC) == AUDIT_AVC) || + (goto_record_type(au, AUDIT_USER_AVC) == AUDIT_USER_AVC)) { + ret = add_additional_data(alert, "AVC Text", + auparse_get_record_text(au)); + PRELUDE_FAIL_CHECK; + } + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Detect mmap 0 here */ + type = AS_MAC; + if (seperm && strcmp(seperm, "mmap_zero") == 0) { + const char *tclass = auparse_find_field(au, "tclass"); + if (tclass && strcmp(tclass, "memprotect")) + type = AS_MMAP0; + } + + /* Describe event */ + if (type == AS_MAC) { + ret = set_classification(alert, "MAC Violation"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, IDMEF_IMPACT_SEVERITY_MEDIUM, + impact_type, assessment_description[AS_MAC]); + } else { + ret = set_classification(alert, "MMAP Page 0"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, IDMEF_IMPACT_SEVERITY_HIGH, + impact_type, assessment_description[AS_MMAP0]); + } + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "avc_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for Application Abnormal Termination related alerts + */ +static int app_term_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert) +{ + int ret; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser, *tuser; + idmef_user_id_t *user_id; + const char *sig; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + ret = idmef_target_new_user(target, &tuser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(tuser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(tuser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + + auparse_first_record(au); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, NULL, target); + PRELUDE_FAIL_CHECK; + + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + auparse_first_record(au); + sig = auparse_find_field(au, "sig"); + if (sig) { + sig = auparse_interpret_field(au); + ret = add_additional_data(alert, "Signal", sig); + PRELUDE_FAIL_CHECK; + } + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, "App Abnormal Termination"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, IDMEF_IMPACT_SEVERITY_MEDIUM, + IDMEF_IMPACT_TYPE_OTHER, + assessment_description[AS_ABEND]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "term_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is to alert that something has opened a promiscuous socket + */ +static int promiscuous_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert) +{ + int ret, type, old_prom=-1, new_prom=-1; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser, *tuser; + idmef_user_id_t *user_id; + const char *dev; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + type = goto_record_type(au, AUDIT_SYSCALL); + if (type == AUDIT_SYSCALL) { + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, + IDMEF_USER_ID_TYPE_ORIGINAL_USER); + + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + } + dev = auparse_find_field(au, "dev"); + if (dev) { + ret = add_additional_data(alert, "Device", dev); + PRELUDE_FAIL_CHECK; + } + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + ret = idmef_target_new_user(target, &tuser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(tuser, IDMEF_USER_CATEGORY_OS_DEVICE); + + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + type = goto_record_type(au, AUDIT_ANOM_PROMISCUOUS); + if (type == AUDIT_ANOM_PROMISCUOUS) { + const char *old_val, *new_val; + + auparse_first_field(au); + new_val = auparse_find_field(au, "prom"); + if (new_val) + new_prom = auparse_get_field_int(au); + old_val = auparse_find_field(au, "old_prom"); + if (old_val) + old_prom = auparse_get_field_int(au); + } + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + if (new_prom == 256 && old_prom == 0) + ret = set_classification(alert, "Promiscuous Socket Opened"); + else if (new_prom == 0 && old_prom == 256) + ret = set_classification(alert, "Promiscuous Socket Closed"); + else + ret = set_classification(alert, "Promiscuous Socket Changed"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, IDMEF_IMPACT_SEVERITY_INFO, + IDMEF_IMPACT_TYPE_RECON, + assessment_description[AS_PROM]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "promiscuous_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is to alert that something has changed the selinux enforcement + */ +static int mac_status_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert) +{ + int ret, type, old_enforce=-1, new_enforce=-1; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser, *tuser; + idmef_user_id_t *user_id; + idmef_impact_severity_t severity; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + + type = goto_record_type(au, AUDIT_SYSCALL); + if (type == AUDIT_SYSCALL) { + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + } + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + ret = idmef_target_new_user(target, &tuser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(tuser, IDMEF_USER_CATEGORY_OS_DEVICE); + + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + type = goto_record_type(au, AUDIT_MAC_STATUS); + if (type == AUDIT_MAC_STATUS) { + const char *old_val, *new_val; + + auparse_first_field(au); + new_val = auparse_find_field(au, "enforcing"); + if (new_val) + new_enforce = auparse_get_field_int(au); + old_val = auparse_find_field(au, "old_enforcing"); + if (old_val) + old_enforce = auparse_get_field_int(au); + } + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + if (new_enforce == 1 && old_enforce == 0) { + ret = set_classification(alert, "SE Linux Enforcement Enabled"); + severity = IDMEF_IMPACT_SEVERITY_LOW; + } else if (new_enforce == 0 && old_enforce == 1) { + ret = set_classification(alert,"SE Linux Enforcement Disabled"); + severity = IDMEF_IMPACT_SEVERITY_HIGH; + } else { + ret = set_classification(alert, "SE Linux Enforcement Changed"); + severity = IDMEF_IMPACT_SEVERITY_LOW; + } + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, severity, IDMEF_IMPACT_TYPE_OTHER, + assessment_description[AS_MAC_STAT]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "mac_status_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for authentication failure alerts + */ +static int auth_failure_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert, const char *msg, + idmef_impact_severity_t severity, as_description_t num) +{ + int ret, gid; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser, *tuser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + ret = idmef_target_new_user(target, &tuser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(tuser, IDMEF_USER_CATEGORY_APPLICATION); + + ret = get_target_group_info(au, tuser); + PRELUDE_FAIL_CHECK; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, msg); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + gid = get_new_gid(au); + if (gid == 0 || gid == 10) { // Root or wheel + impact = IDMEF_IMPACT_TYPE_ADMIN; + severity = IDMEF_IMPACT_SEVERITY_MEDIUM; + } else + impact = IDMEF_IMPACT_TYPE_USER; + ret = do_assessment(alert, au, severity, impact, + assessment_description[num]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "auth_failure_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for watched syscall related alerts + */ +static int watched_syscall_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert, idmef_impact_severity_t severity) +{ + int ret, rtype; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + /* We should only analyze the syscall */ + rtype = goto_record_type(au, AUDIT_SYSCALL); + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + + auparse_first_record(au); + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + rtype = goto_record_type(au, AUDIT_CWD); + if (rtype == AUDIT_CWD) { + ret = get_file_info(au, target, 1); + PRELUDE_FAIL_CHECK; + } + impact = IDMEF_IMPACT_TYPE_OTHER; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + ret = add_exit_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, "Watched Syscall"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, severity, impact, + assessment_description[AS_WATCHED_SYSCALL]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "watches_syscall_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for watched file related alerts + */ +static int watched_file_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert, idmef_impact_severity_t severity) +{ + int ret, rtype; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + + auparse_first_record(au); + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + rtype = goto_record_type(au, AUDIT_CWD); + if (rtype == AUDIT_CWD) { + ret = get_file_info(au, target, 1); + PRELUDE_FAIL_CHECK; + } + impact = IDMEF_IMPACT_TYPE_FILE; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, "Watched File"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + ret = do_assessment(alert, au, severity, impact, + assessment_description[AS_WATCHED_FILE]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "watches_file_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for watched executable related alerts + */ +static int watched_exec_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert, idmef_impact_severity_t severity) +{ + int ret, rtype; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + + auparse_first_record(au); + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + rtype = goto_record_type(au, AUDIT_CWD); + if (rtype == AUDIT_CWD) { + ret = get_file_info(au, target, 1); + PRELUDE_FAIL_CHECK; + } + + ret = add_execve_data(au, alert); + PRELUDE_FAIL_CHECK; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, "Watched Executable"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + if (get_loginuid(au) == 0) + impact = IDMEF_IMPACT_TYPE_ADMIN; + else + impact = IDMEF_IMPACT_TYPE_USER; + ret = do_assessment(alert, au, severity, impact, + assessment_description[AS_WATCHED_EXEC]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "watched_exec_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +/* + * This is for watching exe's being made related alerts + */ +static int watched_mk_exe_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert, idmef_impact_severity_t severity) +{ + int ret, rtype; + idmef_source_t *source; + idmef_target_t *target; + idmef_user_t *suser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + /* Fill in information about the target of the event */ + ret = idmef_alert_new_target(alert, &target, -1); + PRELUDE_FAIL_CHECK; + + auparse_first_record(au); + ret = get_node_info(au, source, target); + PRELUDE_FAIL_CHECK; + + rtype = goto_record_type(au, AUDIT_CWD); + if (rtype == AUDIT_CWD) { + ret = get_file_info(au, target, 1); + PRELUDE_FAIL_CHECK; + } + impact = IDMEF_IMPACT_TYPE_FILE; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, "Executable Created"); + PRELUDE_FAIL_CHECK; + + ret = do_assessment(alert, au, severity, impact, + assessment_description[AS_MK_EXE]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "watched_mk_exe_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} + +static int account_is_watched(auparse_state_t *au) +{ + const char *auid; + + auparse_first_field(au); + auid = auparse_find_field(au, "auid"); + if (auid) { // This is for successful logins + int uid = auparse_get_field_int(au); + if (ilist_find_num(&config.watched_accounts, uid)) + return 1; + } else { // Now try failed logins to see if we know who they are + auparse_first_field(au); + if ((auid = auparse_find_field(au, "acct"))) { + struct passwd *pw = getpwnam(auid); + if (pw && ilist_find_num( + &config.watched_accounts, pw->pw_uid)) + return 1; + } + } + return 0; +} + +static idmef_impact_type_t lookup_itype(const char *kind) +{ + if (strcasecmp(kind, "sys") == 0) + return IDMEF_IMPACT_TYPE_OTHER; + if (strcasecmp(kind, "file") == 0) + return IDMEF_IMPACT_TYPE_FILE; + if (strcasecmp(kind, "exec") == 0) + return IDMEF_IMPACT_TYPE_USER; + if (strcasecmp(kind, "mkexe") == 0) + return IDMEF_IMPACT_TYPE_OTHER; + return IDMEF_IMPACT_TYPE_ERROR; +} + +static idmef_impact_severity_t lookup_iseverity(const char *severity) +{ + if (strncmp(severity, "inf", 3) == 0) + return IDMEF_IMPACT_SEVERITY_INFO; + if (strncmp(severity, "low", 3) == 0) + return IDMEF_IMPACT_SEVERITY_LOW; + if (strncmp(severity, "med", 3) == 0) + return IDMEF_IMPACT_SEVERITY_MEDIUM; + if (strncmp(severity, "hi", 2) == 0) + return IDMEF_IMPACT_SEVERITY_HIGH; + return IDMEF_IMPACT_SEVERITY_ERROR; +} + +static void handle_watched_syscalls(auparse_state_t *au, + idmef_message_t **idmef, idmef_alert_t **alert) +{ + if (config.watched_syscall == E_YES || config.watched_file == E_YES || + config.watched_exec == E_YES || + config.watched_mk_exe == E_YES) { + const char *keyptr; + char *ptr, *kindptr, *ratingptr; + char key[AUDIT_MAX_KEY_LEN+1]; + idmef_impact_type_t type; + idmef_impact_severity_t severity; + + /* If no key or key is not for the ids, return */ + auparse_first_field(au); + keyptr = auparse_find_field(au, "key"); + if (keyptr) + keyptr = auparse_interpret_field(au); + while (keyptr) { + if (strncmp(keyptr, "ids-", 4) == 0) + break; + keyptr = auparse_find_field_next(au); + if (keyptr) + keyptr = auparse_interpret_field(au); + } + if (keyptr == NULL) + return; + + /* This key is for us, parse it up */ + strncpy(key, keyptr, AUDIT_MAX_KEY_LEN); + key[AUDIT_MAX_KEY_LEN] = 0; + + ptr = strchr(key, '-'); // There has to be a - because strncmp + kindptr = ptr + 1; + ptr = strchr(kindptr, '-'); + if (ptr) { + *ptr = 0; + ratingptr = ptr +1; + } else // The rules are misconfigured + return; + + type = lookup_itype(kindptr); + severity = lookup_iseverity(ratingptr); + + if (type == IDMEF_IMPACT_TYPE_OTHER && + strcasecmp(kindptr, "sys") == 0 && + config.watched_syscall == E_YES && + config.watched_syscall_act == A_IDMEF) { + if (new_alert_common(au, idmef, alert) >= 0) + watched_syscall_alert(au, *idmef, *alert, + severity); + } else if (type == IDMEF_IMPACT_TYPE_FILE && + config.watched_file == E_YES && + config.watched_file_act == A_IDMEF) { + if (new_alert_common(au, idmef, alert) >= 0) + watched_file_alert(au, *idmef, *alert, + severity); + } else if (type == IDMEF_IMPACT_TYPE_USER && + config.watched_exec == E_YES && + config.watched_exec_act == A_IDMEF) { + if (new_alert_common(au, idmef, alert) >= 0) + watched_exec_alert(au, *idmef, *alert, + severity); + } else if (type == IDMEF_IMPACT_TYPE_OTHER && + strcasecmp(kindptr, "mkexe") == 0 && + config.watched_mk_exe == E_YES && + config.watched_mk_exe_act == A_IDMEF) { + if (new_alert_common(au, idmef, alert) >= 0) + watched_mk_exe_alert(au, *idmef, *alert, + severity); + } + } +} + +static int tty_alert(auparse_state_t *au, idmef_message_t *idmef, + idmef_alert_t *alert) +{ + int ret; + + idmef_source_t *source; + idmef_user_t *suser; + idmef_user_id_t *user_id; + idmef_impact_type_t impact_type; + idmef_assessment_t *assessment; + idmef_impact_t *impact; + idmef_impact_severity_t severity; + prelude_string_t *str; + idmef_impact_completion_t completion = IDMEF_IMPACT_COMPLETION_ERROR; + + /* Fill in information about the event's source */ + ret = idmef_alert_new_source(alert, &source, -1); + PRELUDE_FAIL_CHECK; + + ret = idmef_source_new_user(source, &suser); + PRELUDE_FAIL_CHECK; + idmef_user_set_category(suser, IDMEF_USER_CATEGORY_APPLICATION); + ret = idmef_user_new_user_id(suser, &user_id, 0); + PRELUDE_FAIL_CHECK; + idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_ORIGINAL_USER); + ret = get_loginuid_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_tty_info(au, user_id); + PRELUDE_FAIL_CHECK; + + ret = get_comm_info(au, source, NULL); + PRELUDE_FAIL_CHECK; + + ret = add_execve_data(au, alert); + PRELUDE_FAIL_CHECK; + + ret = add_serial_number_data(au, alert); + PRELUDE_FAIL_CHECK; + + /* Describe event */ + ret = set_classification(alert, "Keylogger"); + PRELUDE_FAIL_CHECK; + + /* Assess impact */ + if (get_loginuid(au) == 0) + impact_type = IDMEF_IMPACT_TYPE_ADMIN; + else + impact_type = IDMEF_IMPACT_TYPE_USER; + completion = IDMEF_IMPACT_COMPLETION_SUCCEEDED; + severity = IDMEF_IMPACT_SEVERITY_LOW; + + ret = idmef_alert_new_assessment(alert, &assessment); + PRELUDE_FAIL_CHECK; + ret = idmef_assessment_new_impact(assessment, &impact); + PRELUDE_FAIL_CHECK; + idmef_impact_set_severity(impact, severity); + PRELUDE_FAIL_CHECK; + idmef_impact_set_type(impact, impact_type); + PRELUDE_FAIL_CHECK; + ret = idmef_impact_new_description(impact, &str); + PRELUDE_FAIL_CHECK; + ret = prelude_string_set_ref(str, assessment_description[AS_TTY]); + PRELUDE_FAIL_CHECK; + + send_idmef(client, idmef); + idmef_message_destroy(idmef); + + return 0; + + err: + syslog(LOG_ERR, "tty_alert: IDMEF error: %s.\n", + prelude_strerror(ret)); + idmef_message_destroy(idmef); + return -1; +} +static void handle_event(auparse_state_t *au, + auparse_cb_event_t cb_event_type, void *user_data) +{ + int type, num=0; + idmef_message_t *idmef; + idmef_alert_t *alert; + + if (cb_event_type != AUPARSE_CB_EVENT_READY) + return; + + // Loop through the records in the event looking for one to process. + // We use physical record number because we may search around and + // move the cursor accidentally skipping a record. + while (auparse_goto_record_num(au, num) > 0) { + type = auparse_get_type(au); + switch (type) { + case AUDIT_AVC: +// case AUDIT_USER_AVC: ignore USER_AVC for now + if (config.avcs == E_NO) + break; + if (config.avcs_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0) + avc_alert(au, idmef, alert); + break; + case AUDIT_USER_LOGIN: + // Do normal login alert + if (config.logins == E_YES && + config.logins_act == A_IDMEF) { + if (new_alert_common(au, &idmef, &alert) >= 0){ + login_alert(au, idmef, alert, "Login", + IDMEF_IMPACT_SEVERITY_INFO, AS_LOGIN); + }} + // Next do watched account alerts + if (config.watched_acct == E_NO) + break; + if (config.watched_acct_act != A_IDMEF) + break; + else if (account_is_watched(au)) { + if (new_alert_common(au, &idmef, &alert) >= 0){ + login_alert(au, idmef, alert, + "Watched Account Login", + IDMEF_IMPACT_SEVERITY_MEDIUM, + AS_WATCHED_LOGIN); + }} + break; + case AUDIT_ANOM_LOGIN_FAILURES: + if (config.login_failure_max == E_NO) + break; + if (config.login_failure_max_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0){ + login_alert(au, idmef, alert, + "Max Failed Logins", + IDMEF_IMPACT_SEVERITY_LOW, + AS_MAX_LOGIN_FAIL); + } + break; + case AUDIT_ANOM_LOGIN_SESSIONS: + if (config.login_session_max == E_NO) + break; + if (config.login_session_max_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0){ + login_alert(au, idmef, alert, + "Max Concurrent Sessions", + IDMEF_IMPACT_SEVERITY_INFO, + AS_MAX_LOGIN_SESS); + } + break; + case AUDIT_ANOM_LOGIN_LOCATION: + if (config.login_location == E_NO) + break; + if (config.login_location_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0){ + login_alert(au, idmef, alert, + "Login From Forbidden Location", + IDMEF_IMPACT_SEVERITY_MEDIUM, + AS_LOGIN_LOCATION); + } + break; + case AUDIT_ANOM_LOGIN_TIME: + if (config.login_time == E_NO) + break; + if (config.login_time_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0){ + login_alert(au, idmef, alert, + "Login During Forbidden Time", + IDMEF_IMPACT_SEVERITY_LOW, + AS_LOGIN_TIME); + } + break; + case AUDIT_ANOM_ABEND: + if (config.abends == E_NO) + break; + if (config.abends_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0) + app_term_alert(au, idmef, alert); + break; + case AUDIT_ANOM_PROMISCUOUS: + if (config.promiscuous == E_NO) + break; + if (config.promiscuous_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0) + promiscuous_alert(au, idmef, alert); + break; + case AUDIT_MAC_STATUS: + if (config.mac_status == E_NO) + break; + if (config.mac_status_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0) + mac_status_alert(au, idmef, alert); + break; + case AUDIT_GRP_AUTH: + if (config.group_auth == E_NO) + break; + if (config.group_auth_act != A_IDMEF) + break; + else { + const char *result; + + // We only care about failures + auparse_first_field(au); + result = auparse_find_field(au, "res"); + if (result && strcmp(result, "failed")) + break; + if (new_alert_common(au, &idmef, &alert) >= 0){ + auth_failure_alert(au, idmef, alert, + "Group Authentication Failure", + IDMEF_IMPACT_SEVERITY_LOW, + AS_AUTH); + }} + break; + case AUDIT_SYSCALL: + handle_watched_syscalls(au, &idmef, &alert); + // The previous call moves the current record + auparse_goto_record_num(au, num); + break; + case AUDIT_TTY: + if (config.tty == E_NO) + break; + if (config.tty_act != A_IDMEF) + break; + if (new_alert_common(au, &idmef, &alert) >= 0) + tty_alert(au, idmef, alert); + break; + default: + break; + } + num++; + } +} + -- cgit 1.2.3-korg