source: trunk/src/sh_audit.c@ 326

Last change on this file since 326 was 295, checked in by katerina, 14 years ago

Support for IPv6 (ticket #222).

File size: 9.5 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 command[64];
214
215 sl_snprintf(command, sizeof(command), _("%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 sh_ext_system(command);
222 }
223 return;
224}
225
226void sh_audit_mark (char * file)
227{
228 static int flushRules = 0;
229
230 int p = sh_audit_checkdaemon();
231
232 /* Flush all rules at startup.
233 */
234 if (flushRules == 0)
235 {
236 sh_audit_delete_all ();
237 flushRules = 1;
238 }
239
240 if (p >= 0)
241 {
242 size_t len = strlen(file) + 64;
243 char * command = SH_ALLOC(len);
244 char * safe;
245
246 sl_snprintf(command, len, _("%s -w %s -p wa -k samhain"),
247 _(actl_paths[p]),
248 file);
249
250 safe = sh_util_safe_name_keepspace(command);
251 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
252 0, MSG_E_SUBGEN,
253 safe,
254 _("sh_audit_mark") );
255 SH_FREE(safe);
256
257 sh_ext_system(command);
258 }
259 return;
260}
261
262
263static int sh_audit_checkdaemon()
264{
265 int i;
266 static int flag = 0;
267 char command[64];
268 char * p;
269
270 if (flag != 0)
271 return -1;
272
273 if (actl_pnum >= 0)
274 return actl_pnum;
275
276 for (i = 0; i < 4; ++i)
277 {
278 if (0 == access(_(actl_paths[i]), F_OK))/* flawfinder: ignore */
279 {
280 if (0 == access(_(actl_paths[i]), X_OK))/* flawfinder: ignore */
281 {
282 actl_pnum = i;
283 break;
284 }
285 else
286 {
287 char ebuf[SH_ERRBUF_SIZE];
288 int errnum = errno;
289
290 sl_snprintf(ebuf, sizeof(ebuf),
291 _("Cannot execute auditctl - %s\n"),
292 strerror(errnum));
293 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
294 errnum, MSG_E_SUBGEN,
295 ebuf,
296 _("sh_audit_checkdaemon") );
297 flag = 1;
298 actl_pnum = -1;
299 return -1;
300 }
301 }
302 }
303
304 if (actl_pnum == -1 && flag == 0)
305 {
306 char ebuf[SH_ERRBUF_SIZE];
307 int errnum = errno;
308
309 sl_snprintf(ebuf, sizeof(ebuf),
310 _("Cannot find auditctl - %s\n"),
311 strerror(errnum));
312 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
313 errnum, MSG_E_SUBGEN,
314 ebuf,
315 _("sh_audit_checkdaemon") );
316 flag = 1;
317 actl_pnum = -1;
318 return -1;
319 }
320
321 /* We found an executable auditctl */
322
323 sl_snprintf(command, sizeof(command), _("%s -s"), _(actl_paths[actl_pnum]));
324 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
325 0, MSG_E_SUBGEN,
326 command,
327 _("sh_audit_checkdaemon") );
328 p = sh_ext_popen_str (command);
329
330 if (p)
331 {
332 int retval = -1;
333 if (strstr(p, _(" pid=0 ")))
334 {
335 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
336 0, MSG_E_SUBGEN,
337 _("Audit daemon for Linux kernel audit system is not running"),
338 _("sh_audit_checkdaemon") );
339 flag = 1;
340 actl_pnum = -1;
341 }
342 else
343 {
344 retval = actl_pnum;
345 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
346 retval, MSG_E_SUBGEN,
347 _("Audit daemon is running"),
348 _("sh_audit_checkdaemon") );
349 }
350 SH_FREE(p);
351 return retval;
352 }
353
354 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
355 errno, MSG_E_SUBGEN,
356 _("No output from auditctl -s"),
357 _("sh_audit_checkdaemon") );
358 flag = 1;
359 actl_pnum = -1;
360 return -1;
361}
362
363/* HAVE_AUPARSE_H */
364#else
365char * sh_audit_fetch (char * file, time_t time, char * result, size_t rsize)
366{
367 (void) file;
368 (void) time;
369 (void) result;
370 (void) rsize;
371
372 return 0;
373}
374void sh_audit_mark (char * file)
375{
376 (void) file;
377 return;
378}
379void sh_audit_delete_all ()
380{
381 return;
382}
383#endif
384
385/* client || standalone */
386#endif
387
Note: See TracBrowser for help on using the repository browser.