1
#define DBUS_API_SUBJECT_TO_CHANGE
13
#include <dbus/dbus.h>
14
#include <aalogparse/aalogparse.h>
16
#define NULLSPACE(x) (x == NULL) ? &empty_string : &x
17
#define NULLSTRLEN(x) (x == NULL) ? 1 : (strlen(x) + 1)
20
static volatile int signaled = 0;
24
static int event_loop(void);
25
static int is_reject(char *data);
28
static void term_handler( int sig )
35
* main is started by auditd. See dispatcher in auditd.conf
37
int main(int argc, char *argv[])
41
setlocale (LC_ALL, "");
44
/* Make sure we are root */
46
printf("You must be root to run this program.\n");
51
// register sighandlers
53
sa.sa_handler = term_handler;
54
sigemptyset( &sa.sa_mask ) ;
55
sigaction( SIGTERM, &sa, NULL );
56
sa.sa_handler = term_handler;
57
sigemptyset( &sa.sa_mask ) ;
58
sigaction( SIGCHLD, &sa, NULL );
59
sa.sa_handler = SIG_IGN;
60
sigaction( SIGHUP, &sa, NULL );
63
// change over to pipe_fd
66
open("/dev/null", O_RDONLY);
67
fcntl(pipe_fd, F_SETFD, FD_CLOEXEC);
73
/* This function is needed for "old" messages which lumped
74
* everything together under one audit ID.
76
static int is_reject (char *data)
79
/* Look for the first space */
80
char *start = strchr(data, ' ');
81
if ((start != NULL) && (strlen(start) > 9))
83
if (strncmp(start + 1, "REJECTING", 9) == 0)
92
static int event_loop(void)
95
char *empty_string = " "; /* This is a quick way to indicate a 'null' value in our DBUS message */
98
struct audit_dispatcher_header hdr;
100
DBusError error; /* Error, if any */
101
DBusMessage *message; /* Message to send */
102
static DBusConnection *con = NULL; /* Connection to DBUS server */
103
DBusMessageIter iter, /* The main message iterator */
111
char *line = NULL, *parsable_line = NULL;
113
aa_log_record *record;
114
int is_rejection = 0;
116
if (con && !dbus_connection_get_is_connected(con))
118
dbus_connection_unref(con);
124
dbus_error_init(&error);
125
con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
128
dbus_error_free(&error);
134
//message = dbus_message_new_signal("/com/Novell/AppArmor","com.novell.apparmor", "Reject");
136
/* allocate data structures */
137
data = malloc(MAX_AUDIT_MESSAGE_LENGTH);
140
printf("Cannot allocate buffer\n");
144
memset(data, 0, MAX_AUDIT_MESSAGE_LENGTH);
145
memset(&hdr, 0, sizeof(hdr));
149
parsable_line = NULL;
156
FD_SET(pipe_fd, &fd);
157
rc = select(pipe_fd+1, &fd, NULL, NULL, &tv);
163
/* Get header first. it is fixed size */
164
vec[0].iov_base = (void*)&hdr;
165
vec[0].iov_len = sizeof(hdr);
167
memset(data, 0, MAX_AUDIT_MESSAGE_LENGTH);
169
vec[1].iov_base = data;
170
vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH;
172
rc = readv(pipe_fd, vec, 2);
173
if (rc == 0 || rc == -1) {
174
printf("rc == %d(%s)\n", rc, strerror(errno));
178
/* Handle the AppArmor events.
179
* 1500 is used for "old" style messages.
180
* 1503 is used for APPARMOR_DENIED messages.
182
if ((hdr.type == 1500) || (hdr.type == 1503))
184
line = (char *) data;
186
if (hdr.type == 1503)
188
if ((hdr.type == 1500) && (is_reject(line) == 0))
191
/* We only care about REJECTING messages */
192
if (is_rejection == 1)
194
/* parse_record expects things like they appear in audit.log -
195
* which means we need to prepend TYPE=APPARMOR (if hdr.type is 1500)
196
* or type=APPARMOR_DENIED (if hdr.type is 1503). This is not ideal.
198
real_data_size = strlen(line);
199
if (hdr.type == 1500)
201
parsable_line = (char *) malloc(real_data_size + 20);
202
snprintf(parsable_line, real_data_size + 19, "type=APPARMOR msg=%s", line);
206
parsable_line = (char *) malloc(real_data_size + 27);
207
snprintf(parsable_line, real_data_size + 26, "type=APPARMOR_DENIED msg=%s", line);
210
record = parse_record(parsable_line);
211
message = dbus_message_new_signal("/com/Novell/AppArmor","com.novell.apparmor", "REJECT");
212
dbus_message_iter_init_append(message, &iter);
215
* The message has a number of fields appended to it,
216
* all of which map to the aa_log_record struct that we get back from
217
* parse_record(). If an entry in the struct is NULL or otherwise invalid,
218
* the field is still appended as a single blank space (in the case of strings), or a
219
* 0 in case of integers (which are all PIDs and unlikely to ever be 0).
221
* TODO: Pass a bitmask int along for the denied & requested masks
223
* 1 - The full string - BYTE ARRAY
224
* 2 - The PID (record->pid) - DBUS_TYPE_INT64
225
* 3 - The task (record->task) - DBUS_TYPE_INT64
226
* 4 - The audit ID (record->audit_id) - DBUS_TYPE_STRING
227
* 5 - The operation (record->operation: "Exec" "ptrace" etc) - DBUS_TYPE_STRING
228
* 6 - The denied mask (record->denied_mask: "rwx" etc) - DBUS_TYPE_STRING
229
* 7 - The requested mask (record->requested_mask) - DBUS_TYPE_STRING
230
* 8 - The name of the profile (record->profile) - BYTE ARRAY
231
* 9 - The first name field (record->name) - BYTE ARRAY
232
* 10- The second name field (record->name2) - BYTE ARRAY
233
* 11- The attribute (record->attribute) - DBUS_TYPE_STRING
234
* 12- The parent task (record->parent) - BYTE ARRAY
235
* 13- The magic token (record->magic_token) - DBUS_TYPE_INT64
236
* 14- The info field (record->info) - BYTE ARRAY
237
* 15- The active hat (record->active_hat) - BYTE ARRAY
243
/* Please note: NULLSPACE is defined at the top of this file, and will expand to
244
a ternary conditional:
245
(record->audit_id == NULL) ? &empty_string : &record->audit_id
248
The way we handle strings is ugly - some of the characters we allow (0x80, for example) are invalid Unicode,
249
which will cause our DBus connection to be dropped if we send them as a DBUS_TYPE_STRING.
250
Instead, we send a bunch of containers, each with a byte array. Perhaps a struct would be better?
253
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &dataIter);
254
dbus_message_iter_append_fixed_array(&dataIter, DBUS_TYPE_BYTE, &data, strlen(data) + 1);
255
dbus_message_iter_close_container(&iter, &dataIter);
257
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &record->pid);
258
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &record->task);
259
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->audit_id));
260
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->operation));
262
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->denied_mask));
263
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->requested_mask));
265
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &profileIter);
266
dbus_message_iter_append_fixed_array(&profileIter,
268
NULLSPACE(record->profile),
269
NULLSTRLEN(record->profile));
270
dbus_message_iter_close_container(&iter, &profileIter);
272
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &nameIter);
273
dbus_message_iter_append_fixed_array(&nameIter,
275
NULLSPACE(record->name),
276
NULLSTRLEN(record->name));
277
dbus_message_iter_close_container(&iter, &nameIter);
279
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &name2Iter);
280
dbus_message_iter_append_fixed_array(&name2Iter,
282
NULLSPACE(record->name2),
283
NULLSTRLEN(record->name2));
284
dbus_message_iter_close_container(&iter, &name2Iter);
286
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->attribute));
288
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &parentIter);
289
dbus_message_iter_append_fixed_array(&parentIter,
291
NULLSPACE(record->parent),
292
NULLSTRLEN(record->parent));
293
dbus_message_iter_close_container(&iter, &parentIter);
295
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &record->magic_token);
296
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->info));
298
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &activeIter);
299
dbus_message_iter_append_fixed_array(&activeIter,
301
NULLSPACE(record->active_hat),
302
NULLSTRLEN(record->active_hat));
303
dbus_message_iter_close_container(&iter, &activeIter);
307
dbus_connection_send(con, message, NULL);
308
dbus_connection_flush(con);
309
dbus_message_unref(message);
312
if (parsable_line != NULL)
319
dbus_connection_unref(con);