~ubuntu-branches/ubuntu/wily/apparmor/wily

« back to all changes in this revision

Viewing changes to deprecated/management/apparmor-dbus/src/aadbus.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-04-27 10:38:07 UTC
  • mfrom: (5.1.118 natty)
  • Revision ID: james.westby@ubuntu.com-20110427103807-ym3rhwys6o84ith0
Tags: 2.6.1-2
debian/copyright: clarify for some full organization names.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define DBUS_API_SUBJECT_TO_CHANGE
 
2
#include <stdio.h>
 
3
#include <sys/types.h>
 
4
#include <sys/uio.h>
 
5
#include <unistd.h>
 
6
#include <stdlib.h>
 
7
#include <signal.h>
 
8
#include <fcntl.h>
 
9
#include <errno.h>
 
10
#include <string.h>
 
11
#include <locale.h>
 
12
#include <libaudit.h>
 
13
#include <dbus/dbus.h>
 
14
#include <aalogparse/aalogparse.h>
 
15
 
 
16
#define NULLSPACE(x) (x == NULL) ? &empty_string : &x
 
17
#define NULLSTRLEN(x) (x == NULL) ? 1 : (strlen(x) + 1)
 
18
 
 
19
// Local data
 
20
static volatile int signaled = 0;
 
21
static int pipe_fd;
 
22
 
 
23
// Local functions
 
24
static int event_loop(void);
 
25
static int is_reject(char *data);
 
26
 
 
27
// SIGTERM handler
 
28
static void term_handler( int sig )
 
29
{
 
30
        signaled = 1;
 
31
}
 
32
 
 
33
 
 
34
/*
 
35
 * main is started by auditd. See dispatcher in auditd.conf
 
36
 */
 
37
int main(int argc, char *argv[])
 
38
{
 
39
        struct sigaction sa;
 
40
        
 
41
        setlocale (LC_ALL, "");
 
42
        
 
43
#ifndef DEBUG
 
44
/*      Make sure we are root */
 
45
        if (getuid() != 0) {
 
46
                printf("You must be root to run this program.\n");
 
47
                return 4;
 
48
        }
 
49
#endif
 
50
 
 
51
        // register sighandlers
 
52
        sa.sa_flags = 0 ;
 
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 );
 
61
        (void)chdir("/");
 
62
 
 
63
        // change over to pipe_fd
 
64
        pipe_fd = dup(0);
 
65
        close(0);
 
66
        open("/dev/null", O_RDONLY);
 
67
        fcntl(pipe_fd, F_SETFD, FD_CLOEXEC);
 
68
 
 
69
        // Start the program
 
70
        return event_loop();
 
71
}
 
72
 
 
73
/* This function is needed for "old" messages which lumped
 
74
 * everything together under one audit ID.
 
75
 */
 
76
static int is_reject (char *data)
 
77
{
 
78
        int ret = -1;
 
79
        /* Look for the first space */
 
80
        char *start = strchr(data, ' ');
 
81
        if ((start != NULL) && (strlen(start) > 9))
 
82
        {
 
83
                if (strncmp(start + 1, "REJECTING", 9) == 0)
 
84
                {
 
85
                        ret = 0;
 
86
                }
 
87
        }
 
88
 
 
89
        return ret;
 
90
}
 
91
 
 
92
static int event_loop(void)
 
