2 * Copyright 2012 Red Hat Inc., Durham, North Carolina.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Steve Grubb <sgrubb@redhat.com>
22 * This is a sample program to demonstrate several concepts of how to
23 * write an audispd plugin using libauparse. It can be tested by using a
24 * file of raw audit records. You can generate the test file like:
26 * ausearch --start today --raw > test.log.
28 * Then you can test this app by: cat test.log | ./audisp-example
30 * It will print things to stdout. In a real program, you wouldn't
31 * do anything with stdout since that is likely to be pointing to /dev/null.
33 * Excluding some init/destroy items you might need to add to main, the
34 * event_handler function is the main place that you would modify to do
35 * things specific to your plugin.
43 #include <sys/select.h>
49 static volatile int stop = 0;
50 static volatile int hup = 0;
51 static auparse_state_t *au = NULL;
53 /* Local declarations */
54 static void handle_event(auparse_state_t *au,
55 auparse_cb_event_t cb_event_type, void *user_data);
60 static void term_handler( int sig )
66 * SIGHUP handler: re-read config
68 static void hup_handler( int sig )
73 static void reload_config(void)
78 int main(int argc, char *argv[])
80 char tmp[MAX_AUDIT_MESSAGE_LENGTH+1];
83 /* Register sighandlers */
85 sigemptyset(&sa.sa_mask);
86 /* Set handler for the ones we care about */
87 sa.sa_handler = term_handler;
88 sigaction(SIGTERM, &sa, NULL);
89 sa.sa_handler = hup_handler;
90 sigaction(SIGHUP, &sa, NULL);
92 /* Initialize the auparse library */
93 au = auparse_init(AUSOURCE_FEED, 0);
95 printf("audisp-example is exiting due to auparse init errors");
98 auparse_add_callback(au, handle_event, NULL, NULL);
104 /* Load configuration */
112 FD_SET(0, &read_mask);
113 if (auparse_feed_has_data(au))
114 retval= select(1, &read_mask, NULL, NULL, &tv);
116 retval= select(1, &read_mask, NULL, NULL, NULL);
117 } while (retval == -1 && errno == EINTR && !hup && !stop);
119 /* Now the event loop */
120 if (!stop && !hup && retval > 0) {
121 if (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH,
123 auparse_feed(au, tmp, strnlen(tmp,
124 MAX_AUDIT_MESSAGE_LENGTH));
126 } else if (retval == 0)
127 auparse_flush_feed(au);
132 /* Flush any accumulated events from queue */
133 auparse_flush_feed(au);
136 printf("audisp-example is exiting on stop request\n");
138 printf("audisp-example is exiting on stdin EOF\n");
143 /* This function shows how to dump a whole event by iterating over records */
144 static void dump_whole_event(auparse_state_t *au)
146 auparse_first_record(au);
148 printf("%s\n", auparse_get_record_text(au));
149 } while (auparse_next_record(au) > 0);
153 /* This function shows how to dump a whole record's text */
154 static void dump_whole_record(auparse_state_t *au)
156 printf("%s: %s\n", audit_msg_type_to_name(auparse_get_type(au)),
157 auparse_get_record_text(au));
161 /* This function shows how to iterate through the fields of a record
162 * and print its name and raw value and interpretted value. */
163 static void dump_fields_of_record(auparse_state_t *au)
165 printf("record type %d(%s) has %d fields\n", auparse_get_type(au),
166 audit_msg_type_to_name(auparse_get_type(au)),
167 auparse_get_num_fields(au));
169 printf("line=%d file=%s\n", auparse_get_line_number(au),
170 auparse_get_filename(au) ? auparse_get_filename(au) : "stdin");
172 const au_event_t *e = auparse_get_timestamp(au);
174 printf("Error getting timestamp - aborting\n");
177 /* Note that e->sec can be treated as time_t data if you want
178 * something a little more readable */
179 printf("event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec,
180 e->milli, e->serial, e->host ? e->host : "?");
181 auparse_first_field(au);
184 printf("field: %s=%s (%s)\n",
185 auparse_get_field_name(au),
186 auparse_get_field_str(au),
187 auparse_interpret_field(au));
188 } while (auparse_next_field(au) > 0);
192 /* This function receives a single complete event at a time from the auparse
193 * library. This is where the main analysis code would be added. */
194 static void handle_event(auparse_state_t *au,
195 auparse_cb_event_t cb_event_type, void *user_data)
199 if (cb_event_type != AUPARSE_CB_EVENT_READY)
202 /* Loop through the records in the event looking for one to process.
203 We use physical record number because we may search around and
204 move the cursor accidentally skipping a record. */
205 while (auparse_goto_record_num(au, num) > 0) {
206 type = auparse_get_type(au);
207 /* Now we can branch based on what record type we find.
208 This is just a few suggestions, but it could be anything. */
211 dump_fields_of_record(au);
214 dump_whole_record(au);
216 case AUDIT_USER_LOGIN:
218 case AUDIT_ANOM_ABEND:
220 case AUDIT_MAC_STATUS:
221 dump_whole_event(au);