1 /*
2 * AIDE (Advanced Intrusion Detection Environment)
3 *
4 * Copyright (C) 2020 Hannes von Haugwitz
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <errno.h>
25
26 #include "log.h"
27 #include "locale-aide.h"
28
29 LOG_LEVEL prev_log_level = LOG_LEVEL_UNSET;
30 LOG_LEVEL log_level = LOG_LEVEL_UNSET;
31
32 typedef struct log_cache {
33 LOG_LEVEL level;
34 char *message;
35 } log_cache;
36
37 log_cache *cached_lines = NULL;
38 int ncachedlines = 0;
39
40 struct log_level {
41 LOG_LEVEL log_level;
42 const char *name;
43 const char *log_string;
44 };
45
46 static struct log_level log_level_array[] = {
47 { LOG_LEVEL_ERROR, "error", " ERROR" },
48 { LOG_LEVEL_WARNING, "warning", "WARNING" },
49 { LOG_LEVEL_NOTICE, "notice", " NOTICE" },
50 { LOG_LEVEL_INFO, "info", " INFO" },
51 { LOG_LEVEL_RULE, "rule", " RULE" },
52 { LOG_LEVEL_CONFIG, "config", " CONFIG" },
53 { LOG_LEVEL_DEBUG, "debug", " DEBUG" },
54 { LOG_LEVEL_TRACE, "trace", " TRACE" },
55 { 0, NULL, NULL },
56 };
57
cache_line(LOG_LEVEL level,const char * format,va_list ap)58 static void cache_line(LOG_LEVEL level, const char* format, va_list ap) {
59 int n;
60
61 void * tmp = realloc(cached_lines, (ncachedlines+1) * sizeof(log_cache)); /* freed in log_cached_lines() */
62 if (tmp == NULL) {
63 log_msg(LOG_LEVEL_ERROR, "realloc() failed: %s", strerror(errno));
64 exit(EXIT_FAILURE);
65 } else {
66 cached_lines = tmp;
67 }
68
69 cached_lines[ncachedlines].level = level;
70 cached_lines[ncachedlines].message = NULL;
71
72 va_list aq;
73 va_copy(aq, ap);
74 n = vsnprintf(NULL, 0, format, aq) + 1;
75 va_end(aq);
76
77 cached_lines[ncachedlines].message = malloc(n * sizeof(char)); /* freed in log_cached_lines() */
78 vsnprintf(cached_lines[ncachedlines].message, n, format, ap);
79 ncachedlines++;
80 }
81
get_log_level_name(LOG_LEVEL level)82 const char * get_log_level_name(LOG_LEVEL level) {
83 return level?log_level_array[level-1].name:NULL;
84 }
85
log_cached_lines(void)86 static void log_cached_lines(void) {
87 for(int i = 0; i < ncachedlines; ++i) {
88 log_msg(cached_lines[i].level, "%s", cached_lines[i].message);
89 free(cached_lines[i].message);
90 }
91 ncachedlines = 0;
92 free(cached_lines);
93 }
94
vlog_msg(LOG_LEVEL level,const char * format,va_list ap)95 static void vlog_msg(LOG_LEVEL level,const char* format, va_list ap) {
96 FILE* url = stderr;
97
98 if (level == LOG_LEVEL_ERROR || level <= log_level) {
99 fprintf(url, "%s: ", log_level_array[level-1].log_string );
100 vfprintf(url, format, ap);
101 fprintf(url, "\n");
102 } else if (log_level == LOG_LEVEL_UNSET) {
103 cache_line(level, format, ap);
104 }
105 }
106
is_log_level_unset()107 bool is_log_level_unset() {
108 return log_level == LOG_LEVEL_UNSET;
109 }
110
get_log_level_from_string(char * val)111 LOG_LEVEL get_log_level_from_string(char* val) {
112 struct log_level *level;
113
114 for (level = log_level_array; level->log_level != 0; level++) {
115 if (strcmp(val, level->name) == 0) {
116 return level->log_level;
117 }
118 }
119
120 return LOG_LEVEL_UNSET;
121 }
122
set_log_level(LOG_LEVEL level)123 void set_log_level(LOG_LEVEL level) {
124 log_level = level;
125 if (ncachedlines && level != LOG_LEVEL_UNSET) {
126 log_cached_lines();
127 }
128 }
129
toogle_log_level(LOG_LEVEL level)130 LOG_LEVEL toogle_log_level(LOG_LEVEL level) {
131 if (prev_log_level != LOG_LEVEL_UNSET && log_level != level) {
132 set_log_level(level);
133 } else if (log_level != level || prev_log_level != LOG_LEVEL_UNSET) {
134 if (prev_log_level == LOG_LEVEL_UNSET) {
135 prev_log_level = log_level;
136 set_log_level(level);
137 } else {
138 set_log_level(prev_log_level);
139 prev_log_level = LOG_LEVEL_UNSET;
140 }
141 }
142 return log_level;
143 }
144
log_msg(LOG_LEVEL level,const char * format,...)145 void log_msg(LOG_LEVEL level, const char* format, ...) {
146 va_list argp;
147 va_start(argp, format);
148 vlog_msg(level, format, argp);
149 va_end(argp);
150 }
151