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