suricata
util-debug.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22  *
23  * Debug utility functions
24  */
25 
26 #include "suricata-common.h"
27 #include "threads.h"
28 #include "util-debug.h"
29 #include "util-error.h"
30 #include "util-enum.h"
31 #include "util-debug-filters.h"
32 
33 #include "decode.h"
34 #include "detect.h"
35 #include "packet-queue.h"
36 #include "threadvars.h"
37 #include "output.h"
38 
39 #include "tm-queuehandlers.h"
40 #include "tm-queues.h"
41 #include "tm-threads.h"
42 
43 #include "util-unittest.h"
44 #include "util-syslog.h"
45 
46 #ifdef HAVE_RUST
47 #include "rust-log-gen.h"
48 #endif
49 
50 #include "conf.h"
51 
52 /* holds the string-enum mapping for the enums held in the table SCLogLevel */
54  { "Not set", SC_LOG_NOTSET},
55  { "None", SC_LOG_NONE },
56  { "Emergency", SC_LOG_EMERGENCY },
57  { "Alert", SC_LOG_ALERT },
58  { "Critical", SC_LOG_CRITICAL },
59  { "Error", SC_LOG_ERROR },
60  { "Warning", SC_LOG_WARNING },
61  { "Notice", SC_LOG_NOTICE },
62  { "Info", SC_LOG_INFO },
63  { "Perf", SC_LOG_PERF },
64  { "Config", SC_LOG_CONFIG },
65  { "Debug", SC_LOG_DEBUG },
66  { NULL, -1 }
67 };
68 
69 /* holds the string-enum mapping for the enums held in the table SCLogOPIface */
71  { "Console", SC_LOG_OP_IFACE_CONSOLE },
72  { "File", SC_LOG_OP_IFACE_FILE },
73  { "Syslog", SC_LOG_OP_IFACE_SYSLOG },
74  { NULL, -1 }
75 };
76 
77 #if defined (OS_WIN32)
78 /**
79  * \brief Used for synchronous output on WIN32
80  */
81 static SCMutex sc_log_stream_lock;
82 #endif /* OS_WIN32 */
83 
84 /**
85  * \brief Holds the config state for the logging module
86  */
87 static SCLogConfig *sc_log_config = NULL;
88 
89 /**
90  * \brief Returns the full path given a file and configured log dir
91  */
92 static char *SCLogGetLogFilename(const char *);
93 
94 /**
95  * \brief Holds the global log level. Is the same as sc_log_config->log_level
96  */
98 
99 /**
100  * \brief Used to indicate whether the logging module has been init or not
101  */
103 
104 /**
105  * \brief Used to indicate whether the logging module has been cleaned or not
106  */
108 
109 /**
110  * \brief Maps the SC logging level to the syslog logging level
111  *
112  * \param The SC logging level that has to be mapped to the syslog_log_level
113  *
114  * \retval syslog_log_level The mapped syslog_api_log_level, for the logging
115  * module api's internal log_level
116  */
117 static inline int SCLogMapLogLevelToSyslogLevel(int log_level)
118 {
119  int syslog_log_level = 0;
120 
121  switch (log_level) {
122  case SC_LOG_EMERGENCY:
123  syslog_log_level = LOG_EMERG;
124  break;
125  case SC_LOG_ALERT:
126  syslog_log_level = LOG_ALERT;
127  break;
128  case SC_LOG_CRITICAL:
129  syslog_log_level = LOG_CRIT;
130  break;
131  case SC_LOG_ERROR:
132  syslog_log_level = LOG_ERR;
133  break;
134  case SC_LOG_WARNING:
135  syslog_log_level = LOG_WARNING;
136  break;
137  case SC_LOG_NOTICE:
138  syslog_log_level = LOG_NOTICE;
139  break;
140  case SC_LOG_INFO:
141  syslog_log_level = LOG_INFO;
142  break;
143  case SC_LOG_CONFIG:
144  case SC_LOG_DEBUG:
145  case SC_LOG_PERF:
146  syslog_log_level = LOG_DEBUG;
147  break;
148  default:
149  syslog_log_level = LOG_EMERG;
150  break;
151  }
152 
153  return syslog_log_level;
154 }
155 
156 /**
157  * \brief Output function that logs a character string out to a file descriptor
158  *
159  * \param fd Pointer to the file descriptor
160  * \param msg Pointer to the character string that should be logged
161  */
162 static inline void SCLogPrintToStream(FILE *fd, char *msg)
163 {
164  /* Would only happen if the log file failed to re-open during rotation. */
165  if (fd == NULL) {
166  return;
167  }
168 
169 #if defined (OS_WIN32)
170  SCMutexLock(&sc_log_stream_lock);
171 #endif /* OS_WIN32 */
172 
173  if (fprintf(fd, "%s\n", msg) < 0)
174  printf("Error writing to stream using fprintf\n");
175 
176  fflush(fd);
177 
178 #if defined (OS_WIN32)
179  SCMutexUnlock(&sc_log_stream_lock);
180 #endif /* OS_WIN32 */
181 
182  return;
183 }
184 
185 /**
186  * \brief Output function that logs a character string throught the syslog iface
187  *
188  * \param syslog_log_level Holds the syslog_log_level that the message should be
189  * logged as
190  * \param msg Pointer to the char string, that should be logged
191  *
192  * \todo syslog is thread-safe according to POSIX manual and glibc code, but we
193  * we will have to look into non POSIX compliant boxes like freeBSD
194  */
195 static inline void SCLogPrintToSyslog(int syslog_log_level, const char *msg)
196 {
197  //static struct syslog_data data = SYSLOG_DATA_INIT;
198  //syslog_r(syslog_log_level, NULL, "%s", msg);
199 
200  syslog(syslog_log_level, "%s", msg);
201 
202  return;
203 }
204 
205 #ifdef HAVE_LIBJANSSON
206 #include <jansson.h>
207 /**
208  */
209 static int SCLogMessageJSON(struct timeval *tval, char *buffer, size_t buffer_size,
210  SCLogLevel log_level, const char *file,
211  unsigned line, const char *function, SCError error_code,
212  const char *message)
213 {
214  json_t *js = json_object();
215  if (unlikely(js == NULL))
216  goto error;
217  json_t *ejs = json_object();
218  if (unlikely(ejs == NULL))
219  goto error;
220 
221  char timebuf[64];
222  CreateIsoTimeString(tval, timebuf, sizeof(timebuf));
223  json_object_set_new(js, "timestamp", json_string(timebuf));
224 
225  const char *s = SCMapEnumValueToName(log_level, sc_log_level_map);
226  if (s != NULL) {
227  json_object_set_new(js, "log_level", json_string(s));
228  } else {
229  json_object_set_new(js, "log_level", json_string("INVALID"));
230  }
231 
232  json_object_set_new(js, "event_type", json_string("engine"));
233 
234  if (error_code > 0) {
235  json_object_set_new(ejs, "error_code", json_integer(error_code));
236  json_object_set_new(ejs, "error", json_string(SCErrorToString(error_code)));
237  }
238 
239  if (message)
240  json_object_set_new(ejs, "message", json_string(message));
241 
242  if (log_level >= SC_LOG_DEBUG) {
243  if (function)
244  json_object_set_new(ejs, "function", json_string(function));
245 
246  if (file)
247  json_object_set_new(ejs, "file", json_string(file));
248 
249  if (line > 0)
250  json_object_set_new(ejs, "line", json_integer(line));
251  }
252 
253  json_object_set_new(js, "engine", ejs);
254 
255  char *js_s = json_dumps(js,
256  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
257  JSON_ESCAPE_SLASH);
258  snprintf(buffer, buffer_size, "%s", js_s);
259  free(js_s);
260 
261  json_object_del(js, "engine");
262  json_object_clear(js);
263  json_decref(js);
264 
265  return 0;
266 error:
267  return -1;
268 }
269 #endif /* HAVE_LIBJANSSON */
270 
271 /**
272  * \brief Adds the global log_format to the outgoing buffer
273  *
274  * \param log_level log_level of the message that has to be logged
275  * \param msg Buffer containing the outgoing message
276  * \param file File_name from where the message originated
277  * \param function Function_name from where the message originated
278  * \param line Line_no from where the messaged originated
279  *
280  * \retval SC_OK on success; else an error code
281  */
282 static SCError SCLogMessageGetBuffer(
283  struct timeval *tval, int color, SCLogOPType type,
284  char *buffer, size_t buffer_size,
285  const char *log_format,
286 
287  const SCLogLevel log_level, const char *file,
288  const unsigned int line, const char *function,
289  const SCError error_code, const char *message)
290 {
291 #ifdef HAVE_LIBJANSSON
292  if (type == SC_LOG_OP_TYPE_JSON)
293  return SCLogMessageJSON(tval, buffer, buffer_size, log_level, file, line, function, error_code, message);
294 #endif
295 
296  char *temp = buffer;
297  const char *s = NULL;
298  struct tm *tms = NULL;
299 
300  const char *redb = "";
301  const char *red = "";
302  const char *yellowb = "";
303  const char *yellow = "";
304  const char *green = "";
305  const char *blue = "";
306  const char *reset = "";
307  if (color) {
308  redb = "\x1b[1;31m";
309  red = "\x1b[31m";
310  yellowb = "\x1b[1;33m";
311  yellow = "\x1b[33m";
312  green = "\x1b[32m";
313  blue = "\x1b[34m";
314  reset = "\x1b[0m";
315  }
316  /* no of characters_written(cw) by snprintf */
317  int cw = 0;
318 
320 
321  /* make a copy of the format string as it will be modified below */
322  char local_format[strlen(log_format) + 1];
323  strlcpy(local_format, log_format, sizeof(local_format));
324  char *temp_fmt = local_format;
325  char *substr = temp_fmt;
326 
327  while ( (temp_fmt = index(temp_fmt, SC_LOG_FMT_PREFIX)) ) {
328  if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
329  return SC_OK;
330  }
331  switch(temp_fmt[1]) {
332  case SC_LOG_FMT_TIME:
333  temp_fmt[0] = '\0';
334 
335  struct tm local_tm;
336  tms = SCLocalTime(tval->tv_sec, &local_tm);
337 
338  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
339  "%s%s%d/%d/%04d -- %02d:%02d:%02d%s",
340  substr, green, tms->tm_mday, tms->tm_mon + 1,
341  tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
342  tms->tm_sec, reset);
343  if (cw < 0)
344  return SC_ERR_SPRINTF;
345  temp += cw;
346  temp_fmt++;
347  substr = temp_fmt;
348  substr++;
349  break;
350 
351  case SC_LOG_FMT_PID:
352  temp_fmt[0] = '\0';
353  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
354  "%s%s%u%s", substr, yellow, getpid(), reset);
355  if (cw < 0)
356  return SC_ERR_SPRINTF;
357  temp += cw;
358  temp_fmt++;
359  substr = temp_fmt;
360  substr++;
361  break;
362 
363  case SC_LOG_FMT_TID:
364  temp_fmt[0] = '\0';
365  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
366  "%s%s%lu%s", substr, yellow, SCGetThreadIdLong(), reset);
367  if (cw < 0)
368  return SC_ERR_SPRINTF;
369  temp += cw;
370  temp_fmt++;
371  substr = temp_fmt;
372  substr++;
373  break;
374 
375  case SC_LOG_FMT_TM:
376  temp_fmt[0] = '\0';
377 /* disabled to prevent dead lock:
378  * log or alloc (which calls log on error) can call TmThreadsGetCallingThread
379  * which will lock tv_root_lock. This can happen while we already hold this
380  * lock. */
381 #if 0
383  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg),
384  "%s%s", substr, ((tv != NULL)? tv->name: "UNKNOWN TM"));
385 #endif
386  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
387  "%s%s", substr, "N/A");
388  if (cw < 0)
389  return SC_ERR_SPRINTF;
390  temp += cw;
391  temp_fmt++;
392  substr = temp_fmt;
393  substr++;
394  break;
395 
397  temp_fmt[0] = '\0';
398  s = SCMapEnumValueToName(log_level, sc_log_level_map);
399  if (s != NULL) {
400  if (log_level <= SC_LOG_ERROR)
401  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
402  "%s%s%s%s", substr, redb, s, reset);
403  else if (log_level == SC_LOG_WARNING)
404  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
405  "%s%s%s%s", substr, red, s, reset);
406  else if (log_level == SC_LOG_NOTICE)
407  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
408  "%s%s%s%s", substr, yellowb, s, reset);
409  else
410  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
411  "%s%s%s%s", substr, yellow, s, reset);
412  } else {
413  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
414  "%s%s", substr, "INVALID");
415  }
416  if (cw < 0)
417  return SC_ERR_SPRINTF;
418  temp += cw;
419  temp_fmt++;
420  substr = temp_fmt;
421  substr++;
422  break;
423 
425  temp_fmt[0] = '\0';
426  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
427  "%s%s%s%s", substr, blue, file, reset);
428  if (cw < 0)
429  return SC_ERR_SPRINTF;
430  temp += cw;
431  temp_fmt++;
432  substr = temp_fmt;
433  substr++;
434  break;
435 
436  case SC_LOG_FMT_LINE:
437  temp_fmt[0] = '\0';
438  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
439  "%s%s%u%s", substr, green, line, reset);
440  if (cw < 0)
441  return SC_ERR_SPRINTF;
442  temp += cw;
443  temp_fmt++;
444  substr = temp_fmt;
445  substr++;
446  break;
447 
448  case SC_LOG_FMT_FUNCTION:
449  temp_fmt[0] = '\0';
450  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
451  "%s%s%s%s", substr, green, function, reset);
452  if (cw < 0)
453  return SC_ERR_SPRINTF;
454  temp += cw;
455  temp_fmt++;
456  substr = temp_fmt;
457  substr++;
458  break;
459 
460  }
461  temp_fmt++;
462  }
463  if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
464  return SC_OK;
465  }
466  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s", substr);
467  if (cw < 0) {
468  return SC_ERR_SPRINTF;
469  }
470  temp += cw;
471  if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
472  return SC_OK;
473  }
474 
475  if (error_code != SC_OK) {
476  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer),
477  "[%sERRCODE%s: %s%s%s(%s%d%s)] - ", yellow, reset, red, SCErrorToString(error_code), reset, yellow, error_code, reset);
478  if (cw < 0) {
479  return SC_ERR_SPRINTF;
480  }
481  temp += cw;
482  if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
483  return SC_OK;
484  }
485  }
486 
487  const char *hi = "";
488  if (error_code > SC_OK)
489  hi = red;
490  else if (log_level <= SC_LOG_NOTICE)
491  hi = yellow;
492  cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - buffer), "%s%s%s", hi, message, reset);
493  if (cw < 0) {
494  return SC_ERR_SPRINTF;
495  }
496  temp += cw;
497  if ((temp - buffer) > SC_LOG_MAX_LOG_MSG_LEN) {
498  return SC_OK;
499  }
500 
501  if (sc_log_config->op_filter_regex != NULL) {
502 #define MAX_SUBSTRINGS 30
503  int ov[MAX_SUBSTRINGS];
504 
505  if (pcre_exec(sc_log_config->op_filter_regex,
506  sc_log_config->op_filter_regex_study,
507  buffer, strlen(buffer), 0, 0, ov, MAX_SUBSTRINGS) < 0)
508  {
509  return SC_ERR_LOG_FG_FILTER_MATCH; // bit hacky, but just return !0
510  }
511 #undef MAX_SUBSTRINGS
512  }
513 
514  return SC_OK;
515 }
516 
517 /** \internal
518  * \brief try to reopen file
519  * \note no error reporting here, as we're called by SCLogMessage
520  * \retval status 0 ok, -1 error */
521 static int SCLogReopen(SCLogOPIfaceCtx *op_iface_ctx)
522 {
523  if (op_iface_ctx->file == NULL) {
524  return 0;
525  }
526 
527  if (op_iface_ctx->file_d != NULL) {
528  fclose(op_iface_ctx->file_d);
529  }
530  op_iface_ctx->file_d = fopen(op_iface_ctx->file, "a");
531  if (op_iface_ctx->file_d == NULL) {
532  return -1;
533  }
534  return 0;
535 }
536 
537 /**
538  * \brief Adds the global log_format to the outgoing buffer
539  *
540  * \param log_level log_level of the message that has to be logged
541  * \param msg Buffer containing the outgoing message
542  * \param file File_name from where the message originated
543  * \param function Function_name from where the message originated
544  * \param line Line_no from where the messaged originated
545  *
546  * \retval SC_OK on success; else an error code
547  */
548 SCError SCLogMessage(const SCLogLevel log_level, const char *file,
549  const unsigned int line, const char *function,
550  const SCError error_code, const char *message)
551 {
552  char buffer[SC_LOG_MAX_LOG_MSG_LEN] = "";
553  SCLogOPIfaceCtx *op_iface_ctx = NULL;
554 
555  if (sc_log_module_initialized != 1) {
556  printf("Logging module not initialized. Call SCLogInitLogModule() "
557  "first before using the debug API\n");
558  return SC_OK;
559  }
560 
561  /* get ts here so we log the same ts to each output */
562  struct timeval tval;
563  gettimeofday(&tval, NULL);
564 
565  op_iface_ctx = sc_log_config->op_ifaces;
566  while (op_iface_ctx != NULL) {
567  if (log_level != SC_LOG_NOTSET && log_level > op_iface_ctx->log_level) {
568  op_iface_ctx = op_iface_ctx->next;
569  continue;
570  }
571 
572  switch (op_iface_ctx->iface) {
574  if (SCLogMessageGetBuffer(&tval, op_iface_ctx->use_color, op_iface_ctx->type,
575  buffer, sizeof(buffer),
576  op_iface_ctx->log_format ?
577  op_iface_ctx->log_format : sc_log_config->log_format,
578  log_level, file, line, function,
579  error_code, message) == 0)
580  {
581  SCLogPrintToStream((log_level == SC_LOG_ERROR)? stderr: stdout, buffer);
582  }
583  break;
585  if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer),
586  op_iface_ctx->log_format ?
587  op_iface_ctx->log_format : sc_log_config->log_format,
588  log_level, file, line, function,
589  error_code, message) == 0)
590  {
591  int r = 0;
592  SCMutexLock(&op_iface_ctx->fp_mutex);
593  if (op_iface_ctx->rotation_flag) {
594  r = SCLogReopen(op_iface_ctx);
595  op_iface_ctx->rotation_flag = 0;
596  }
597  SCLogPrintToStream(op_iface_ctx->file_d, buffer);
598  SCMutexUnlock(&op_iface_ctx->fp_mutex);
599 
600  /* report error outside of lock to avoid recursion */
601  if (r == -1) {
602  SCLogError(SC_ERR_FOPEN, "re-opening file \"%s\" failed: %s",
603  op_iface_ctx->file, strerror(errno));
604  }
605  }
606  break;
608  if (SCLogMessageGetBuffer(&tval, 0, op_iface_ctx->type, buffer, sizeof(buffer),
609  op_iface_ctx->log_format ?
610  op_iface_ctx->log_format : sc_log_config->log_format,
611  log_level, file, line, function,
612  error_code, message) == 0)
613  {
614  SCLogPrintToSyslog(SCLogMapLogLevelToSyslogLevel(log_level), buffer);
615  }
616  break;
617  default:
618  break;
619  }
620  op_iface_ctx = op_iface_ctx->next;
621  }
622  return SC_OK;
623 }
624 
625 /**
626  * \brief Returns whether debug messages are enabled to be logged or not
627  *
628  * \retval 1 if debug messages are enabled to be logged
629  * \retval 0 if debug messages are not enabled to be logged
630  */
632 {
633 #ifdef DEBUG
635  return 1;
636  else
637  return 0;
638 #else
639  return 0;
640 #endif
641 }
642 
643 /**
644  * \brief Allocates an output buffer for an output interface. Used when we
645  * want the op_interface log_format to override the global_log_format.
646  * Currently not used.
647  *
648  * \retval buffer Pointer to the newly created output_buffer
649  */
651 {
652  SCLogOPBuffer *buffer = NULL;
653  SCLogOPIfaceCtx *op_iface_ctx = NULL;
654  int i = 0;
655 
656  if ( (buffer = SCMalloc(sc_log_config->op_ifaces_cnt *
657  sizeof(SCLogOPBuffer))) == NULL) {
658  SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogAllocLogOPBuffer. Exiting...");
659  exit(EXIT_FAILURE);
660  }
661 
662  op_iface_ctx = sc_log_config->op_ifaces;
663  for (i = 0;
664  i < sc_log_config->op_ifaces_cnt;
665  i++, op_iface_ctx = op_iface_ctx->next) {
666  buffer[i].log_format = op_iface_ctx->log_format;
667  buffer[i].temp = buffer[i].msg;
668  }
669 
670  return buffer;
671 }
672 
673 /*----------------------The logging module initialization code--------------- */
674 
675 /**
676  * \brief Returns a new output_interface_context
677  *
678  * \retval iface_ctx Pointer to a newly allocated output_interface_context
679  * \initonly
680  */
681 static inline SCLogOPIfaceCtx *SCLogAllocLogOPIfaceCtx(void)
682 {
683  SCLogOPIfaceCtx *iface_ctx = NULL;
684 
685  if ( (iface_ctx = SCMalloc(sizeof(SCLogOPIfaceCtx))) == NULL) {
686  SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogallocLogOPIfaceCtx. Exiting...");
687  exit(EXIT_FAILURE);
688  }
689  memset(iface_ctx, 0, sizeof(SCLogOPIfaceCtx));
690 
691  return iface_ctx;
692 }
693 
694 /**
695  * \brief Initializes the file output interface
696  *
697  * \param file Path to the file used for logging purposes
698  * \param log_format Pointer to the log_format for this op interface, that
699  * overrides the global_log_format
700  * \param log_level Override of the global_log_level by this interface
701  *
702  * \retval iface_ctx Pointer to the file output interface context created
703  * \initonly
704  */
705 static inline SCLogOPIfaceCtx *SCLogInitFileOPIface(const char *file,
706  const char *log_format,
707  int log_level,
709 {
710  SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
711 
712  if (iface_ctx == NULL) {
713  SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitFileOPIface. Exiting...");
714  exit(EXIT_FAILURE);
715  }
716 
717  if (file == NULL || log_format == NULL) {
718  goto error;
719  }
720 
721  iface_ctx->iface = SC_LOG_OP_IFACE_FILE;
722  iface_ctx->type = type;
723 
724  if ( (iface_ctx->file_d = fopen(file, "a")) == NULL) {
725  printf("Error opening file %s\n", file);
726  goto error;
727  }
728 
729  if ((iface_ctx->file = SCStrdup(file)) == NULL) {
730  goto error;
731  }
732 
733  if ((iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
734  goto error;
735  }
736 
737  SCMutexInit(&iface_ctx->fp_mutex, NULL);
739 
740  iface_ctx->log_level = log_level;
741 
742  return iface_ctx;
743 
744 error:
745  if (iface_ctx->file != NULL) {
746  SCFree((char *)iface_ctx->file);
747  iface_ctx->file = NULL;
748  }
749  if (iface_ctx->log_format != NULL) {
750  SCFree((char *)iface_ctx->log_format);
751  iface_ctx->log_format = NULL;
752  }
753  if (iface_ctx->file_d != NULL) {
754  fclose(iface_ctx->file_d);
755  iface_ctx->file_d = NULL;
756  }
757  SCFree(iface_ctx);
758  return NULL;
759 }
760 
761 /**
762  * \brief Initializes the console output interface and deals with possible
763  * env var overrides.
764  *
765  * \param log_format Pointer to the log_format for this op interface, that
766  * overrides the global_log_format
767  * \param log_level Override of the global_log_level by this interface
768  *
769  * \retval iface_ctx Pointer to the console output interface context created
770  * \initonly
771  */
772 static inline SCLogOPIfaceCtx *SCLogInitConsoleOPIface(const char *log_format,
773  SCLogLevel log_level, SCLogOPType type)
774 {
775  SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
776 
777  if (iface_ctx == NULL) {
778  SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitConsoleOPIface. Exiting...");
779  exit(EXIT_FAILURE);
780  }
781 
782  iface_ctx->iface = SC_LOG_OP_IFACE_CONSOLE;
783  iface_ctx->type = type;
784 
785  /* console log format is overridden by envvars */
786  const char *tmp_log_format = log_format;
787  const char *s = getenv(SC_LOG_ENV_LOG_FORMAT);
788  if (s != NULL) {
789 #if 0
790  printf("Overriding setting for \"console.format\" because of env "
791  "var SC_LOG_FORMAT=\"%s\".\n", s);
792 #endif
793  tmp_log_format = s;
794  }
795 
796  if (tmp_log_format != NULL &&
797  (iface_ctx->log_format = SCStrdup(tmp_log_format)) == NULL) {
798  printf("Error allocating memory\n");
799  exit(EXIT_FAILURE);
800  }
801 
802  /* console log level is overridden by envvars */
803  SCLogLevel tmp_log_level = log_level;
804  s = getenv(SC_LOG_ENV_LOG_LEVEL);
805  if (s != NULL) {
806  SCLogLevel l = SCMapEnumNameToValue(s, sc_log_level_map);
807  if (l > SC_LOG_NOTSET && l < SC_LOG_LEVEL_MAX) {
808 #if 0
809  printf("Overriding setting for \"console.level\" because of env "
810  "var SC_LOG_LEVEL=\"%s\".\n", s);
811 #endif
812  tmp_log_level = l;
813  }
814  }
815  iface_ctx->log_level = tmp_log_level;
816 
817 #ifndef OS_WIN32
818  if (isatty(fileno(stdout)) && isatty(fileno(stderr))) {
819  iface_ctx->use_color = TRUE;
820  }
821 #endif
822 
823  return iface_ctx;
824 }
825 
826 /**
827  * \brief Initializes the syslog output interface
828  *
829  * \param facility The facility code for syslog
830  * \param log_format Pointer to the log_format for this op interface, that
831  * overrides the global_log_format
832  * \param log_level Override of the global_log_level by this interface
833  *
834  * \retval iface_ctx Pointer to the syslog output interface context created
835  */
836 static inline SCLogOPIfaceCtx *SCLogInitSyslogOPIface(int facility,
837  const char *log_format,
838  SCLogLevel log_level,
840 {
841  SCLogOPIfaceCtx *iface_ctx = SCLogAllocLogOPIfaceCtx();
842 
843  if ( iface_ctx == NULL) {
844  SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitSyslogOPIface. Exiting...");
845  exit(EXIT_FAILURE);
846  }
847 
848  iface_ctx->iface = SC_LOG_OP_IFACE_SYSLOG;
849  iface_ctx->type = type;
850 
851  if (facility == -1)
852  facility = SC_LOG_DEF_SYSLOG_FACILITY;
853  iface_ctx->facility = facility;
854 
855  if (log_format != NULL &&
856  (iface_ctx->log_format = SCStrdup(log_format)) == NULL) {
857  printf("Error allocating memory\n");
858  exit(EXIT_FAILURE);
859  }
860 
861  iface_ctx->log_level = log_level;
862 
863  openlog(NULL, LOG_NDELAY, iface_ctx->facility);
864 
865  return iface_ctx;
866 }
867 
868 /**
869  * \brief Frees the output_interface context supplied as an argument
870  *
871  * \param iface_ctx Pointer to the op_interface_context to be freed
872  */
873 static inline void SCLogFreeLogOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx)
874 {
875  SCLogOPIfaceCtx *temp = NULL;
876 
877  while (iface_ctx != NULL) {
878  temp = iface_ctx;
879 
880  if (iface_ctx->file_d != NULL) {
881  fclose(iface_ctx->file_d);
882  SCMutexDestroy(&iface_ctx->fp_mutex);
883  }
884 
885  if (iface_ctx->file != NULL)
886  SCFree((void *)iface_ctx->file);
887 
888  if (iface_ctx->log_format != NULL)
889  SCFree((void *)iface_ctx->log_format);
890 
891  if (iface_ctx->iface == SC_LOG_OP_IFACE_SYSLOG) {
892  closelog();
893  }
894 
895  iface_ctx = iface_ctx->next;
896 
897  SCFree(temp);
898  }
899 
900  return;
901 }
902 
903 /**
904  * \brief Internal function used to set the logging module global_log_level
905  * during the initialization phase
906  *
907  * \param sc_lid The initialization data supplied.
908  * \param sc_lc The logging module context which has to be updated.
909  */
910 static inline void SCLogSetLogLevel(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
911 {
912  SCLogLevel log_level = SC_LOG_NOTSET;
913  const char *s = NULL;
914 
915  /* envvar overrides config */
916  s = getenv(SC_LOG_ENV_LOG_LEVEL);
917  if (s != NULL) {
918  log_level = SCMapEnumNameToValue(s, sc_log_level_map);
919  } else if (sc_lid != NULL) {
920  log_level = sc_lid->global_log_level;
921  }
922 
923  /* deal with the global_log_level to be used */
924  if (log_level > SC_LOG_NOTSET && log_level < SC_LOG_LEVEL_MAX)
925  sc_lc->log_level = log_level;
926  else {
928 #ifndef UNITTESTS
929  if (sc_lid != NULL) {
930  printf("Warning: Invalid/No global_log_level assigned by user. Falling "
931  "back on the default_log_level \"%s\"\n",
932  SCMapEnumValueToName(sc_lc->log_level, sc_log_level_map));
933  }
934 #endif
935  }
936 
937  /* we also set it to a global var, as it is easier to access it */
939 
940  return;
941 }
942 
943 /**
944  * \brief Internal function used to set the logging module global_log_format
945  * during the initialization phase
946  *
947  * \param sc_lid The initialization data supplied.
948  * \param sc_lc The logging module context which has to be updated.
949  */
950 static inline void SCLogSetLogFormat(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
951 {
952  const char *format = NULL;
953 
954  /* envvar overrides config */
955  format = getenv(SC_LOG_ENV_LOG_FORMAT);
956  if (format == NULL) {
957  if (sc_lid != NULL) {
958  format = sc_lid->global_log_format;
959  }
960  }
961 
962  /* deal with the global log format to be used */
963  if (format == NULL || strlen(format) > SC_LOG_MAX_LOG_FORMAT_LEN) {
964  format = SC_LOG_DEF_LOG_FORMAT;
965 #ifndef UNITTESTS
966  if (sc_lid != NULL) {
967  printf("Warning: Invalid/No global_log_format supplied by user or format "
968  "length exceeded limit of \"%d\" characters. Falling back on "
969  "default log_format \"%s\"\n", SC_LOG_MAX_LOG_FORMAT_LEN,
970  format);
971  }
972 #endif
973  }
974 
975  if (format != NULL && (sc_lc->log_format = SCStrdup(format)) == NULL) {
976  printf("Error allocating memory\n");
977  exit(EXIT_FAILURE);
978  }
979 
980  return;
981 }
982 
983 /**
984  * \brief Internal function used to set the logging module global_op_ifaces
985  * during the initialization phase
986  *
987  * \param sc_lid The initialization data supplied.
988  * \param sc_lc The logging module context which has to be updated.
989  */
990 static inline void SCLogSetOPIface(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
991 {
992  SCLogOPIfaceCtx *op_ifaces_ctx = NULL;
993  int op_iface = 0;
994  const char *s = NULL;
995 
996  if (sc_lid != NULL && sc_lid->op_ifaces != NULL) {
997  sc_lc->op_ifaces = sc_lid->op_ifaces;
998  sc_lid->op_ifaces = NULL;
999  sc_lc->op_ifaces_cnt = sc_lid->op_ifaces_cnt;
1000  } else {
1001  s = getenv(SC_LOG_ENV_LOG_OP_IFACE);
1002  if (s != NULL) {
1003  op_iface = SCMapEnumNameToValue(s, sc_log_op_iface_map);
1004 
1005  if(op_iface < 0 || op_iface >= SC_LOG_OP_IFACE_MAX) {
1006  op_iface = SC_LOG_DEF_LOG_OP_IFACE;
1007 #ifndef UNITTESTS
1008  printf("Warning: Invalid output interface supplied by user. "
1009  "Falling back on default_output_interface \"%s\"\n",
1010  SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
1011 #endif
1012  }
1013  }
1014  else {
1015  op_iface = SC_LOG_DEF_LOG_OP_IFACE;
1016 #ifndef UNITTESTS
1017  if (sc_lid != NULL) {
1018  printf("Warning: Output_interface not supplied by user. Falling "
1019  "back on default_output_interface \"%s\"\n",
1020  SCMapEnumValueToName(op_iface, sc_log_op_iface_map));
1021  }
1022 #endif
1023  }
1024 
1025  switch (op_iface) {
1027  op_ifaces_ctx = SCLogInitConsoleOPIface(NULL, SC_LOG_LEVEL_MAX,0);
1028  break;
1029  case SC_LOG_OP_IFACE_FILE:
1030  s = getenv(SC_LOG_ENV_LOG_FILE);
1031  if (s == NULL) {
1032  char *str = SCLogGetLogFilename(SC_LOG_DEF_LOG_FILE);
1033  if (str != NULL) {
1034  op_ifaces_ctx = SCLogInitFileOPIface(str, NULL, SC_LOG_LEVEL_MAX,0);
1035  SCFree(str);
1036  }
1037  } else {
1038  op_ifaces_ctx = SCLogInitFileOPIface(s, NULL, SC_LOG_LEVEL_MAX,0);
1039  }
1040  break;
1042  s = getenv(SC_LOG_ENV_LOG_FACILITY);
1043  if (s == NULL)
1045 
1046  op_ifaces_ctx = SCLogInitSyslogOPIface(SCMapEnumNameToValue(s, SCSyslogGetFacilityMap()), NULL, -1,0);
1047  break;
1048  }
1049  sc_lc->op_ifaces = op_ifaces_ctx;
1050  sc_lc->op_ifaces_cnt++;
1051  }
1052  return;
1053 }
1054 
1055 /**
1056  * \brief Internal function used to set the logging module op_filter
1057  * during the initialization phase
1058  *
1059  * \param sc_lid The initialization data supplied.
1060  * \param sc_lc The logging module context which has to be updated.
1061  */
1062 static inline void SCLogSetOPFilter(SCLogInitData *sc_lid, SCLogConfig *sc_lc)
1063 {
1064  const char *filter = NULL;
1065 
1066  int opts = 0;
1067  const char *ep;
1068  int eo = 0;
1069 
1070  /* envvar overrides */
1071  filter = getenv(SC_LOG_ENV_LOG_OP_FILTER);
1072  if (filter == NULL) {
1073  if (sc_lid != NULL) {
1074  filter = sc_lid->op_filter;
1075  }
1076  }
1077 
1078  if (filter != NULL && strcmp(filter, "") != 0) {
1079  sc_lc->op_filter = SCStrdup(filter);
1080  if (sc_lc->op_filter == NULL) {
1081  printf("pcre filter alloc failed\n");
1082  return;
1083  }
1084  sc_lc->op_filter_regex = pcre_compile(filter, opts, &ep, &eo, NULL);
1085  if (sc_lc->op_filter_regex == NULL) {
1086  SCFree(sc_lc->op_filter);
1087  printf("pcre compile of \"%s\" failed at offset %d : %s\n", filter,
1088  eo, ep);
1089  return;
1090  }
1091 
1092  sc_lc->op_filter_regex_study = pcre_study(sc_lc->op_filter_regex, 0,
1093  &ep);
1094  if (ep != NULL) {
1095  printf("pcre study failed: %s\n", ep);
1096  return;
1097  }
1098  }
1099 
1100  return;
1101 }
1102 
1103 /**
1104  * \brief Returns a pointer to a new SCLogInitData. This is a public interface
1105  * intended to be used after the logging paramters are read from the
1106  * conf file
1107  *
1108  * \retval sc_lid Pointer to the newly created SCLogInitData
1109  * \initonly
1110  */
1112 {
1113  SCLogInitData *sc_lid = NULL;
1114 
1115  /* not using SCMalloc here because if it fails we can't log */
1116  if ( (sc_lid = SCMalloc(sizeof(SCLogInitData))) == NULL)
1117  return NULL;
1118 
1119  memset(sc_lid, 0, sizeof(SCLogInitData));
1120 
1121  return sc_lid;
1122 }
1123 
1124 #ifdef UNITTESTS
1125 #ifndef OS_WIN32
1126 /**
1127  * \brief Frees a SCLogInitData
1128  *
1129  * \param sc_lid Pointer to the SCLogInitData to be freed
1130  */
1131 static void SCLogFreeLogInitData(SCLogInitData *sc_lid)
1132 {
1133  if (sc_lid != NULL) {
1134  SCLogFreeLogOPIfaceCtx(sc_lid->op_ifaces);
1135  SCFree(sc_lid);
1136  }
1137 
1138  return;
1139 }
1140 #endif
1141 #endif
1142 
1143 /**
1144  * \brief Frees the logging module context
1145  */
1146 static inline void SCLogFreeLogConfig(SCLogConfig *sc_lc)
1147 {
1148  if (sc_lc != NULL) {
1149  if (sc_lc->startup_message != NULL)
1150  SCFree(sc_lc->startup_message);
1151  if (sc_lc->log_format != NULL)
1152  SCFree(sc_lc->log_format);
1153  if (sc_lc->op_filter != NULL)
1154  SCFree(sc_lc->op_filter);
1155 
1156  if (sc_lc->op_filter_regex != NULL)
1157  pcre_free(sc_lc->op_filter_regex);
1158  if (sc_lc->op_filter_regex_study)
1160 
1161  SCLogFreeLogOPIfaceCtx(sc_lc->op_ifaces);
1162  SCFree(sc_lc);
1163  }
1164 
1165  return;
1166 }
1167 
1168 /**
1169  * \brief Appends an output_interface to the output_interface list sent in head
1170  *
1171  * \param iface_ctx Pointer to the output_interface that has to be added to head
1172  * \param head Pointer to the output_interface list
1173  */
1175 {
1176  SCLogOPIfaceCtx *temp = NULL, *prev = NULL;
1177  SCLogOPIfaceCtx **head = &sc_lid->op_ifaces;
1178 
1179  if (iface_ctx == NULL) {
1180 #ifdef DEBUG
1181  printf("Argument(s) to SCLogAppendOPIfaceCtx() NULL\n");
1182 #endif
1183  return;
1184  }
1185 
1186  temp = *head;
1187  while (temp != NULL) {
1188  prev = temp;
1189  temp = temp->next;
1190  }
1191 
1192  if (prev == NULL)
1193  *head = iface_ctx;
1194  else
1195  prev->next = iface_ctx;
1196 
1197  sc_lid->op_ifaces_cnt++;
1198 
1199  return;
1200 }
1201 
1202 
1203 /**
1204  * \brief Creates a new output interface based on the arguments sent. The kind
1205  * of output interface to be created is decided by the iface_name arg.
1206  * If iface_name is "file", the arg argument will hold the filename to be
1207  * used for logging purposes. If iface_name is "syslog", the arg
1208  * argument holds the facility code. If iface_name is "console", arg is
1209  * NULL.
1210  *
1211  * \param iface_name Interface name. Can be "console", "file" or "syslog"
1212  * \param log_format Override for the global_log_format
1213  * \param log_level Override for the global_log_level
1214  * \param log_level Parameter required by a particular interface. Explained in
1215  * the function description
1216  *
1217  * \retval iface_ctx Pointer to the newly created output interface
1218  */
1219 SCLogOPIfaceCtx *SCLogInitOPIfaceCtx(const char *iface_name,
1220  const char *log_format,
1221  int log_level, const char *arg)
1222 {
1223  int iface = SCMapEnumNameToValue(iface_name, sc_log_op_iface_map);
1224 
1225  if (log_level < SC_LOG_NONE || log_level > SC_LOG_DEBUG) {
1226 #ifndef UNITTESTS
1227  printf("Warning: Supplied log_level_override for op_interface \"%s\" "
1228  "is invalid. Defaulting to not specifying an override\n",
1229  iface_name);
1230 #endif
1231  log_level = SC_LOG_NOTSET;
1232  }
1233 
1234  switch (iface) {
1236  return SCLogInitConsoleOPIface(log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1237  case SC_LOG_OP_IFACE_FILE:
1238  return SCLogInitFileOPIface(arg, log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1240  return SCLogInitSyslogOPIface(SCMapEnumNameToValue(arg, SCSyslogGetFacilityMap()),
1241  log_format, log_level, SC_LOG_OP_TYPE_REGULAR);
1242  default:
1243 #ifdef DEBUG
1244  printf("Output Interface \"%s\" not supported by the logging module",
1245  iface_name);
1246 #endif
1247  return NULL;
1248  }
1249 }
1250 
1251 /**
1252  * \brief Initializes the logging module.
1253  *
1254  * \param sc_lid The initialization data for the logging module. If sc_lid is
1255  * NULL, we would stick to the default configuration for the
1256  * logging subsystem.
1257  * \initonly
1258  */
1260 {
1261  /* De-initialize the logging context, if it has already init by the
1262  * environment variables at the start of the engine */
1264 
1265 #if defined (OS_WIN32)
1266  if (SCMutexInit(&sc_log_stream_lock, NULL) != 0) {
1267  SCLogError(SC_ERR_MUTEX, "Failed to initialize log mutex.");
1268  exit(EXIT_FAILURE);
1269  }
1270 #endif /* OS_WIN32 */
1271 
1272  /* sc_log_config is a global variable */
1273  if ( (sc_log_config = SCMalloc(sizeof(SCLogConfig))) == NULL) {
1274  SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCLogInitLogModule. Exiting...");
1275  exit(EXIT_FAILURE);
1276  }
1277  memset(sc_log_config, 0, sizeof(SCLogConfig));
1278 
1279  SCLogSetLogLevel(sc_lid, sc_log_config);
1280  SCLogSetLogFormat(sc_lid, sc_log_config);
1281  SCLogSetOPIface(sc_lid, sc_log_config);
1282  SCLogSetOPFilter(sc_lid, sc_log_config);
1283 
1286 
1287  //SCOutputPrint(sc_did->startup_message);
1288 
1289 #ifdef HAVE_RUST
1290  rs_log_set_level(sc_log_global_log_level);
1291 #endif
1292 
1293  return;
1294 }
1295 
1296 void SCLogLoadConfig(int daemon, int verbose)
1297 {
1298  ConfNode *outputs;
1299  SCLogInitData *sc_lid;
1300  int have_logging = 0;
1301 
1302  outputs = ConfGetNode("logging.outputs");
1303  if (outputs == NULL) {
1304  SCLogDebug("No logging.output configuration section found.");
1305  return;
1306  }
1307 
1308  sc_lid = SCLogAllocLogInitData();
1309  if (sc_lid == NULL) {
1310  SCLogDebug("Could not allocate memory for log init data");
1311  return;
1312  }
1313 
1314  /* Get default log level and format. */
1315  const char *default_log_level_s = NULL;
1316  if (ConfGet("logging.default-log-level", &default_log_level_s) == 1) {
1317  sc_lid->global_log_level =
1318  SCMapEnumNameToValue(default_log_level_s, sc_log_level_map);
1319  if (sc_lid->global_log_level == -1) {
1320  SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid default log level: %s",
1321  default_log_level_s);
1322  exit(EXIT_FAILURE);
1323  }
1324  }
1325  else {
1327  "No default log level set, will use notice.");
1328  sc_lid->global_log_level = SC_LOG_NOTICE;
1329  }
1330 
1331  if (verbose) {
1332  sc_lid->global_log_level += verbose;
1333  if (sc_lid->global_log_level > SC_LOG_LEVEL_MAX)
1335  }
1336 
1337  if (ConfGet("logging.default-log-format", &sc_lid->global_log_format) != 1)
1339 
1340  (void)ConfGet("logging.default-output-filter", &sc_lid->op_filter);
1341 
1342  ConfNode *seq_node, *output;
1343  TAILQ_FOREACH(seq_node, &outputs->head, next) {
1344  SCLogLevel level = sc_lid->global_log_level;
1345  SCLogOPIfaceCtx *op_iface_ctx = NULL;
1346  const char *format;
1347  const char *level_s;
1348 
1349  output = ConfNodeLookupChild(seq_node, seq_node->val);
1350  if (output == NULL)
1351  continue;
1352 
1353  /* By default an output is enabled. */
1354  const char *enabled = ConfNodeLookupChildValue(output, "enabled");
1355  if (enabled != NULL && ConfValIsFalse(enabled))
1356  continue;
1357 
1359  const char *type_s = ConfNodeLookupChildValue(output, "type");
1360  if (type_s != NULL) {
1361  if (strcmp(type_s, "regular") == 0)
1362  type = SC_LOG_OP_TYPE_REGULAR;
1363  else if (strcmp(type_s, "json") == 0) {
1364 #ifdef HAVE_LIBJANSSON
1365  type = SC_LOG_OP_TYPE_JSON;
1366 #else
1367  SCLogError(SC_ERR_INVALID_ARGUMENT, "libjansson support not "
1368  "compiled in, can't use 'json' logging");
1369  exit(EXIT_FAILURE);
1370 #endif /* HAVE_LIBJANSSON */
1371  }
1372  }
1373 
1374  /* if available use the log format setting for this output,
1375  * otherwise fall back to the global setting. */
1376  format = ConfNodeLookupChildValue(output, "format");
1377  if (format == NULL)
1378  format = sc_lid->global_log_format;
1379 
1380  level_s = ConfNodeLookupChildValue(output, "level");
1381  if (level_s != NULL) {
1382  level = SCMapEnumNameToValue(level_s, sc_log_level_map);
1383  if (level == -1) {
1384  SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid log level: %s",
1385  level_s);
1386  exit(EXIT_FAILURE);
1387  }
1388  }
1389 
1390  if (strcmp(output->name, "console") == 0) {
1391  op_iface_ctx = SCLogInitConsoleOPIface(format, level, type);
1392  }
1393  else if (strcmp(output->name, "file") == 0) {
1394  const char *filename = ConfNodeLookupChildValue(output, "filename");
1395  if (filename == NULL) {
1397  "Logging to file requires a filename");
1398  exit(EXIT_FAILURE);
1399  }
1400  char *path = NULL;
1401  if (!(PathIsAbsolute(filename))) {
1402  path = SCLogGetLogFilename(filename);
1403  } else {
1404  path = SCStrdup(filename);
1405  }
1406  if (path == NULL)
1407  FatalError(SC_ERR_FATAL, "failed to setup output to file");
1408  have_logging = 1;
1409  op_iface_ctx = SCLogInitFileOPIface(path, format, level, type);
1410  SCFree(path);
1411  }
1412  else if (strcmp(output->name, "syslog") == 0) {
1413  int facility = SC_LOG_DEF_SYSLOG_FACILITY;
1414  const char *facility_s = ConfNodeLookupChildValue(output,
1415  "facility");
1416  if (facility_s != NULL) {
1417  facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap());
1418  if (facility == -1) {
1419  SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid syslog "
1420  "facility: \"%s\", now using \"%s\" as syslog "
1421  "facility", facility_s, SC_LOG_DEF_SYSLOG_FACILITY_STR);
1422  facility = SC_LOG_DEF_SYSLOG_FACILITY;
1423  }
1424  }
1425  SCLogDebug("Initializing syslog logging with format \"%s\"", format);
1426  have_logging = 1;
1427  op_iface_ctx = SCLogInitSyslogOPIface(facility, format, level, type);
1428  }
1429  else {
1430  SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid logging method: %s, "
1431  "ignoring", output->name);
1432  }
1433  if (op_iface_ctx != NULL) {
1434  SCLogAppendOPIfaceCtx(op_iface_ctx, sc_lid);
1435  }
1436  }
1437 
1438  if (daemon && (have_logging == 0)) {
1440  "NO logging compatible with daemon mode selected,"
1441  " suricata won't be able to log. Please update "
1442  " 'logging.outputs' in the YAML.");
1443  }
1444 
1445  SCLogInitLogModule(sc_lid);
1446 
1447  SCLogDebug("sc_log_global_log_level: %d", sc_log_global_log_level);
1448  SCLogDebug("sc_lc->log_format: %s", sc_log_config->log_format);
1449  SCLogDebug("SCLogSetOPFilter: filter: %s", sc_log_config->op_filter);
1450 
1451  if (sc_lid != NULL)
1452  SCFree(sc_lid);
1453 }
1454 
1455 /**
1456  * \brief Returns a full file path given a filename uses log dir specified in
1457  * conf or DEFAULT_LOG_DIR
1458  *
1459  * \param filearg The relative filename for which we want a full path include
1460  * log directory
1461  *
1462  * \retval log_filename The fullpath of the logfile to open
1463  */
1464 static char *SCLogGetLogFilename(const char *filearg)
1465 {
1466  const char *log_dir = ConfigGetLogDirectory();
1467  char *log_filename = SCMalloc(PATH_MAX);
1468  if (unlikely(log_filename == NULL))
1469  return NULL;
1470  snprintf(log_filename, PATH_MAX, "%s/%s", log_dir, filearg);
1471  return log_filename;
1472 }
1473 
1474 /**
1475  * \brief De-Initializes the logging module
1476  */
1478 {
1479  SCLogFreeLogConfig(sc_log_config);
1480 
1481  /* reset the global logging_module variables */
1485  sc_log_config = NULL;
1486 
1487  /* de-init the FD filters */
1489  /* de-init the FG filters */
1491 
1492 #if defined (OS_WIN32)
1493  SCMutexDestroy(&sc_log_stream_lock);
1494 #endif /* OS_WIN32 */
1495 
1496  return;
1497 }
1498 
1499 //------------------------------------Unit_Tests--------------------------------
1500 
1501 /* The logging engine should be tested to the maximum extent possible, since
1502  * logging code would be used throughout the codebase, and hence we can't afford
1503  * to have a single bug here(not that you can afford to have a bug
1504  * elsewhere ;) ). Please report a bug, if you get a slightest hint of a bug
1505  * from the logging module.
1506  */
1507 
1508 #ifdef UNITTESTS
1509 
1510 static int SCLogTestInit01(void)
1511 {
1512 #ifndef OS_WIN32
1513  /* unset any environment variables set for the logging module */
1517 
1518  SCLogInitLogModule(NULL);
1519 
1520  FAIL_IF_NULL(sc_log_config);
1521 
1522  FAIL_IF_NOT(SC_LOG_DEF_LOG_LEVEL == sc_log_config->log_level);
1523  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1524  SC_LOG_DEF_LOG_OP_IFACE == sc_log_config->op_ifaces->iface);
1525  FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1526  strcmp(SC_LOG_DEF_LOG_FORMAT, sc_log_config->log_format) == 0);
1527 
1529 
1530  setenv(SC_LOG_ENV_LOG_LEVEL, "Debug", 1);
1531  setenv(SC_LOG_ENV_LOG_OP_IFACE, "Console", 1);
1532  setenv(SC_LOG_ENV_LOG_FORMAT, "%n- %l", 1);
1533 
1534  SCLogInitLogModule(NULL);
1535 
1536  FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1537  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1538  SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1539  FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1540  !strcmp("%n- %l", sc_log_config->log_format));
1541 
1545 
1547 #endif
1548  PASS;
1549 }
1550 
1551 static int SCLogTestInit02(void)
1552 {
1553 #ifndef OS_WIN32
1554  SCLogInitData *sc_lid = NULL;
1555  SCLogOPIfaceCtx *sc_iface_ctx = NULL;
1556  char *logfile = SCLogGetLogFilename("boo.txt");
1557  sc_lid = SCLogAllocLogInitData();
1558  FAIL_IF_NULL(sc_lid);
1559  sc_lid->startup_message = "Test02";
1560  sc_lid->global_log_level = SC_LOG_DEBUG;
1561  sc_lid->op_filter = "boo";
1562  sc_iface_ctx = SCLogInitOPIfaceCtx("file", "%m - %d", SC_LOG_ALERT,
1563  logfile);
1564  SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1565  sc_iface_ctx = SCLogInitOPIfaceCtx("console", NULL, SC_LOG_ERROR,
1566  NULL);
1567  SCLogAppendOPIfaceCtx(sc_iface_ctx, sc_lid);
1568 
1569  SCLogInitLogModule(sc_lid);
1570 
1571  FAIL_IF_NULL(sc_log_config);
1572 
1573  FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1574  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1575  SC_LOG_OP_IFACE_FILE == sc_log_config->op_ifaces->iface);
1576  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1577  sc_log_config->op_ifaces->next != NULL &&
1578  SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->next->iface);
1579  FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1580  strcmp(SC_LOG_DEF_LOG_FORMAT, sc_log_config->log_format) == 0);
1581  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1582  sc_log_config->op_ifaces->log_format != NULL &&
1583  strcmp("%m - %d", sc_log_config->op_ifaces->log_format) == 0);
1584  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1585  sc_log_config->op_ifaces->next != NULL &&
1586  sc_log_config->op_ifaces->next->log_format == NULL);
1587 
1588  SCLogFreeLogInitData(sc_lid);
1590 
1591  sc_lid = SCLogAllocLogInitData();
1592  FAIL_IF_NULL(sc_lid);
1593  sc_lid->startup_message = "Test02";
1594  sc_lid->global_log_level = SC_LOG_DEBUG;
1595  sc_lid->op_filter = "boo";
1596  sc_lid->global_log_format = "kaboo";
1597 
1598  SCLogInitLogModule(sc_lid);
1599 
1600  FAIL_IF_NULL(sc_log_config);
1601 
1602  FAIL_IF_NOT(SC_LOG_DEBUG == sc_log_config->log_level);
1603  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1604  SC_LOG_OP_IFACE_CONSOLE == sc_log_config->op_ifaces->iface);
1605  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1606  sc_log_config->op_ifaces->next == NULL);
1607  FAIL_IF_NOT(sc_log_config->log_format != NULL &&
1608  strcmp("kaboo", sc_log_config->log_format) == 0);
1609  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1610  sc_log_config->op_ifaces->log_format == NULL);
1611  FAIL_IF_NOT(sc_log_config->op_ifaces != NULL &&
1612  sc_log_config->op_ifaces->next == NULL);
1613 
1614  SCLogFreeLogInitData(sc_lid);
1616  SCFree(logfile);
1617 #endif
1618  PASS;
1619 }
1620 
1621 static int SCLogTestInit03(void)
1622 {
1623  SCLogInitLogModule(NULL);
1624 
1625  SCLogAddFGFilterBL(NULL, "bamboo", -1);
1626  SCLogAddFGFilterBL(NULL, "soo", -1);
1627  SCLogAddFGFilterBL(NULL, "dummy", -1);
1628 
1630 
1631  SCLogAddFGFilterBL(NULL, "dummy1", -1);
1632  SCLogAddFGFilterBL(NULL, "dummy2", -1);
1633 
1635 
1637 
1638  PASS;
1639 }
1640 
1641 static int SCLogTestInit04(void)
1642 {
1643  SCLogInitLogModule(NULL);
1644 
1645  SCLogAddFDFilter("bamboo");
1646  SCLogAddFDFilter("soo");
1647  SCLogAddFDFilter("foo");
1648  SCLogAddFDFilter("roo");
1649 
1651 
1652  SCLogAddFDFilter("loo");
1653  SCLogAddFDFilter("soo");
1654 
1656 
1657  SCLogRemoveFDFilter("bamboo");
1658  SCLogRemoveFDFilter("soo");
1659  SCLogRemoveFDFilter("foo");
1660  SCLogRemoveFDFilter("noo");
1661 
1663 
1665 
1666  PASS;
1667 }
1668 
1669 static int SCLogTestInit05(void)
1670 {
1671  char str[4096];
1672  memset(str, 'A', sizeof(str));
1673  SCLogInfo("%s", str);
1674 
1675  PASS;
1676 }
1677 
1678 #endif /* UNITTESTS */
1679 
1681 {
1682 
1683 #ifdef UNITTESTS
1684 
1685  UtRegisterTest("SCLogTestInit01", SCLogTestInit01);
1686  UtRegisterTest("SCLogTestInit02", SCLogTestInit02);
1687  UtRegisterTest("SCLogTestInit03", SCLogTestInit03);
1688  UtRegisterTest("SCLogTestInit04", SCLogTestInit04);
1689  UtRegisterTest("SCLogTestInit05", SCLogTestInit05);
1690 
1691 #endif /* UNITTESTS */
1692 
1693  return;
1694 }
#define SC_LOG_FMT_LOG_LEVEL
Definition: util-debug.h:197
#define SCMutex
#define SC_LOG_ENV_LOG_FORMAT
Definition: util-debug.h:43
uint8_t op_ifaces_cnt
Definition: util-debug.h:189
#define SC_LOG_ENV_LOG_LEVEL
ENV vars that can be used to set the properties for the logging module.
Definition: util-debug.h:39
#define SC_LOG_DEF_LOG_LEVEL
Definition: util-debug.h:96
#define SCLogDebug(...)
Definition: util-debug.h:335
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:69
SCLogLevel log_level
Definition: util-debug.h:178
SCLogLevel sc_log_global_log_level
Holds the global log level. Is the same as sc_log_config->log_level.
Definition: util-debug.c:97
#define SC_LOG_DEF_SYSLOG_FACILITY_STR
Definition: util-debug.h:105
SCLogOPIfaceCtx * SCLogInitOPIfaceCtx(const char *iface_name, const char *log_format, int log_level, const char *arg)
Creates a new output interface based on the arguments sent. The kind of output interface to be create...
Definition: util-debug.c:1219
#define LOG_WARNING
Definition: win32-syslog.h:43
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
struct HtpBodyChunk_ * next
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
void SCLogInitLogModule(SCLogInitData *sc_lid)
Initializes the logging module.
Definition: util-debug.c:1259
#define BUG_ON(x)
const char * log_format
Definition: util-debug.h:142
SCLogLevel global_log_level
Definition: util-debug.h:159
#define SC_LOG_ENV_LOG_OP_FILTER
Definition: util-debug.h:44
#define PASS
Pass the test.
#define unlikely(expr)
Definition: util-optimize.h:35
Holds the config state used by the logging api.
Definition: util-debug.h:176
char * log_format
Definition: util-debug.h:179
#define SC_LOG_MAX_LOG_MSG_LEN
Definition: util-debug.h:90
SCEnumCharMap * SCSyslogGetFacilityMap(void)
returns the syslog facility enum map
Definition: util-syslog.c:57
int sc_log_module_cleaned
Used to indicate whether the logging module has been cleaned or not.
Definition: util-debug.c:107
SCEnumCharMap sc_log_op_iface_map[]
Definition: util-debug.c:70
const char * startup_message
Definition: util-debug.h:156
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition: util-enum.c:41
char * val
Definition: conf.h:34
const char * op_filter
Definition: util-debug.h:165
Flow * head
Definition: flow-hash.h:102
SCLogOPIface iface
Definition: util-debug.h:122
void unsetenv(const char *name)
#define SC_LOG_DEF_LOG_OP_IFACE
Definition: util-debug.h:99
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:815
int16_t use_color
Definition: util-debug.h:124
#define TRUE
Structure to be used when log_level override support would be provided by the logging module...
Definition: util-debug.h:112
#define SCMutexLock(mut)
SCLogOPIfaceCtx * op_ifaces
Definition: util-debug.h:168
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
void SCLogLoadConfig(int daemon, int verbose)
Definition: util-debug.c:1296
SCLogLevel
The various log levels NOTE: when adding new level, don&#39;t forget to update SCLogMapLogLevelToSyslogLe...
Definition: util-debug.h:51
ThreadVars * TmThreadsGetCallingThread(void)
Returns the TV for the calling thread.
Definition: tm-threads.c:2168
#define LOG_INFO
Definition: win32-syslog.h:45
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:631
#define LOG_ERR
Definition: win32-syslog.h:42
char * startup_message
Definition: util-debug.h:177
uint8_t op_ifaces_cnt
Definition: util-debug.h:170
#define SC_LOG_DEF_LOG_FILE
Definition: util-debug.h:102
const char * file
Definition: util-debug.h:128
Structure containing init data, that would be passed to SCInitDebugModule()
Definition: util-debug.h:154
SCLogLevel log_level
Definition: util-debug.h:139
#define str(s)
#define openlog(__ident, __option, __facility)
Definition: win32-syslog.h:76
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:843
SCEnumCharMap sc_log_level_map[]
Definition: util-debug.c:53
#define SCMutexUnlock(mut)
void OutputRegisterFileRotationFlag(int *flag)
Register a flag for file rotation notification.
Definition: output.c:866
void CreateIsoTimeString(const struct timeval *ts, char *str, size_t size)
Definition: util-time.c:179
SCLogInitData * SCLogAllocLogInitData(void)
Returns a pointer to a new SCLogInitData. This is a public interface intended to be used after the lo...
Definition: util-debug.c:1111
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:232
#define SC_LOG_FMT_FILE_NAME
Definition: util-debug.h:198
#define SC_LOG_FMT_TIME
Definition: util-debug.h:193
SCLogOPType
Definition: util-debug.h:77
uint8_t type
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define SC_LOG_DEF_LOG_FORMAT
Definition: util-debug.h:86
#define SCGetThreadIdLong(...)
Definition: threads.h:253
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
SCError
Definition: util-error.h:29
pcre_extra * op_filter_regex_study
Definition: util-debug.h:184
#define SC_LOG_ENV_LOG_FACILITY
Definition: util-debug.h:42
char msg[SC_LOG_MAX_LOG_MSG_LEN]
Definition: util-debug.h:113
#define SC_LOG_FMT_PID
Definition: util-debug.h:194
#define SC_LOG_DEF_SYSLOG_FACILITY
Definition: util-debug.h:106
#define LOG_CRIT
Definition: win32-syslog.h:41
int ConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:591
SCLogOPIfaceCtx * op_ifaces
Definition: util-debug.h:187
The output interface context for the logging module.
Definition: util-debug.h:121
pcre * op_filter_regex
Definition: util-debug.h:183
int SCLogRemoveFDFilter(const char *function)
Removes a Function-Dependent(FD) filter.
#define SC_LOG_ENV_LOG_FILE
Definition: util-debug.h:41
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:39
int SCLogPrintFGFilters()
Prints the FG filters(both WL and BL). Used for debugging purposes.
#define SC_LOG_FMT_TM
Definition: util-debug.h:196
#define SCMutexInit(mut, mutattrs)
#define closelog()
Definition: win32-syslog.h:75
void setenv(const char *name, const char *value, int overwrite)
#define index
Definition: win32-misc.h:29
#define SC_LOG_ENV_LOG_OP_IFACE
Definition: util-debug.h:40
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
#define LOG_NOTICE
Definition: win32-syslog.h:44
const char * SCErrorToString(SCError err)
Maps the error code, to its string equivalent.
Definition: util-error.c:40
Definition: conf.h:32
const char * ConfigGetLogDirectory()
Definition: util-conf.c:36
#define SCMalloc(a)
Definition: util-mem.h:166
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
const char * log_format
Definition: util-debug.h:115
#define SCFree(a)
Definition: util-mem.h:228
void SCLogReleaseFGFilters(void)
int SCLogAddFGFilterBL(const char *file, const char *function, int line)
Adds a Blacklist(BL) fine-grained(FG) filter. A FG filter BL filter allows messages that don&#39;t match ...
#define LOG_ALERT
Definition: win32-syslog.h:40
int SCLogAddFDFilter(const char *function)
Adds a Function-Dependent(FD) filter.
void SCLogReleaseFDFilters(void)
Releases all the FD filters added to the logging module.
#define LOG_DEBUG
Definition: win32-syslog.h:46
void SCLogAppendOPIfaceCtx(SCLogOPIfaceCtx *iface_ctx, SCLogInitData *sc_lid)
Appends an output_interface to the output_interface list sent in head.
Definition: util-debug.c:1174
const char * global_log_format
Definition: util-debug.h:162
char * name
Definition: conf.h:33
#define FatalError(x,...)
Definition: util-debug.h:539
#define SC_LOG_FMT_TID
Definition: util-debug.h:195
int sc_log_module_initialized
Used to indicate whether the logging module has been init or not.
Definition: util-debug.c:102
#define LOG_EMERG
Definition: win32-syslog.h:39
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:176
#define syslog(__pri, __fmt, __param)
Definition: win32-syslog.h:78
#define SC_LOG_FMT_PREFIX
Definition: util-debug.h:203
struct SCLogOPIfaceCtx_ * next
Definition: util-debug.h:147
#define SCStrdup(a)
Definition: util-mem.h:212
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
char name[16]
Definition: threadvars.h:59
#define pcre_free_study
SCLogOPBuffer * SCLogAllocLogOPBuffer(void)
Allocates an output buffer for an output interface. Used when we want the op_interface log_format to ...
Definition: util-debug.c:650
const char * msg
int SCLogPrintFDFilters(void)
Prints the FG filters(both WL and BL). Used for debugging purposes.
SCMutex fp_mutex
Definition: util-debug.h:145
#define SC_LOG_FMT_LINE
Definition: util-debug.h:199
Per thread variable structure.
Definition: threadvars.h:57
void SCLogRegisterTests()
Definition: util-debug.c:1680
void SCLogDeInitLogModule(void)
De-Initializes the logging module.
Definition: util-debug.c:1477
#define SC_LOG_FMT_FUNCTION
Definition: util-debug.h:200
#define MAX_SUBSTRINGS
char * op_filter
Definition: util-debug.h:181
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
#define SC_LOG_MAX_LOG_FORMAT_LEN
Definition: util-debug.h:93
SCError SCLogMessage(const SCLogLevel log_level, const char *file, const unsigned int line, const char *function, const SCError error_code, const char *message)
Adds the global log_format to the outgoing buffer.
Definition: util-debug.c:548
#define SCMutexDestroy