source: trunk/src/sh_audit.c@ 425

Last change on this file since 425 was 419, checked in by katerina, 12 years ago

Fix for ticket #323 (build error with Linux audit).

File size: 11.4 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2010 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
23
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <errno.h>
29#include <unistd.h>
30
31#if !defined(SH_COMPILE_STATIC) && defined(__linux__) && defined(HAVE_AUPARSE_H) && defined(HAVE_AUPARSE_LIB)
32#include <auparse.h>
33
34#include "samhain.h"
35#include "sh_error.h"
36#include "sh_extern.h"
37#include "sh_utils.h"
38
39#undef FIL__
40#define FIL__ _("sh_audit.c")
41
42#define REC_SIZE_SYSCALL 32
43#define REC_SIZE_EXE 64
44#define REC_SIZE_SUCCESS 32
45
46struct recordState {
47 char syscall[REC_SIZE_SYSCALL];
48 char exe[REC_SIZE_EXE];
49 char success[REC_SIZE_SUCCESS];
50 unsigned int auid;
51 unsigned int uid;
52 unsigned int gid;
53 unsigned int euid;
54 unsigned int egid;
55 unsigned int fsuid;
56 unsigned int fsgid;
57 time_t time;
58 unsigned int milli;
59};
60
61static int listRecords (auparse_state_t * au, struct recordState * state)
62{
63 if (auparse_first_record(au) != 1)
64 return -1;
65
66 state->time = auparse_get_time(au);
67 state->milli = auparse_get_milli(au);
68
69 if (auparse_find_field(au, _("syscall")))
70 sl_strlcpy(state->syscall, auparse_interpret_field(au), REC_SIZE_SYSCALL);
71
72 if (auparse_find_field(au, _("success")))
73 strncpy(state->success, auparse_interpret_field(au), REC_SIZE_SUCCESS);
74
75 if (auparse_find_field(au, "uid"))
76 state->uid = auparse_get_field_int(au);
77 if (auparse_find_field(au, "gid"))
78 state->gid = auparse_get_field_int(au);
79
80 if (auparse_find_field(au, _("euid")))
81 state->euid = auparse_get_field_int(au);
82 if (auparse_find_field(au, _("fsuid")))
83 state->fsuid = auparse_get_field_int(au);
84
85 auparse_first_field(au);
86
87 if (auparse_find_field(au, _("auid")))
88 state->auid = auparse_get_field_int(au);
89
90 auparse_first_field(au);
91
92 if (auparse_find_field(au, _("egid")))
93 state->egid = auparse_get_field_int(au);
94 if (auparse_find_field(au, _("fsgid")))
95 state->fsgid = auparse_get_field_int(au);
96
97 auparse_first_field(au);
98
99 if (auparse_find_field(au, "exe"))
100 sl_strlcpy(state->exe, auparse_interpret_field(au), REC_SIZE_EXE);
101
102 return 0;
103}
104
105static char * doAuparse (char * file, time_t time, char * result, size_t rsize)
106{
107 struct recordState state;
108 struct recordState stateFetched;
109
110 auparse_state_t * au = auparse_init(AUSOURCE_LOGS, NULL);
111
112 if (!au)
113 {
114 char ebuf[SH_ERRBUF_SIZE];
115 int errnum = errno;
116
117 sl_snprintf(ebuf, sizeof(ebuf), _("Error in auparse_init() - %s\n"),
118 strerror(errnum));
119 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
120 ebuf,
121 _("doAuparse") );
122 return NULL;
123 }
124
125 if (ausearch_add_interpreted_item(au, _("name"), "=", file,
126 AUSEARCH_RULE_CLEAR) != 0)
127 {
128 goto err;
129 }
130
131 if (time != 0)
132 {
133 ausearch_add_timestamp_item(au, ">=", time-1, 0, AUSEARCH_RULE_AND);
134 ausearch_add_timestamp_item(au, "<=", time+1, 0, AUSEARCH_RULE_AND);
135 }
136
137 if (ausearch_set_stop(au, AUSEARCH_STOP_RECORD) != 0)
138 {
139 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
140 _("Error in ausearch_set_stop\n"),
141 _("doAuparse") );
142 goto err;
143 }
144
145 memset(&state, '\0', sizeof(state));
146
147 while (ausearch_next_event(au) == 1)
148 {
149 memset(&stateFetched, '\0', sizeof(state));
150 listRecords(au, &stateFetched);
151 if (0 == strcmp(stateFetched.success, "yes"))
152 {
153 memcpy(&state, &stateFetched, sizeof(state));
154 }
155 auparse_next_event(au);
156 }
157
158 if (0 == strcmp(state.success, "yes"))
159 {
160 char * tmp_exe = sh_util_safe_name(state.exe);
161 sl_snprintf(result, rsize,
162 _("time=%lu.%u, syscall=%s, auid=%u, uid=%u, gid=%u, euid=%u, egid=%u, fsuid=%u, fsgid=%u, exe=%s"),
163 (unsigned long) state.time, state.milli,
164 state.syscall,
165 state.auid, state.uid, state.gid, state.euid, state.egid,
166 state.fsuid, state.fsgid, tmp_exe);
167 SH_FREE(tmp_exe);
168 auparse_destroy(au);
169 return result;
170 }
171
172 err:
173 auparse_destroy(au);
174 return NULL;
175}
176
177static int sh_audit_checkdaemon();
178static int actl_pnum = -1;
179static char * actl_paths[4] =
180 {
181 N_("/sbin/auditctl"),
182 N_("/usr/sbin/auditctl"),
183 N_("/bin/auditctl"),
184 N_("/usr/bin/auditctl")
185 };
186
187
188/* Public function to fetch an audit record for path 'file', time 'time'
189 * The 'result' array should be sized ~256 char.
190 */
191char * sh_audit_fetch (char * file, time_t time, char * result, size_t rsize)
192{
193 char * res = NULL;
194
195 if (sh_audit_checkdaemon() >= 0)
196 {
197 res = doAuparse (file, time, result, rsize);
198
199 if (!res)
200 {
201 res = doAuparse (file, 0, result, rsize);
202 }
203 }
204 return res;
205}
206
207void sh_audit_delete_all ()
208{
209 int p = sh_audit_checkdaemon();
210
211 if (p >= 0)
212 {
213 char ctl[64];
214
215 sl_snprintf(ctl, sizeof(ctl), _("%s -D -k samhain"),
216 _(actl_paths[p]));
217 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
218 0, MSG_E_SUBGEN,
219 _("Deleting audit daemon rules with key samhain"),
220 _("sh_audit_delete_all") );
221
222 sl_strlcpy(ctl, _(actl_paths[p]), sizeof(ctl));
223 sh_ext_system(ctl, ctl, "-D", "-k", _("samhain"), NULL);
224 }
225 return;
226}
227
228static void sh_audit_mark_int (const char * file)
229{
230 static int flushRules = 0;
231
232 int p = sh_audit_checkdaemon();
233
234 /* Flush all rules at startup.
235 */
236 if (flushRules == 0)
237 {
238 sh_audit_delete_all ();
239 flushRules = 1;
240 }
241
242 if (p >= 0)
243 {
244 size_t len = strlen(file) + 64;
245 char * command = SH_ALLOC(len);
246 char * safe;
247 char ctl[64];
248
249 sl_snprintf(command, len, _("%s -w %s -p wa -k samhain"),
250 _(actl_paths[p]),
251 file);
252
253 safe = sh_util_safe_name_keepspace(command);
254 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
255 0, MSG_E_SUBGEN,
256 safe,
257 _("sh_audit_mark") );
258 SH_FREE(safe);
259
260 sl_strlcpy(ctl, _(actl_paths[p]), sizeof(ctl));
261 sl_strlcpy(command, file, len);
262
263 sh_ext_system(ctl, ctl, "-w", command, "-p", "wa", "-k", _("samhain"), NULL);
264
265 SH_FREE(command);
266 }
267 return;
268}
269
270struct aud_list {
271 char * file;
272 struct aud_list * next;
273};
274
275struct aud_list * mark_these = NULL;
276
277static void add_this (char * file)
278{
279 struct aud_list * this = SH_ALLOC(sizeof(struct aud_list));
280 this->file = sh_util_strdup(file);
281 this->next = mark_these;
282 return;
283}
284
285static int test_exchange (struct aud_list * this, char * file)
286{
287 size_t len0 = sl_strlen(this->file);
288 size_t len1 = sl_strlen(file);
289 int ret = -1;
290
291 if (len0 == len1)
292 {
293 return strcmp(this->file, file);
294 }
295 else
296 {
297 char * s0 = SH_ALLOC(len0 + 2);
298 char * s1 = SH_ALLOC(len1 + 2);
299
300 sl_strlcpy(s0, this->file, len0 + 2);
301 sl_strlcpy(s1, file, len1 + 2);
302
303 if (s0 < s1)
304 {
305 sl_strlcat(s0, "/", len0 + 2);
306 ret = strncmp(s0, s1, len0 + 1);
307 }
308 else
309 {
310 sl_strlcat(s1, "/", len1 + 2);
311 if (0 == strncmp(s0, s1, len1 + 1))
312 {
313 SH_FREE(this->file);
314 this->file = sh_util_strdup(file);
315 ret = 0;
316 }
317 }
318 SH_FREE(s0);
319 SH_FREE(s1);
320 }
321
322 return ret;
323}
324
325void sh_audit_mark (char * file)
326{
327 struct aud_list * this = mark_these;
328
329 if (!mark_these) {
330 add_this (file);
331 return;
332 }
333
334 while (this)
335 {
336 if (0 == test_exchange(this, file))
337 return;
338 this = this->next;
339 }
340
341 add_this (file);
342 return;
343}
344
345void sh_audit_commit ()
346{
347 struct aud_list * next;
348 struct aud_list * this = mark_these;
349
350 mark_these = NULL;
351
352 while (this)
353 {
354 sh_audit_mark_int (this->file);
355 next = this->next;
356 SH_FREE(this->file);
357 SH_FREE(this);
358 this = next;
359 }
360
361}
362
363static int sh_audit_checkdaemon()
364{
365 int i;
366 static int flag = 0;
367 char command[64];
368 char * p;
369
370 if (flag != 0)
371 return -1;
372
373 if (actl_pnum >= 0)
374 return actl_pnum;
375
376 for (i = 0; i < 4; ++i)
377 {
378 if (0 == access(_(actl_paths[i]), F_OK))/* flawfinder: ignore */
379 {
380 if (0 == access(_(actl_paths[i]), X_OK))/* flawfinder: ignore */
381 {
382 actl_pnum = i;
383 break;
384 }
385 else
386 {
387 char ebuf[SH_ERRBUF_SIZE];
388 int errnum = errno;
389
390 sl_snprintf(ebuf, sizeof(ebuf),
391 _("Cannot execute auditctl - %s\n"),
392 strerror(errnum));
393 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
394 errnum, MSG_E_SUBGEN,
395 ebuf,
396 _("sh_audit_checkdaemon") );
397 flag = 1;
398 actl_pnum = -1;
399 return -1;
400 }
401 }
402 }
403
404 if (actl_pnum == -1 && flag == 0)
405 {
406 char ebuf[SH_ERRBUF_SIZE];
407 int errnum = errno;
408
409 sl_snprintf(ebuf, sizeof(ebuf),
410 _("Cannot find auditctl - %s\n"),
411 strerror(errnum));
412 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
413 errnum, MSG_E_SUBGEN,
414 ebuf,
415 _("sh_audit_checkdaemon") );
416 flag = 1;
417 actl_pnum = -1;
418 return -1;
419 }
420
421 /* We found an executable auditctl */
422
423 sl_snprintf(command, sizeof(command), _("%s -s"), _(actl_paths[actl_pnum]));
424 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
425 0, MSG_E_SUBGEN,
426 command,
427 _("sh_audit_checkdaemon") );
428 p = sh_ext_popen_str (command);
429
430 if (p)
431 {
432 int retval = -1;
433 if (strstr(p, _(" pid=0 ")))
434 {
435 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
436 0, MSG_E_SUBGEN,
437 _("Audit daemon for Linux kernel audit system is not running"),
438 _("sh_audit_checkdaemon") );
439 flag = 1;
440 actl_pnum = -1;
441 }
442 else
443 {
444 retval = actl_pnum;
445 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
446 retval, MSG_E_SUBGEN,
447 _("Audit daemon is running"),
448 _("sh_audit_checkdaemon") );
449 }
450 SH_FREE(p);
451 return retval;
452 }
453
454 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
455 errno, MSG_E_SUBGEN,
456 _("No output from auditctl -s"),
457 _("sh_audit_checkdaemon") );
458 flag = 1;
459 actl_pnum = -1;
460 return -1;
461}
462
463/* HAVE_AUPARSE_H */
464#else
465char * sh_audit_fetch (char * file, time_t time, char * result, size_t rsize)
466{
467 (void) file;
468 (void) time;
469 (void) result;
470 (void) rsize;
471
472 return 0;
473}
474void sh_audit_mark (const char * file)
475{
476 (void) file;
477 return;
478}
479void sh_audit_delete_all ()
480{
481 return;
482}
483void sh_audit_commit ()
484{
485 return;
486}
487#endif
488
489/* client || standalone */
490#endif
491
Note: See TracBrowser for help on using the repository browser.