93
{
 
94
        void* data;
 
95
        char *empty_string = " "; /* This is a quick way to indicate a 'null' value in our DBUS message */
 
96
 
 
97
        struct iovec vec[2];
 
98
        struct audit_dispatcher_header hdr;
 
99
 
 
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 */
 
104
                                profileIter,
 
105
                                nameIter,
 
106
                                name2Iter,
 
107
                                parentIter,
 
108
                                activeIter,
 
109
                                dataIter;
 
110
 
 
111
        char *line = NULL, *parsable_line = NULL;
 
112
        int real_data_size;
 
113
        aa_log_record *record;
 
114
        int is_rejection = 0;
 
115
 
 
116
        if (con && !dbus_connection_get_is_connected(con))
 
117
        {
 
118
                dbus_connection_unref(con);
 
119
                con = NULL;
 
120
        }
 
121
        
 
122
        if (!con)
 
123
        {
 
124
                dbus_error_init(&error);
 
125
                con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
 
126
                if (!con)
 
127
                {
 
128
                        dbus_error_free(&error);
 
129
                        return 1;
 
130
                }
 
131
        }
 
132
 
 
133
 
 
134
        //message = dbus_message_new_signal("/com/Novell/AppArmor","com.novell.apparmor", "Reject");
 
135
 
 
136
        /* allocate data structures */
 
137
        data = malloc(MAX_AUDIT_MESSAGE_LENGTH);
 
138
        if (data == NULL) 
 
139
        {
 
140
                printf("Cannot allocate buffer\n");
 
141
                return 1;
 
142
        }
 
143
 
 
144
        memset(data, 0, MAX_AUDIT_MESSAGE_LENGTH);
 
145
        memset(&hdr, 0, sizeof(hdr));
 
146
        do
 
147
        {
 
148
                int rc;
 
149
                parsable_line = NULL;
 
150
                is_rejection = 0;
 
151
                struct timeval tv;
 
152
                fd_set fd;
 
153
                tv.tv_sec = 1;
 
154
                tv.tv_usec = 0;
 
155
                FD_ZERO(&fd);
 
156
                FD_SET(pipe_fd, &fd);
 
157
                rc = select(pipe_fd+1, &fd, NULL, NULL, &tv);
 
158
                if (rc == 0) 
 
159
                        continue;
 
160
                 else if (rc == -1)
 
161
                        break;
 
162
 
 
163
                /* Get header first. it is fixed size */
 
164
                vec[0].iov_base = (void*)&hdr;
 
165
                vec[0].iov_len = sizeof(hdr);
 
166
 
 
167
                memset(data, 0, MAX_AUDIT_MESSAGE_LENGTH);
 
168
                // Next payload 
 
169
                vec[1].iov_base = data;
 
170
                vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH; 
 
171
 
 
172
                rc = readv(pipe_fd, vec, 2);
 
173
                if (rc == 0 || rc == -1) {
 
174
                        printf("rc == %d(%s)\n", rc, strerror(errno));
 
175
                        break;
 
176
                }
 
177
 
 
178
                /* Handle the AppArmor events.
 
179
                 * 1500 is used for "old" style messages.
 
180
                 * 1503 is used for APPARMOR_DENIED messages. 
 
181
                 */
 
182
                if ((hdr.type == 1500) || (hdr.type == 1503))
 
183
                {
 
184
                        line = (char *) data;
 
185
                        record = NULL;
 
186
                        if (hdr.type == 1503)
 
187
                                is_rejection = 1;
 
188
                        if ((hdr.type == 1500) && (is_reject(line) == 0))
 
189
                                is_rejection = 1;
 
190
 
 
191
                        /* We only care about REJECTING messages */
 
192
                        if (is_rejection == 1)
 
193
                        {
 
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.
 
197
                                 */
 
198
                                real_data_size = strlen(line);
 
199
                                if (hdr.type == 1500)
 
200
                                {
 
201
                                        parsable_line = (char *) malloc(real_data_size + 20);
 
202
                                        snprintf(parsable_line, real_data_size + 19, "type=APPARMOR msg=%s", line);
 
203
                                }
 
204
                                else
 
205
                                {
 
206
                                        parsable_line = (char *) malloc(real_data_size + 27);
 
207
                                        snprintf(parsable_line, real_data_size + 26, "type=APPARMOR_DENIED msg=%s", line);
 
208
                                }
 
209
 
 
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);
 
213
 
 
214
                                /*
 
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).
 
220
                                 *
 
221
                                 * TODO: Pass a bitmask int along for the denied & requested masks
 
222
                                 *
 
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
 
238
                                 */
 
239
 
 
240
                                if (record != NULL)
 
241
                                {
 
242
 
 
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
 
246
                                           for example.
 
247
 
 
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? 
 
251
                                        */
 
252
 
 
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);
 
256
 
 
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));
 
261
 
 
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));
 
264
 
 
265
                                        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &profileIter);
 
266
                                        dbus_message_iter_append_fixed_array(&profileIter,
 
267
                                                                                DBUS_TYPE_BYTE,
 
268
                                                                                NULLSPACE(record->profile),
 
269
                                                                                NULLSTRLEN(record->profile));
 
270
                                        dbus_message_iter_close_container(&iter, &profileIter);
 
271
 
 
272
                                        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &nameIter);
 
273
                                        dbus_message_iter_append_fixed_array(&nameIter,
 
274
                                                                                DBUS_TYPE_BYTE,
 
275
                                                                                NULLSPACE(record->name),
 
276
                                                                                NULLSTRLEN(record->name));
 
277
                                        dbus_message_iter_close_container(&iter, &nameIter);
 
278
 
 
279
                                        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &name2Iter);
 
280
                                        dbus_message_iter_append_fixed_array(&name2Iter,
 
281
                                                                                DBUS_TYPE_BYTE,
 
282
                                                                                NULLSPACE(record->name2),
 
283
                                                                                NULLSTRLEN(record->name2));
 
284
                                        dbus_message_iter_close_container(&iter, &name2Iter);
 
285
 
 
286
                                        dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, NULLSPACE(record->attribute));
 
287
 
 
288
                                        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &parentIter);
 
289
                                        dbus_message_iter_append_fixed_array(&parentIter,
 
290
                                                                                DBUS_TYPE_BYTE,
 
291
                                                                                NULLSPACE(record->parent),
 
292
                                                                                NULLSTRLEN(record->parent));
 
293
                                        dbus_message_iter_close_container(&iter, &parentIter);
 
294
 
 
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));
 
297
 
 
298
                                        dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &activeIter);
 
299
                                        dbus_message_iter_append_fixed_array(&activeIter,
 
300
                                                                                DBUS_TYPE_BYTE,
 
301
                                                                                NULLSPACE(record->active_hat),
 
302
                                                                                NULLSTRLEN(record->active_hat));
 
303
                                        dbus_message_iter_close_container(&iter, &activeIter);
 
304
 
 
305
 
 
306
                                }
 
307
                                dbus_connection_send(con, message, NULL);
 
308
                                dbus_connection_flush(con);
 
309
                                dbus_message_unref(message);
 
310
                                free_record(record);
 
311
 
 
312
                                if (parsable_line != NULL)
 
313
                                        free(parsable_line);
 
314
                        }
 
315
                }
 
316
        } while(!signaled);
 
317
 
 
318
        if (con)
 
319
                dbus_connection_unref(con);
 
320
        free(data);
 
321
        return 0;
 
322
}