Imported Upstream version 2.4.3
[platform/upstream/audit.git] / contrib / plugin / audisp-example.c
1 /* audisp-example.c --
2  * Copyright 2012 Red Hat Inc., Durham, North Carolina.
3  * All Rights Reserved.
4  *
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.
9  *
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.
14  *
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
18  *
19  * Authors:
20  *   Steve Grubb <sgrubb@redhat.com>
21  *
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:
25  *
26  * ausearch --start today --raw > test.log.
27  *
28  * Then you can test this app by: cat test.log | ./audisp-example
29  *
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.
32  *
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. 
36  *
37  */
38
39 #define _GNU_SOURCE
40 #include <stdio.h>
41 #include <signal.h>
42 #include <string.h>
43 #include <sys/select.h>
44 #include <errno.h>
45 #include "libaudit.h"
46 #include "auparse.h"
47
48 /* Global Data */
49 static volatile int stop = 0;
50 static volatile int hup = 0;
51 static auparse_state_t *au = NULL;
52
53 /* Local declarations */
54 static void handle_event(auparse_state_t *au,
55                 auparse_cb_event_t cb_event_type, void *user_data);
56
57 /*
58  * SIGTERM handler
59  */
60 static void term_handler( int sig )
61 {
62         stop = 1;
63 }
64
65 /*
66  * SIGHUP handler: re-read config
67  */
68 static void hup_handler( int sig )
69 {
70         hup = 1;
71 }
72
73 static void reload_config(void)
74 {
75         hup = 0;
76 }
77
78 int main(int argc, char *argv[])
79 {
80         char tmp[MAX_AUDIT_MESSAGE_LENGTH+1];
81         struct sigaction sa;
82
83         /* Register sighandlers */
84         sa.sa_flags = 0;
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);
91
92         /* Initialize the auparse library */
93         au = auparse_init(AUSOURCE_FEED, 0);
94         if (au == NULL) {
95                 printf("audisp-example is exiting due to auparse init errors");
96                 return -1;
97         }
98         auparse_add_callback(au, handle_event, NULL, NULL);
99         do {
100                 fd_set read_mask;
101                 struct timeval tv;
102                 int retval;
103
104                 /* Load configuration */
105                 if (hup) {
106                         reload_config();
107                 }
108                 do {
109                         tv.tv_sec = 5;
110                         tv.tv_usec = 0;
111                         FD_ZERO(&read_mask);
112                         FD_SET(0, &read_mask);
113                         if (auparse_feed_has_data(au))
114                                 retval= select(1, &read_mask, NULL, NULL, &tv);
115                         else
116                                 retval= select(1, &read_mask, NULL, NULL, NULL);
117                 } while (retval == -1 && errno == EINTR && !hup && !stop);
118
119                 /* Now the event loop */
120                  if (!stop && !hup && retval > 0) {
121                         if (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH,
122                                 stdin)) {
123                                 auparse_feed(au, tmp, strnlen(tmp,
124                                                 MAX_AUDIT_MESSAGE_LENGTH));
125                         }
126                 } else if (retval == 0)
127                         auparse_flush_feed(au);
128                 if (feof(stdin))
129                         break;
130         } while (stop == 0);
131
132         /* Flush any accumulated events from queue */
133         auparse_flush_feed(au);
134         auparse_destroy(au);
135         if (stop)
136                 printf("audisp-example is exiting on stop request\n");
137         else
138                 printf("audisp-example is exiting on stdin EOF\n");
139
140         return 0;
141 }
142
143 /* This function shows how to dump a whole event by iterating over records */
144 static void dump_whole_event(auparse_state_t *au)
145 {
146         auparse_first_record(au);
147         do {
148                 printf("%s\n", auparse_get_record_text(au));
149         } while (auparse_next_record(au) > 0);
150         printf("\n");
151 }
152
153 /* This function shows how to dump a whole record's text */
154 static void dump_whole_record(auparse_state_t *au)
155 {
156         printf("%s: %s\n", audit_msg_type_to_name(auparse_get_type(au)),
157                 auparse_get_record_text(au));
158         printf("\n");
159 }
160
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)
164 {
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));
168
169         printf("line=%d file=%s\n", auparse_get_line_number(au),
170                 auparse_get_filename(au) ? auparse_get_filename(au) : "stdin");
171
172         const au_event_t *e = auparse_get_timestamp(au);
173         if (e == NULL) {
174                 printf("Error getting timestamp - aborting\n");
175                 return;
176         }
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);
182
183         do {
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);
189         printf("\n");
190 }
191
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)
196 {
197         int type, num=0;
198
199         if (cb_event_type != AUPARSE_CB_EVENT_READY)
200                 return;
201
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. */
209                 switch (type) {
210                         case AUDIT_AVC:
211                                 dump_fields_of_record(au);
212                                 break;
213                         case AUDIT_SYSCALL:
214                                 dump_whole_record(au); 
215                                 break;
216                         case AUDIT_USER_LOGIN:
217                                 break;
218                         case AUDIT_ANOM_ABEND:
219                                 break;
220                         case AUDIT_MAC_STATUS:
221                                 dump_whole_event(au); 
222                                 break;
223                         default:
224                                 break;
225                 }
226                 num++;
227         }
228 }
229