source: trunk/src/sh_log_check.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 33.5 KB
RevLine 
[183]1
2#include "config_xor.h"
3
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <sys/types.h>
8#include <sys/stat.h>
[271]9#include <fcntl.h>
[183]10
[276]11#ifdef HAVE_DIRENT_H
12#include <dirent.h>
13#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
14#else
15#define dirent direct
16#define NAMLEN(dirent) (dirent)->d_namlen
17#ifdef HAVE_SYS_NDIR_H
18#include <sys/ndir.h>
19#endif
20#ifdef HAVE_SYS_DIR_H
21#include <sys/dir.h>
22#endif
23#ifdef HAVE_NDIR_H
24#include <ndir.h>
25#endif
26#endif
27
[271]28#if !defined(O_NONBLOCK)
29#if defined(O_NDELAY)
30#define O_NONBLOCK  O_NDELAY
31#else
32#define O_NONBLOCK  0
33#endif
34#endif
35
[183]36#ifdef USE_LOGFILE_MONITOR
37
38#undef  FIL__
39#define FIL__  _("sh_log_check.c")
40
41/* Debian/Ubuntu: libpcre3-dev */
[203]42#ifdef HAVE_PCRE_PCRE_H
43#include <pcre/pcre.h>
44#else
[183]45#include <pcre.h>
[203]46#endif
[183]47
48#include "samhain.h"
49#include "sh_pthread.h"
50#include "sh_utils.h"
[265]51#include "sh_unix.h"
[183]52#include "sh_string.h"
53#include "sh_log_check.h"
54#include "sh_log_evalrule.h"
[265]55#include "sh_log_correlate.h"
56#include "sh_log_mark.h"
57#include "sh_log_repeat.h"
[275]58#include "sh_extern.h"
[183]59
60/* List of supported logfile types, format is
[260]61 * {
62 *   "TYPE_CODE",
63 *   Reader_Callback_Function,
64 *   Parser_Callback_function,
65 *   Evaluate_Callback_Function
66 * }
[183]67 * If Reader_Callback_Function is NULL, the default (line-oriented
68 * text file) reader is used.
69 */
70struct sh_logfile_type sh_logtypes_def[] = {
[185]71    {  "SYSLOG", NULL,            sh_parse_syslog, NULL },
72    {  "SAMBA",  sh_read_samba,   sh_parse_samba,  NULL },
73    {  "APACHE", NULL,            sh_parse_apache, sh_eval_fileinfo_apache },
[183]74#if defined(HAVE_SYS_ACCT_H)
[185]75    {  "PACCT",  sh_read_pacct,   sh_parse_pacct,  NULL },
[183]76#endif
[276]77    {  "SHELL",  sh_read_shell,   sh_parse_shell,  NULL },
[183]78};
79
80/* -------------------------- Internal Stuff -------------------------- */
81
82struct logfile_record {
83  dev_t  device_id;
84  ino_t  inode;
85  fpos_t offset;
86};
87
[276]88static int    do_checkpoint_cleanup = S_FALSE;
89
[265]90static char * save_dir = NULL;
[183]91
[276]92static const char * get_save_dir(void)
[183]93{
[276]94  int retval;
[183]95
96  if (!save_dir)
97    {
[276]98      save_dir = sh_util_strdup(DEFAULT_DATAROOT);
[183]99
100      SH_MUTEX_LOCK(mutex_thread_nolog);
101      retval = tf_trust_check (save_dir, SL_YESPRIV);
102      SH_MUTEX_UNLOCK(mutex_thread_nolog);
103
104      if (retval != 0)
105        {
106          return(NULL);
107        }
108    }
[276]109  return save_dir;
110}
[183]111
[276]112static void clean_dir()
113{
114  DIR * dir;
115  struct dirent * entry;
[183]116
[276]117  const char * dirpath;
118
119  if (S_FALSE == do_checkpoint_cleanup)
120    return;
121
122  dirpath = get_save_dir();
123
124  if (dirpath)
[183]125    {
[276]126      dir = opendir(dirpath);
127      if (dir)
128        {
129          unsigned long a, b;
130          int retval;
131          char c;
132          size_t dlen = strlen(dirpath) + 1;
133          time_t now  = time(NULL);
134
135          while (NULL != (entry = readdir(dir)))
136            {
137              retval = sscanf(entry->d_name, "%lu_%lu%c", &a, &b, &c);
138
139              if (2 == retval)
140                {
141                  struct stat buf;
142                  char * path;
143                  size_t  plen = strlen(entry->d_name) + 1;
144
[481]145                  if (S_TRUE == sl_ok_adds(plen, dlen))
[276]146                    {
147                      plen += dlen;
148                      path = SH_ALLOC(plen);
149                      (void) sl_snprintf(path, plen, "%s/%s", 
150                                         dirpath,entry->d_name);
151
152                      if (0 == retry_lstat(FIL__, __LINE__, path, &buf) &&
153                          S_ISREG(buf.st_mode))
154                        {
155                          if (buf.st_mtime < now && 
156                              (now - buf.st_mtime) > 2592000) /* 30 days */
157                            {
158                              if (0 == tf_trust_check (path, SL_YESPRIV))
159                                {
160                                  unlink(path);
161                                }
162                            }
163                        }
164                    }
165                }
166            }
167          closedir(dir);
168        }
[183]169    }
[276]170}
[183]171
[276]172static char * build_path (struct sh_logfile * record)
173{
174  size_t plen;
175  char * path = NULL;
176  const char * dir = get_save_dir();
177
178  if (dir)
179    {
180      plen = strlen(dir);
181
[481]182      if (S_TRUE == sl_ok_adds(plen, 130))
[276]183        {
184          plen += 130; /* 64 + 64 + 2 */
185          path = SH_ALLOC(plen);
186          (void) sl_snprintf(path, plen, "%s/%lu_%lu", dir,
187                             (unsigned long) record->device_id, 
188                             (unsigned long) record->inode);
189        }
190    }
191
[183]192  return path;
193}
194
195static void save_pos (struct sh_logfile * record)
196{
197  char * path;
198  FILE * fd;
[276]199  mode_t mask;
[183]200  struct logfile_record save_rec;
201
202  path = build_path(record);
203
204  if (path)
205    {
[265]206      if (0 != sh_unix_check_piddir (path))
207        {
208          SH_FREE(path);
209          return;
210        }
211
[276]212      mask = umask(S_IWGRP | S_IWOTH);
[183]213      fd = fopen(path, "wb");
[276]214      (void) umask(mask);
215
[183]216      if (fd)
217        {
218          save_rec.device_id = record->device_id;
219          save_rec.inode     = record->inode;
220          memcpy(&(save_rec.offset), &(record->offset), sizeof(fpos_t));
221          if (1 != fwrite(&save_rec, sizeof(struct logfile_record), 1, fd))
222            {
[252]223              (void) sl_fclose(FIL__, __LINE__, fd);
[183]224              (void) remove(path);
225            }
226          else
227            {
[252]228              (void) sl_fclose(FIL__, __LINE__, fd);
[183]229            }
230        }
231      SH_FREE(path);
232    }
233  return;
234}
235
236static int read_pos (struct sh_logfile * record)
237{
238  int    retval = 0;
239  char * path;
240  FILE * fd;
241  struct logfile_record save_rec;
242
243  path = build_path(record);
244
245  if (path)
246    {
247      fd = fopen(path, "rb");
248      if (fd)
249        {
250          if (1 == fread(&save_rec, sizeof(struct logfile_record), 1, fd))
251            {
252              if (save_rec.device_id == record->device_id &&
253                  save_rec.inode     == record->inode)
254                {
255                  memcpy(&(record->offset),&(save_rec.offset),sizeof(fpos_t));
256                  retval = 1;
257                }
258            }
[252]259          (void) sl_fclose(FIL__, __LINE__, fd);
[183]260        }
261      SH_FREE(path);
262    }
263  return retval;
264}
265
266/*@null@*/ static struct sh_logfile * sh_watched_logs = NULL;
267
268int sh_add_watch (const char * str)
269{
270  char * filename;
271
272  unsigned int    i;
273  unsigned int    defsize;
274  struct sh_logfile_type * log_type = NULL;
275  struct sh_logfile * thisfile;
276  struct stat buf;
277
278  unsigned int nfields = 3; /* logtype:path[:regex] */
279  size_t       lengths[3];
280  char *       new = sh_util_strdup(str);
281  char **      splits = split_array(new, &nfields, ':', lengths);
282
283  if (nfields < 2 || (lengths[0] == 0 || lengths[0] >= SH_MAX_LCODE_SIZE || lengths[1] == 0))
284    {
285      sh_string * msg =  sh_string_new(0);
286      sh_string_add_from_char(msg, _("Format error: "));
287      sh_string_add_from_char(msg, str);
288     
289      SH_MUTEX_LOCK(mutex_thread_nolog);
290      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
291                      sh_string_str(msg),
292                      _("sh_add_watch"));
293      SH_MUTEX_UNLOCK(mutex_thread_nolog);
294      sh_string_destroy(&msg);
295
296      SH_FREE(new);
297      return -2;
298    }
299
300  defsize = 
301    (unsigned int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type));
302
303  for (i = 0; i < defsize; ++i)
304    {
305      if (0 == strcmp(splits[0], sh_logtypes_def[i].code))
306        {
307          log_type = &(sh_logtypes_def[i]);
308          break;
309        }
310    }
311
312  if (log_type == NULL)
313    {
314      sh_string * msg =  sh_string_new(0);
315      sh_string_add_from_char(msg, _("Unsupported log type: "));
316      sh_string_add_from_char(msg, splits[0]);
317     
318      SH_MUTEX_LOCK(mutex_thread_nolog);
319      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
320                      sh_string_str(msg),
321                      _("sh_add_watch"));
322      SH_MUTEX_UNLOCK(mutex_thread_nolog);
323      sh_string_destroy(&msg);
324
325      SH_FREE(new);
326      return -3;
327    }
328
[275]329  if (splits[1][0] != '/' && 0 != strcmp(splits[0], _("SHELL")))
[183]330    {
331      sh_string * msg =  sh_string_new(0);
332      sh_string_add_from_char(msg, _("Logfile path not absolute: "));
333      sh_string_add_from_char(msg, splits[1]);
334     
335      SH_MUTEX_LOCK(mutex_thread_nolog);
336      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
337                      sh_string_str(msg),
338                      _("sh_add_watch"));
339      SH_MUTEX_UNLOCK(mutex_thread_nolog);
340      sh_string_destroy(&msg);
341
342      SH_FREE(new);
343      return -4;
344    }
345
346  filename = /*@i@*/sh_util_strdup(splits[1]);
347  thisfile = SH_ALLOC(sizeof(struct sh_logfile));
348
349  thisfile->filename     = filename;
[276]350  if (0 == strcmp(splits[0], _("SHELL")))
[275]351    thisfile->flags        = SH_LOGFILE_NOFILE;
352  else
353    thisfile->flags        = SH_LOGFILE_REWIND;
[183]354  thisfile->inode        = 0;
355  thisfile->device_id    = 0;
356  thisfile->fp           = NULL;
357  if (log_type->get_record)
358    thisfile->get_record   = log_type->get_record;
359  else
360    thisfile->get_record   = sh_default_reader;
361  thisfile->parse_record = log_type->parse_record;
362
363  /* An optional regex for parsing the file. The result
364   * 'fileinfo' should contain info about host/time position.
365   */
366  if (log_type->eval_fileinfo)
367    {
368      if (nfields == 3 && lengths[2] > 0)
369        {
370          thisfile->fileinfo     = log_type->eval_fileinfo(splits[2]);
371
372          if (thisfile->fileinfo == NULL)
373            {
374              sh_string * msg =  sh_string_new(0);
375              sh_string_add_from_char(msg, _("Logfile format description not recognized: "));
376              sh_string_add_from_char(msg, splits[2]);
377             
378              SH_MUTEX_LOCK(mutex_thread_nolog);
379              sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
380                              sh_string_str(msg),
381                              _("sh_add_watch"));
382              SH_MUTEX_UNLOCK(mutex_thread_nolog);
383              sh_string_destroy(&msg);
384
385              SH_FREE(filename);
386              SH_FREE(thisfile);
387              SH_FREE(new);
388              return -1;
389            }
390        }
391      else
392        {
393          sh_string * msg =  sh_string_new(0);
394          sh_string_add_from_char(msg, _("Logfile format description missing: "));
395          sh_string_add_from_char(msg, splits[1]);
396         
397          SH_MUTEX_LOCK(mutex_thread_nolog);
398          sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
399                          sh_string_str(msg),
400                          _("sh_add_watch"));
401          SH_MUTEX_UNLOCK(mutex_thread_nolog);
402          sh_string_destroy(&msg);
403
404          SH_FREE(filename);
405          SH_FREE(thisfile);
406          SH_FREE(new);
407          return -1;
408        }
409    }
410  else
411    {
412      thisfile->fileinfo     = NULL;
413    }
414  thisfile->next         = sh_watched_logs;
415
416  /* Try reading saved offset. On success clear rewind flag.
417   */
[275]418  if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0)
[183]419    {
[275]420      if (0 == stat(thisfile->filename, &buf))
421        {
422          if (S_ISREG(buf.st_mode)
[271]423#ifdef S_ISLNK
[275]424              || S_ISLNK(buf.st_mode)
[271]425#endif
[275]426              )
[271]427            {
[275]428              thisfile->inode     = buf.st_ino;
429              thisfile->device_id = buf.st_dev;
430             
431              if (0 != read_pos(thisfile))
432                {
433                  thisfile->flags &= ~SH_LOGFILE_REWIND;
434                }
[271]435            }
[275]436          else if (S_ISFIFO(buf.st_mode))
437            {
438              thisfile->inode      = buf.st_ino;
439              thisfile->device_id  = buf.st_dev;
440              thisfile->flags     |= SH_LOGFILE_PIPE;
441            }
[183]442        }
[275]443      else
[271]444        {
[275]445          sh_string * msg =  sh_string_new(0);
446          sh_string_add_from_char(msg, _("Logfile is not a regular file, link, or named pipe: "));
447          sh_string_add_from_char(msg, splits[1]);
448         
449          SH_MUTEX_LOCK(mutex_thread_nolog);
450          sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
451                          sh_string_str(msg),
452                          _("sh_add_watch"));
453          SH_MUTEX_UNLOCK(mutex_thread_nolog);
454          sh_string_destroy(&msg);
455         
456          SH_FREE(filename);
457          SH_FREE(thisfile);
458          SH_FREE(new);
459          return -1;
[271]460        }
[183]461    }
462
463  sh_watched_logs        = thisfile;
464
465  SH_FREE(new);
466  return 0;
467}
468
469void sh_dump_watches()
470{
471  struct sh_logfile * thisfile;
472
473  while (sh_watched_logs)
474    {
475      thisfile        = sh_watched_logs;
476      sh_watched_logs = thisfile->next;
477
[275]478      if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0 &&
479          (thisfile->flags & SH_LOGFILE_PIPE) == 0)
[271]480        {
481          save_pos(thisfile);
482        }
[183]483
[275]484      if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0)
485        {
486          if (thisfile->fp)
487            sl_fclose(FIL__, __LINE__, thisfile->fp);
488        }
489
[183]490      if (thisfile->filename)
491        SH_FREE(thisfile->filename);
492      SH_FREE(thisfile);
493    }
494  return;
495}
496
497/* This variable is not used anywhere. It only exist
498 * to assign &new to them, which keeps gcc from
499 * putting it into a register, and avoids the 'clobbered
500 * by longjmp' warning. And no, 'volatile' proved insufficient.
501 */
[481]502void * sh_dummy_502_thisfile = NULL;
[183]503
504void sh_check_watches()
505{
506  struct sh_logrecord * logrecord;
507  struct sh_logfile * thisfile = sh_watched_logs;
508  sh_string * record = sh_string_new(0);
509  char * tmp;
510
511  /* Take the address to keep gcc from putting them into registers.
512   * Avoids the 'clobbered by longjmp' warning.
513   */
[481]514  sh_dummy_502_thisfile = (void*) &thisfile;
[183]515
516  while (thisfile)
517    {
[271]518      volatile size_t count = 0;
519
[183]520      SH_MUTEX_LOCK(mutex_thread_nolog);
521      tmp = sh_util_safe_name (thisfile->filename);
522      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKS,
523                      tmp);
524      SH_FREE(tmp);
525      SH_MUTEX_UNLOCK(mutex_thread_nolog);
526
527      for (;;) {
528
529        record = thisfile->get_record(record, thisfile);
530
531        if (record)
532          {
533            logrecord = thisfile->parse_record(record, thisfile->fileinfo);
534            ++count;
535
536            if (logrecord)
537              {
538                logrecord->filename = thisfile->filename;
[185]539               
540                /* Don't report if 'init', just set file pointer
541                 */
542                if (sh.flag.checkSum != SH_CHECK_INIT)
543                  {
544                    sh_eval_process_msg(logrecord);
545                  }
[183]546
547                if (logrecord->message) 
548                  sh_string_destroy(&(logrecord->message));
549                if (logrecord->host)
550                  sh_string_destroy(&(logrecord->host));
[185]551                if (logrecord->timestr)
552                  sh_string_destroy(&(logrecord->timestr));
[183]553                SH_FREE(logrecord);
554              }
555          }
556        else
557          {
[185]558            record = sh_string_new(0);
[183]559            break;
560          }
561      }
562
563      SH_MUTEX_LOCK(mutex_thread_nolog);
564      tmp = sh_util_safe_name (thisfile->filename);
565      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKE,
566                      tmp, (unsigned long)count);
567      SH_FREE(tmp);
568      SH_MUTEX_UNLOCK(mutex_thread_nolog);
569
570      thisfile = thisfile->next;
571    }
572  sh_string_destroy(&record);
573  return;
574}
575
576/********************************************************
577 * Search rotated logfile
578 */
[425]579extern char * sh_rotated_log_search(const char * path, struct stat * buf);
[183]580
581
582/* Open file, position at stored offset
583 */
584int sh_open_for_reader (struct sh_logfile * logfile)
585{
586  struct stat buf;
587  sh_string * filename;
588
589  /* check whether file exists, get inode to check for
590   * logfile rotation
591   */
592  if (0 != retry_stat(FIL__, __LINE__, logfile->filename, &buf))
593    {
594      char * tmp;
595
596      SH_MUTEX_LOCK(mutex_thread_nolog);
597      tmp = sh_util_safe_name (logfile->filename);
598      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_MISS,
599                      tmp);
600      SH_FREE(tmp);
601      SH_MUTEX_UNLOCK(mutex_thread_nolog);
602
603      memset (&(logfile->offset), '\0', sizeof(fpos_t));
604      logfile->flags |= SH_LOGFILE_REWIND;
605      return 0;
606    }
607
608  filename = sh_string_new(0);
609  (void) sh_string_set_from_char (filename, logfile->filename);
610
611  /* detect and handle logfile rotation
612   */
[271]613  if (logfile->inode != buf.st_ino && 
614      logfile->inode != 0 &&
615      !S_ISFIFO(buf.st_mode))
[183]616    {
617      /* Case 1) We have dealt with the moved file already.
618       *         Clear the moved flag, set the rewind flag,
619       *         fix logfile->inode.
620       */
621      if ((logfile->flags & SH_LOGFILE_MOVED) != 0)
622        {
623          /* done with rotated file, start with current file
624           */
625          memset (&(logfile->offset), '\0', sizeof(fpos_t));
626          logfile->flags    |= SH_LOGFILE_REWIND;
627          logfile->flags    &= ~SH_LOGFILE_MOVED;
628          logfile->inode     = buf.st_ino;
629          logfile->device_id = buf.st_dev;
630        }
631
632      /* Case 2) Searching for rotated file.
633       *         If found:     set the moved flag, fix path for fopen.
634       *         If not found: set the rewind flag, fix logfile->inode.
635       */
636      else
637        {
638          char *oldfile = sh_rotated_log_search(logfile->filename, &buf);
639
640          if (NULL != oldfile)
641            {
642              (void) sh_string_set_from_char (filename, oldfile);
643              SH_FREE(oldfile);
644              logfile->flags |= SH_LOGFILE_MOVED;
645            }
646          else
647            {
648              memset (&(logfile->offset), '\0', sizeof(fpos_t));
649              logfile->flags    |= SH_LOGFILE_REWIND;
650              logfile->inode     = buf.st_ino;
651              logfile->device_id = buf.st_dev;
652            }
653        }
654    }
655
656  /* open file
657   */
[271]658  if (!S_ISFIFO(buf.st_mode))
659    {
660      logfile->fp = fopen(filename->str, "r");
661    }
662  else
663    {
664      int fd_temp = open (filename->str, O_RDONLY|O_NONBLOCK);
665
666      if (fd_temp >= 0)
667        {
668          logfile->fp = fdopen(fd_temp, "r");
669        }
670    }
671
[183]672  if (!logfile->fp)
673    {
674      char * tmp;
675
676      SH_MUTEX_LOCK(mutex_thread_nolog);
677      tmp = sh_util_safe_name (logfile->filename);
678      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EOPEN,
679                      tmp);
680      SH_FREE(tmp);
681      SH_MUTEX_UNLOCK(mutex_thread_nolog);
682
683      sh_string_destroy(&filename);
684      return 0;
685    }
686
687  sh_string_destroy(&filename);
688 
[271]689  if ((logfile->flags & SH_LOGFILE_PIPE) == 0)
[183]690    {
[271]691      if ((logfile->flags & SH_LOGFILE_REWIND) != 0)
[183]692        {
693          rewind(logfile->fp);
694          fgetpos(logfile->fp, &(logfile->offset));
[271]695          logfile->flags &= ~SH_LOGFILE_REWIND;
[183]696        }
[271]697      else
698        {
699          /* file too short
700           */
701          if (0 != fsetpos(logfile->fp, &(logfile->offset)))
702            {
703              rewind(logfile->fp);
704              fgetpos(logfile->fp, &(logfile->offset));
705            }
706        }
[183]707    }
708
709  return 1;
710}
711
712/******************************************************
713 *  Default reader for ascii text files
714 */
715sh_string * sh_default_reader (sh_string * s, struct sh_logfile * logfile)
716{
[275]717  volatile int         status;
[183]718  char * tmp;
719
720 start_read:
721
722  if (logfile->fp)
723    {
724      /* Result cannot be larger than 8192, thus cast is ok
725       */
726      status = (int) sh_string_read(s, logfile->fp, 8192);
727      if (status <= 0)
728        {
729          fgetpos(logfile->fp, &(logfile->offset));
[252]730          sl_fclose(FIL__, __LINE__, logfile->fp);
[183]731          logfile->fp = NULL;
732          sh_string_destroy(&s);
[271]733          if (status == 0 || (logfile->flags & SH_LOGFILE_PIPE) != 0)
[183]734            {
735              return NULL;
736            }
737
738          SH_MUTEX_LOCK(mutex_thread_nolog);
739          tmp = sh_util_safe_name (logfile->filename);
740          sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
741                          tmp);
742          SH_FREE(tmp);
743          SH_MUTEX_UNLOCK(mutex_thread_nolog);
744
745          return NULL;
746        }
747      return s;
748    }
749
750  if (0 != sh_open_for_reader(logfile))
751    goto start_read;
752
753  return NULL;
754}
755
[276]756struct task_entry
[275]757{
758  sh_tas_t task;
[276]759  struct task_entry * next;
760};
[275]761
[276]762static struct task_entry * tasklist = NULL;
763
764static struct task_entry * task_find(FILE * fp)
765{
766  struct task_entry * entry = tasklist;
767  while (entry)
768    {
769      if (entry->task.pipe == fp)
770        return (entry);
771      entry = entry->next;
772    }
773  return NULL;
774}
775 
776static void task_remove(struct task_entry * task)
777{
778  struct task_entry * entry = tasklist;
779  struct task_entry * prev  = tasklist;
780
781  while (entry)
782    {
783      if (entry == task)
784        {
785          if (entry == tasklist)
786            {
787              tasklist = entry->next;
788              SH_FREE(entry);
789              return;
790            }
791          else
792            {
793              prev->next = entry->next;
794              SH_FREE(entry);
795              return;
796            }
797        }
798      prev  = entry;
799      entry = entry->next;
800    }
801  return;
802}
803 
804static void task_add(struct task_entry * entry)
805{
806  entry->next = tasklist;
807  tasklist    = entry;
808  return;
809}
810 
811sh_string * sh_command_reader (sh_string * s, struct sh_logfile * logfile)
812{
813  struct task_entry * entry;
814
815  volatile int        status;
[275]816  char * tmp;
817
818 start_read:
819
820  if (logfile->fp)
821    {
822      /* Result cannot be larger than 8192, thus cast is ok
823       */
824      status = (int) sh_string_read(s, logfile->fp, 8192);
825
826      if (status <= 0)
827        {
[276]828          entry = task_find(logfile->fp);
829          sh_ext_pclose (&(entry->task));
830          task_remove(entry);
831
[275]832          logfile->fp = NULL;
833          sh_string_destroy(&s);
834
835          if (status == 0)
836            {
837              return NULL;
838            }
839
840          SH_MUTEX_LOCK(mutex_thread_nolog);
841          tmp = sh_util_safe_name (logfile->filename);
842          sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
843                          tmp);
844          SH_FREE(tmp);
845          SH_MUTEX_UNLOCK(mutex_thread_nolog);
846
847          return NULL;
848        }
849      return s;
850    }
851
[276]852  entry = SH_ALLOC(sizeof(struct task_entry));
853
[415]854  status = sh_ext_popen_init (&(entry->task), logfile->filename, logfile->filename, NULL);
[275]855  if (0 == status)
856    {
[276]857      task_add(entry);
858      logfile->fp = entry->task.pipe;
[275]859      goto start_read;
860    }
861  else
862    {
[276]863      SH_FREE(entry);
[275]864      SH_MUTEX_LOCK(mutex_thread_nolog);
865      sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN, 
866                      _("Could not open pipe"), _("sh_command reader"));
867      SH_MUTEX_UNLOCK(mutex_thread_nolog);
868    }
869
870  return NULL;
871}
872
[183]873/******************************************************
[185]874 *  Reader for continued text files
875 */
876sh_string * sh_cont_reader (sh_string * s, struct sh_logfile * logfile, char*cont)
877{
878  int         status;
879  char      * tmp;
880  sh_string * str;
881  int         remain = 8192;
882  int         count  = 0;
883
884  if (!sh_string_truncate(s, 0))
885    return NULL;
886
887 start_read:
888
889  if (logfile->fp)
890    {
891      str = sh_string_new(0);
892
893      /* Result cannot be larger than 8192, thus cast is ok
894       */
895      status = (int) sh_string_read(str, logfile->fp, 8192);
896
897      if (status > 0)
898        {
899         
900          do {
901            s       = sh_string_add (s, str);
902            count  += status;
903            remain -= status;
904
905            if (remain <= 0)
906              {
907                return s;
908              }
909
910            status = (int) sh_string_read_cont(str, logfile->fp, count, cont);
911
912            if (status == 0)
913              {
914                return s;
915              }
916          }
917          while (status > 0);
918        }
919
920      if (status <= 0)
921        {
922          fgetpos(logfile->fp, &(logfile->offset));
[252]923          sl_fclose(FIL__, __LINE__, logfile->fp);
[185]924          logfile->fp = NULL;
925          sh_string_destroy(&s);
[271]926          if (status == 0 || (logfile->flags & SH_LOGFILE_PIPE) != 0)
[185]927            {
928              return NULL;
929            }
930
931          SH_MUTEX_LOCK(mutex_thread_nolog);
932          tmp = sh_util_safe_name (logfile->filename);
933          sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
934                          tmp);
935          SH_FREE(tmp);
936          SH_MUTEX_UNLOCK(mutex_thread_nolog);
937
938          return NULL;
939        }
940
941      return s;
942    }
943
944  if (0 != sh_open_for_reader(logfile))
945    goto start_read;
946
947  return NULL;
948}
949
950/******************************************************
[183]951 *  Reader for binary files
952 */
[362]953sh_string * sh_binary_reader (void * s, size_t size, 
954                              struct sh_logfile * logfile)
[183]955{
956  size_t         status;
957
958 start_read:
959
960  if (logfile->fp)
961    {
962
963      status = fread(s, size, 1, logfile->fp);
964
965      if (status != 1)
966        {
[362]967          memset(s, '\0', size);
[271]968          if (ferror(logfile->fp) && (logfile->flags & SH_LOGFILE_PIPE) == 0)
[183]969            {
970              char * tmp;
971              SH_MUTEX_LOCK(mutex_thread_nolog);
972              tmp = sh_util_safe_name (logfile->filename);
973              sh_error_handle((-1), FIL__, __LINE__, errno, MSG_LOGMON_EREAD,
974                              tmp);
975              SH_FREE(tmp);
976              SH_MUTEX_UNLOCK(mutex_thread_nolog);
977            }
978          fgetpos(logfile->fp, &(logfile->offset));
[252]979          sl_fclose(FIL__, __LINE__, logfile->fp);
[183]980          logfile->fp = NULL;
981          return NULL;
982        }
983      return s;
984    }
985
986  if (0 != sh_open_for_reader(logfile))
987    goto start_read;
988
989  return NULL;
990}
991
992
993
994/**********************************************************
995 *
996 * Utilities
997 *
998 **********************************************************/
999
[265]1000/* Return current year, unless that would result
1001 * in a date far in the future. If that happens,
1002 * return last year.
1003 */
1004static int year_guess (struct tm * btime)
1005{
1006  int           year;
1007  struct tm     ts;
1008  time_t        now    = time(NULL);
1009  time_t        check;
1010
1011  memcpy(&ts, localtime(&now), sizeof(struct tm));
1012  year = ts.tm_year;
1013
1014  /* Check result to detect year wrap
1015   * (logfile entry from last year).
1016   */
1017  btime->tm_year = year;
1018  check = mktime(btime);
1019  if (check > (now + (86400*30)))
1020    --year;
1021
1022  return year;
1023}
1024
[183]1025time_t conv_timestamp (struct tm * btime, 
1026                       struct tm * old_tm, time_t * old_time)
1027{
1028  time_t timestamp;
1029  long   offtime;
1030
1031  /* timestamp - mktime is slooow, thus cache result
1032   */
1033  if (btime->tm_isdst == old_tm->tm_isdst &&
1034      btime->tm_year  == old_tm->tm_year  &&
1035      btime->tm_mon   == old_tm->tm_mon   &&
1036      btime->tm_mday  == old_tm->tm_mday)
1037    {
1038      offtime = 
1039        (btime->tm_hour - old_tm->tm_hour) * 3600 +
1040        (btime->tm_min  - old_tm->tm_min)  * 60   +
1041        (btime->tm_sec  - old_tm->tm_sec);
[265]1042
[183]1043      *old_time += offtime;
1044      memcpy(old_tm, btime, sizeof(struct tm));
1045      timestamp = *old_time;
1046    }
1047  else
1048    {
[265]1049      int year_btime = btime->tm_year;
1050
1051      if (btime->tm_year == 0)
1052        btime->tm_year = year_guess(btime);
[183]1053      timestamp = mktime(btime);
[265]1054      btime->tm_year = year_btime;
[183]1055      *old_time  = timestamp;
1056      memcpy(old_tm, btime, sizeof(struct tm));
1057    }
1058  return timestamp;
1059}
1060
1061/*********************************************************
1062 *
1063 * MODULE STUFF
1064 *
1065 *********************************************************/
1066#include "sh_modules.h"
1067
1068SH_MUTEX_STATIC(mutex_logmon_check, PTHREAD_MUTEX_INITIALIZER);
1069
1070static int ShLogmonActive        = S_FALSE;
1071#define SH_LOGMON_INTERVAL 10
1072static time_t sh_logmon_interval = SH_LOGMON_INTERVAL;
1073
1074int sh_log_check_init (struct mod_type * arg)
1075{
[257]1076#if !defined(HAVE_PTHREAD)
1077  (void) arg;
1078#endif
1079
[183]1080  if (ShLogmonActive == S_FALSE)
1081    return SH_MOD_FAILED;
1082#ifdef HAVE_PTHREAD
1083  if (arg != NULL && arg->initval < 0 &&
1084      (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
1085    {
1086      if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
1087        return SH_MOD_THREAD;
1088      else
1089        return SH_MOD_FAILED;
1090    }
[335]1091  else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
1092           (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
1093    {
1094      return SH_MOD_THREAD;
1095    }
[183]1096#endif
1097  if (sh_watched_logs != NULL)
1098    return 0;
1099
1100  return -1;
1101}
1102
1103int sh_log_check_timer(time_t tcurrent) 
1104{
1105  static time_t lastcheck = 0;
1106
1107  SL_ENTER(_("sh_log_check_timer"));
1108  if ((time_t) (tcurrent - lastcheck) >= sh_logmon_interval)
1109    {
1110      lastcheck  = tcurrent;
1111      SL_RETURN((-1), _("sh_log_check_timer"));
1112    }
1113  SL_RETURN(0, _("sh_log_check_timer"));
1114}
1115
1116
1117int sh_log_check_check(void) 
1118{
1119  int status = 0;
1120
1121  SL_ENTER(_("sh_log_check_check"));
1122
1123  SH_MUTEX_LOCK(mutex_logmon_check);
1124
1125  status = 0;
1126
1127  if( ShLogmonActive != S_FALSE )
1128    {
1129      sh_check_watches();
[260]1130      sh_keep_match();
[265]1131      sh_log_mark_check();
[276]1132      clean_dir();
[183]1133    }
1134  SH_MUTEX_UNLOCK(mutex_logmon_check);
1135
1136  SL_RETURN(status, _("sh_log_check_check"));
1137}
1138
1139int sh_log_check_reconf(void) 
1140{
1141  int status = 0;
1142
1143  SL_ENTER(_("sh_log_check_check"));
1144
1145  SH_MUTEX_LOCK(mutex_logmon_check);
1146
1147  ShLogmonActive     = S_FALSE;
1148  sh_logmon_interval = SH_LOGMON_INTERVAL;
1149  sh_dump_watches();
1150  sh_eval_cleanup();
1151
1152  SH_MUTEX_UNLOCK(mutex_logmon_check);
1153
1154  SL_RETURN(status, _("sh_log_check_check"));
1155}
1156
1157int sh_log_check_cleanup(void) 
1158{
[265]1159  sh_log_mark_destroy();
[183]1160  return sh_log_check_reconf();
1161}
1162
1163/*********************  OPTIONS **********************/
1164
1165static int sh_logmon_set_active  (const char *str);
[276]1166static int sh_logmon_set_clean  (const char *str);
[183]1167static int sh_logmon_set_interval(const char *str);
1168static int sh_logmon_add_watch (const char * str);
1169static int sh_logmon_add_group (const char * str);
1170static int sh_logmon_end_group (const char * str);
1171static int sh_logmon_add_host  (const char * str);
1172static int sh_logmon_end_host  (const char * str);
1173static int sh_logmon_add_queue (const char * str);
1174static int sh_logmon_add_rule  (const char * str);
1175extern int sh_set_hidepid(const char *s);
[265]1176static int sh_logmon_set_save_dir(const char *s);
[183]1177
1178sh_rconf sh_log_check_table[] = {
1179    {
1180        N_("logmonactive"),
1181        sh_logmon_set_active,
1182    },
1183    {
1184        N_("logmoninterval"),
1185        sh_logmon_set_interval,
1186    },
1187    {
[276]1188        N_("logmonclean"),
1189        sh_logmon_set_clean,
1190    },
1191    {
[183]1192        N_("logmonwatch"),
1193        sh_logmon_add_watch,
1194    },
1195    {
1196        N_("logmonqueue"),
1197        sh_logmon_add_queue,
1198    },
1199    {
1200        N_("logmongroup"),
1201        sh_logmon_add_group,
1202    },
1203    {
1204        N_("logmonendgroup"),
1205        sh_logmon_end_group,
1206    },
1207    {
1208        N_("logmonhost"),
1209        sh_logmon_add_host,
1210    },
1211    {
1212        N_("logmonendhost"),
1213        sh_logmon_end_host,
1214    },
1215    {
1216        N_("logmonrule"),
1217        sh_logmon_add_rule,
1218    },
1219    {
1220        N_("logmonhidepid"),
1221        sh_set_hidepid,
1222    },
1223    {
[265]1224        N_("logmonsavedir"),
1225        sh_logmon_set_save_dir,
1226    },
1227    {
1228        N_("logmonmarkseverity"),
[349]1229        sh_log_set_mark_severity,
[265]1230    },
1231    {
1232        N_("logmonburstthreshold"),
1233        sh_repeat_set_trigger,
1234    },
1235    {
1236        N_("logmonburstqueue"),
1237        sh_repeat_set_queue,
1238    },
1239    {
1240        N_("logmonburstcron"),
1241        sh_repeat_set_cron,
1242    },
1243    {
[358]1244        N_("logmondeadtime"),
1245        sh_keep_deadtime,
1246    },
1247    {
[183]1248        NULL,
1249        NULL
1250    }
1251};
1252
1253/* Decide if we're active.
1254 */
1255static int sh_logmon_set_active(const char *str) 
1256{
1257  int value;
1258   
1259  SL_ENTER(_("sh_logmon_set_active"));
1260
1261  value = sh_util_flagval(str, &ShLogmonActive);
1262
1263  SL_RETURN((value), _("sh_logmon_set_active"));
1264}
1265
[276]1266/* Decide if we're active.
1267 */
1268static int sh_logmon_set_clean(const char *str) 
1269{
1270  int value;
1271   
1272  SL_ENTER(_("sh_logmon_set_active"));
1273
1274  value = sh_util_flagval(str, &do_checkpoint_cleanup);
1275
1276  SL_RETURN((value), _("sh_logmon_set_active"));
1277}
1278
[265]1279static int sh_logmon_set_save_dir(const char *str) 
1280{
1281  int retval = -1;
1282   
1283  SL_ENTER(_("sh_logmon_set_save_dir"));
1284
1285  if (str && str[0] == '/')
1286    {
1287      if (save_dir)
1288        {
1289          SH_FREE(save_dir);
1290          save_dir = NULL;
1291        }
1292      save_dir = sh_util_strdup(str);
1293      retval = 0;
1294    }
1295
1296  SL_RETURN((retval), _("sh_logmon_set_save_dir"));
1297}
1298
[183]1299static int sh_logmon_set_interval (const char * c)
1300{
1301  int retval = 0;
1302  long val;
1303
1304  SL_ENTER(_("sh_logmon_set_interval"));
1305  val = strtol (c, (char **)NULL, 10);
1306  if (val <= 0)
1307    {
1308      SH_MUTEX_LOCK(mutex_thread_nolog);
1309      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1310                       _("log monitoring interval"), c);
1311      SH_MUTEX_UNLOCK(mutex_thread_nolog);
1312      retval = -1;
1313    }
[362]1314  else
1315    {
1316      sh_logmon_interval = (time_t) val;
1317    }
1318  SL_RETURN(retval, _("sh_logmon_set_interval"));
[183]1319}
1320
1321/* Add a watch on a logfile.
1322 * Format: TYPE : Filename [: File_Format]
1323 */
1324static int sh_logmon_add_watch (const char * str)
1325{
1326  return sh_add_watch(str);
1327}
1328
1329/* Add a host.
1330 * Format: Name_Regex
1331 */
1332static int sh_logmon_add_host (const char * str)
1333{
1334  return sh_eval_hadd(str);
1335}
1336
1337/* End a host.
1338 * Format: Name
1339 */
1340static int sh_logmon_end_host (const char * str)
1341{
1342  (void) str;
1343  return sh_eval_hend(NULL);
1344}
1345
1346/* Add a group of rules.
1347 * Groups can be under hosts, but not vice versa.
1348 * Format: Name : Prefix_Regex
1349 */
1350static int sh_logmon_add_group (const char * str)
1351{
1352  return sh_eval_gadd(str);
1353}
1354
1355/* End a group of rules.
1356 * Format: Name
1357 */
1358static int sh_logmon_end_group (const char * str)
1359{
1360  (void) str;
1361  return sh_eval_gend(NULL);
1362}
1363
1364/* Define a reporting queue.
[272]1365 * Format: Label : [Interval] : TYPE : Severity[:alias]
[183]1366 * TYPE must be 'report' or 'sum'
1367 * Interval is ignored for TYPE='report'
1368 */
1369static int sh_logmon_add_queue (const char * str)
1370{
1371  return sh_eval_qadd(str);
1372}
1373
1374/* Define a check rule.
[260]1375 * Format: [KEEP(seconds,label):]Queue_Label : Regex
1376 * KEEP indicates that we keep the label, to perform
1377 *      correlation matching
[183]1378 */
1379static int sh_logmon_add_rule (const char * str)
1380{
1381  return sh_eval_radd(str);
1382}
1383
1384
1385#if 0
1386
1387/* >>>>>>>>>>>  MAIN <<<<<<<<<<<<<<<<<<< */
1388
1389int main (int argc, char * argv[])
1390{
1391  int status, i;
1392  FILE * fp;
1393  sh_string * s = NULL;
1394  static char template[] = "/tmp/xtest.XXXXXX";
1395
1396  /* pacct */
1397  status = sh_add_watch("PACCT:/var/log/account/pacct");
1398  sh_check_watches();
1399  sh_dump_watches();
1400  exit(0);
1401
1402  /* apache log */
1403  sh_eval_gadd("four_o_four:404");
1404  sh_eval_qadd("test:1:sum:7");
1405  sh_eval_radd("test:^(\\d+.\\d+.\\d+.\\d+).*");
1406  sh_eval_gend(NULL);
1407  sh_eval_radd("trash:.*");
1408  status = sh_add_watch("APACHE:/var/log/apache2/access.log:combined");
1409  sh_check_watches();
1410  sh_dump_watches();
1411  exit(0);
1412
1413  /* logfile */
1414  sh_set_hidepid(1);
1415  sh_eval_hadd("hslxmsrv1");
1416  sh_eval_gadd("postfix:postfix");
1417  sh_eval_qadd("test::report:7");
1418  sh_eval_radd("test:postfix/smtpd: disconnect from localhost.*");
1419  sh_eval_radd("trash:postfix/smtpd: disconnect.*");
1420  sh_eval_hadd("hspc05");
1421  sh_eval_gadd("cron:CRON");
1422  sh_eval_qadd("test:1:sum:7");
1423  sh_eval_radd("test:CRON: PAM adding faulty module: (/lib/security/.*.so)");
1424  sh_eval_radd("trash:.*");
1425  status = sh_add_watch("SYSLOG:/var/log/messages");
1426  sh_check_watches();
1427
1428  sh_dump_watches();
1429  exit(0);
1430
1431  printf("%d types\n",
1432         (int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type)));
1433
1434  /* test sh_add_watch
1435   */
1436  status = sh_add_watch("");
1437  printf("%2d: zero length, expect -1\n", status);
1438  status = sh_add_watch(NULL);
1439  printf("%2d: NULL, expect -2\n", status);
1440  status = sh_add_watch("0123456789012345:/var/log/messages");
1441  printf("%2d: long, expect -2\n", status);
1442  status = sh_add_watch("012345678901234:/var/log/messages");
1443  printf("%2d: exact length, expect -3\n", status);
1444  status = sh_add_watch("01234567890123:56789");
1445  printf("%2d: short length, expect -3\n", status);
1446  status = sh_add_watch("SYSLOG:var/log/messages");
1447  printf("%2d: short badpath, expect -4\n", status);
1448  status = sh_add_watch("SYSLOG:/var/log/messages");
[237]1449  /* status = sh_add_watch("SYSLOG:/var/log/dpkg.log.1"); */
[183]1450  printf("%2d: short path ok, expect 0\n", status);
1451
1452  /* test sh_string_read
1453   */
1454  s = sh_string_new();
1455
1456  status = /*@i@*/mkstemp(template);
1457
1458  if (status < 0) {
1459    fprintf(stderr, "error in mkstemp!\n"); exit(EXIT_FAILURE); }
1460
1461  fp = fdopen(status, "r+");
1462  if (!fp) {
1463    fprintf(stderr, "error in fdopen!\n"); exit(EXIT_FAILURE); }
1464
[237]1465  for (i = 0; i <  80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
1466  for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
1467  for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
1468  for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
1469  for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
[183]1470  for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1471  for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1472  for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1473  for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
1474
1475  rewind(fp);
1476
1477  for (i = 0; i < 9; ++i)
1478    {
1479      status = (int) sh_string_read(s, fp, 120);
1480      printf("%d: status = %d, len = %d, size = %d\n",
1481             i, status, (int)s->len, (int)s->siz);
1482      if (status == -2)
1483        (void) sh_string_read(s, fp, 240);
1484      else
1485        printf("%s\n", s->str);
1486    }
1487
1488  rewind(fp);
1489
1490  (void) sh_string_truncate(s, 0);
1491
1492  for (i = 0; i < 9; ++i)
1493    {
1494      status = (int) sh_string_read(s, fp, 240);
1495      printf("%d: status = %d, len = %d, size = %d\n",
1496             i, status, (int)s->len, (int)s->siz);
1497      if (status == -2)
1498        (void) sh_string_read(s, fp, 240);
1499      else
1500        {
1501          for (status = 0; status < (int)s->len; ++status)
1502            {
1503              if (s->str[status] != 'a')
1504                {
1505                  break;
1506                }
1507            }
1508          printf("%d %s\n", status, s->str);
1509        }
1510    }
1511
[252]1512  sl_fclose(FIL__, __LINE__, fp); remove(template);
[183]1513
1514
1515
1516  return 0;
1517}
1518#endif
1519
1520/* #ifdef USE_LOGFILE_MONITOR */
1521#endif
1522
Note: See TracBrowser for help on using the repository browser.