source: trunk/src/sh_audit.c @ 452

Last change on this file since 452 was 434, checked in by katerina, 9 years ago

Fix for ticket #339 (broken audit support)

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  mark_these = this;
283  return;
284}
285
286static int test_exchange (struct aud_list * this, char * file)
287{
288  size_t len0 = sl_strlen(this->file);
289  size_t len1 = sl_strlen(file);
290  int    ret  = -1;
291
292  if (len0 == len1)
293    {
294      return strcmp(this->file, file);
295    }
296  else
297    {
298      char * s0 = SH_ALLOC(len0 + 2);
299      char * s1 = SH_ALLOC(len1 + 2);
300
301       sl_strlcpy(s0, this->file, len0 + 2); 
302       sl_strlcpy(s1, file,       len1 + 2); 
303
304       if (s0 < s1)
305         {
306           sl_strlcat(s0, "/", len0 + 2);
307           ret = strncmp(s0, s1, len0 + 1);
308         }
309       else
310         {
311           sl_strlcat(s1, "/", len1 + 2);
312           if (0 == strncmp(s0, s1, len1 + 1))
313             {
314               SH_FREE(this->file);
315               this->file = sh_util_strdup(file);
316               ret = 0;
317             }
318         }
319       SH_FREE(s0);
320       SH_FREE(s1);
321    }
322 
323  return ret;
324}
325
326void sh_audit_mark (char * file)
327{
328  struct aud_list * this = mark_these;
329
330  if (!mark_these) {
331    add_this (file);
332    return;
333  }
334
335  while (this)
336    {
337      if (0 == test_exchange(this, file))
338        return;
339      this = this->next;
340    }
341
342  add_this (file);
343  return;
344}
345
346void sh_audit_commit ()
347{
348  struct aud_list * next;
349  struct aud_list * this = mark_these;
350
351  mark_these = NULL;
352
353  while (this)
354    {
355      sh_audit_mark_int (this->file);
356      next = this->next;
357      SH_FREE(this->file);
358      SH_FREE(this);
359      this = next;
360    }
361 
362}
363
364static int sh_audit_checkdaemon()
365{
366  int  i;
367  static int flag = 0;
368  char command[64];
369  char * p;
370
371  if (flag != 0)
372    return -1;
373
374  if (actl_pnum >= 0)
375    return actl_pnum;
376
377  for (i = 0; i < 4; ++i)
378    {
379      if (0 == access(_(actl_paths[i]), F_OK))/* flawfinder: ignore */
380        {
381          if (0 == access(_(actl_paths[i]), X_OK))/* flawfinder: ignore */
382            {
383              actl_pnum = i;
384              break;
385            }
386          else
387            {
388              char ebuf[SH_ERRBUF_SIZE];
389              int  errnum = errno;
390             
391              sl_snprintf(ebuf, sizeof(ebuf), 
392                          _("Cannot execute auditctl - %s\n"), 
393                          strerror(errnum));
394              sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 
395                               errnum, MSG_E_SUBGEN,
396                               ebuf,
397                               _("sh_audit_checkdaemon") );
398              flag = 1;
399              actl_pnum = -1;
400              return -1;
401            }
402        }
403    }
404
405  if (actl_pnum == -1 && flag == 0)
406    {
407      char ebuf[SH_ERRBUF_SIZE];
408      int  errnum = errno;
409     
410      sl_snprintf(ebuf, sizeof(ebuf), 
411                  _("Cannot find auditctl - %s\n"), 
412                  strerror(errnum));
413      sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 
414                       errnum, MSG_E_SUBGEN,
415                       ebuf,
416                       _("sh_audit_checkdaemon") );
417      flag = 1;
418      actl_pnum = -1;
419      return -1;
420    }
421
422  /* We found an executable auditctl */
423
424  sl_snprintf(command, sizeof(command), _("%s -s"), _(actl_paths[actl_pnum]));
425  sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 
426                   0, MSG_E_SUBGEN,
427                   command,
428                   _("sh_audit_checkdaemon") );
429  p = sh_ext_popen_str (command);
430
431  if (p)
432    {
433      int retval = -1;
434      if (strstr(p, _(" pid=0 ")))
435        {
436          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 
437                           0, MSG_E_SUBGEN,
438                           _("Audit daemon for Linux kernel audit system is not running"),
439                           _("sh_audit_checkdaemon") );
440          flag = 1;
441          actl_pnum = -1;
442        }
443      else
444        {
445          retval = actl_pnum;
446          sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 
447                           retval, MSG_E_SUBGEN,
448                           _("Audit daemon is running"),
449                           _("sh_audit_checkdaemon") );
450        }
451      SH_FREE(p);
452      return retval;
453    }
454
455  sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 
456                   errno, MSG_E_SUBGEN,
457                   _("No output from auditctl -s"),
458                   _("sh_audit_checkdaemon") );
459  flag = 1;
460  actl_pnum = -1;
461  return -1;
462}
463
464/* HAVE_AUPARSE_H */
465#else
466char * sh_audit_fetch (char * file, time_t time, char * result, size_t rsize)
467{
468  (void) file;
469  (void) time;
470  (void) result;
471  (void) rsize;
472
473  return 0;
474}
475void sh_audit_mark (const char * file)
476{
477  (void) file;
478  return;
479}
480void sh_audit_delete_all ()
481{
482  return;
483}
484void sh_audit_commit ()
485{
486  return;
487}
488#endif
489
490/* client || standalone */
491#endif
492
Note: See TracBrowser for help on using the repository browser.