1 /*
2 * Copyright (c) 2002-2013 Balabit
3 * Copyright (c) 1998-2013 Balázs Scheidler
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * As an additional exemption you are allowed to compile & link against the
20 * OpenSSL libraries as published by the OpenSSL project. See the file
21 * COPYING for details.
22 *
23 */
24 #include "template/templates.h"
25 #include "template/repr.h"
26 #include "template/compiler.h"
27 #include "template/macros.h"
28 #include "template/escaping.h"
29 #include "template/repr.h"
30 #include "cfg.h"
31
32 gboolean
log_template_is_literal_string(const LogTemplate * self)33 log_template_is_literal_string(const LogTemplate *self)
34 {
35 if (!self->compiled_template)
36 return TRUE;
37
38 if (self->escape || self->compiled_template->next)
39 return FALSE;
40
41 return log_template_elem_is_literal_string((LogTemplateElem *) self->compiled_template->data);
42 }
43
44 const gchar *
log_template_get_literal_value(const LogTemplate * self,gssize * value_len)45 log_template_get_literal_value(const LogTemplate *self, gssize *value_len)
46 {
47 g_assert(log_template_is_literal_string(self));
48
49 if (!self->compiled_template)
50 return "";
51
52 LogTemplateElem *e = (LogTemplateElem *) self->compiled_template->data;
53
54 if (value_len)
55 *value_len = e->text_len;
56
57 return e->text;
58 }
59
60 gboolean
log_template_is_trivial(LogTemplate * self)61 log_template_is_trivial(LogTemplate *self)
62 {
63 return self->trivial;
64 }
65
66 const gchar *
log_template_get_trivial_value(LogTemplate * self,LogMessage * msg,gssize * value_len)67 log_template_get_trivial_value(LogTemplate *self, LogMessage *msg, gssize *value_len)
68 {
69 g_assert(self->trivial);
70
71 if (!self->compiled_template)
72 return "";
73
74 LogTemplateElem *e = (LogTemplateElem *) self->compiled_template->data;
75
76 switch (e->type)
77 {
78 case LTE_MACRO:
79 if (e->text_len > 0)
80 {
81 if (value_len)
82 *value_len = e->text_len;
83 return e->text;
84 }
85 else if (e->macro == M_MESSAGE)
86 return log_msg_get_value(msg, LM_V_MESSAGE, value_len);
87 else if (e->macro == M_HOST)
88 return log_msg_get_value(msg, LM_V_HOST, value_len);
89 g_assert_not_reached();
90 case LTE_VALUE:
91 return log_msg_get_value(msg, e->value_handle, value_len);
92 default:
93 g_assert_not_reached();
94 }
95 }
96
97 static gboolean
_calculate_triviality(LogTemplate * self)98 _calculate_triviality(LogTemplate *self)
99 {
100 /* if we need to escape, that's not trivial */
101 if (self->escape)
102 return FALSE;
103
104 /* empty templates are trivial */
105 if (self->compiled_template == NULL)
106 return TRUE;
107
108 /* more than one element */
109 if (self->compiled_template->next != NULL)
110 return FALSE;
111
112 const LogTemplateElem *e = (LogTemplateElem *) self->compiled_template->data;
113
114 /* reference to non-last element of the context, that's not trivial */
115 if (e->msg_ref > 0)
116 return FALSE;
117
118 if (log_template_elem_is_literal_string(e))
119 return TRUE;
120
121 switch (e->type)
122 {
123 case LTE_FUNC:
124 /* functions are never trivial */
125 return FALSE;
126 case LTE_MACRO:
127 if (e->text_len > 0)
128 return FALSE;
129
130 /* we have macros for MESSAGE and HOST for compatibility reasons, but
131 * they should be considered trivial */
132
133 if (e->macro == M_MESSAGE || e->macro == M_HOST)
134 return TRUE;
135 return FALSE;
136 case LTE_VALUE:
137 /* values are trivial if they don't contain text */
138 return e->text_len == 0;
139 default:
140 g_assert_not_reached();
141 }
142 }
143
144 static void
log_template_reset_compiled(LogTemplate * self)145 log_template_reset_compiled(LogTemplate *self)
146 {
147 log_template_elem_free_list(self->compiled_template);
148 self->compiled_template = NULL;
149 self->trivial = FALSE;
150 }
151
152 gboolean
log_template_compile(LogTemplate * self,const gchar * template,GError ** error)153 log_template_compile(LogTemplate *self, const gchar *template, GError **error)
154 {
155 LogTemplateCompiler compiler;
156 gboolean result;
157
158 g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
159
160 log_template_reset_compiled(self);
161 if (self->template)
162 g_free(self->template);
163 self->template = g_strdup(template);
164
165 log_template_compiler_init(&compiler, self);
166 result = log_template_compiler_compile(&compiler, &self->compiled_template, error);
167 log_template_compiler_clear(&compiler);
168
169 self->trivial = _calculate_triviality(self);
170 return result;
171 }
172
173 void
log_template_compile_literal_string(LogTemplate * self,const gchar * literal)174 log_template_compile_literal_string(LogTemplate *self, const gchar *literal)
175 {
176 log_template_reset_compiled(self);
177 g_free(self->template);
178 self->template = g_strdup(literal);
179 self->compiled_template = g_list_append(self->compiled_template,
180 log_template_elem_new_macro(literal, M_NONE, NULL, 0));
181
182 self->trivial = _calculate_triviality(self);
183 }
184
185 void
log_template_set_escape(LogTemplate * self,gboolean enable)186 log_template_set_escape(LogTemplate *self, gboolean enable)
187 {
188 self->escape = enable;
189 }
190
191 gboolean
log_template_set_type_hint(LogTemplate * self,const gchar * type_hint,GError ** error)192 log_template_set_type_hint(LogTemplate *self, const gchar *type_hint, GError **error)
193 {
194 g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
195
196 return type_hint_parse(type_hint, &self->type_hint, error);
197 }
198
199 /* NOTE: we should completely get rid off the name property of templates,
200 * we basically use it at two locations:
201 *
202 * 1) dbparser uses it to store SyntheticMessages, there the "name" of a
203 * value is stored here
204 *
205 * 2) we reuse the LogTemplate structure (which represents a compiled
206 * template) to store a template {} statement in the configuration,
207 * which apart from a compiled template, also sports a name. This was
208 * the original reason the name attribute was introduced. This basically
209 * blends two unrelated purposes in the same struct.
210 *
211 * Other call sites pass a dummy value, which is probably never used in any
212 * meaningful way.
213 *
214 * Both usages and the dummy call-sites should be removed, and the entire
215 * thing replaced by another struct that contains a LogTemplate.
216 *
217 * I saw this to cause confusion numerous times already.
218 * --
219 * Bazsi.
220 */
221 void
log_template_set_name(LogTemplate * self,const gchar * name)222 log_template_set_name(LogTemplate *self, const gchar *name)
223 {
224 if (self->name)
225 g_free(self->name);
226 self->name = g_strdup(name);
227 }
228
229 /* NOTE: the name parameter should not be used, please pass a NULL until it is eliminated */
230 LogTemplate *
log_template_new(GlobalConfig * cfg,const gchar * name)231 log_template_new(GlobalConfig *cfg, const gchar *name)
232 {
233 LogTemplate *self = g_new0(LogTemplate, 1);
234
235 log_template_set_name(self, name);
236 g_atomic_counter_set(&self->ref_cnt, 1);
237 self->cfg = cfg;
238 return self;
239 }
240
241 static void
log_template_free(LogTemplate * self)242 log_template_free(LogTemplate *self)
243 {
244 log_template_reset_compiled(self);
245 g_free(self->name);
246 g_free(self->template);
247 g_free(self);
248 }
249
250 LogTemplate *
log_template_ref(LogTemplate * s)251 log_template_ref(LogTemplate *s)
252 {
253 if (s)
254 g_atomic_counter_inc(&s->ref_cnt);
255 return s;
256 }
257
258 void
log_template_unref(LogTemplate * s)259 log_template_unref(LogTemplate *s)
260 {
261 if (s && g_atomic_counter_dec_and_test(&s->ref_cnt))
262 log_template_free(s);
263 }
264
265 /* NOTE: _init needs to be idempotent when called multiple times w/o invoking _destroy */
266 void
log_template_options_init(LogTemplateOptions * options,GlobalConfig * cfg)267 log_template_options_init(LogTemplateOptions *options, GlobalConfig *cfg)
268 {
269 gint i;
270
271 if (options->initialized)
272 return;
273 if (options->ts_format == -1)
274 options->ts_format = cfg->template_options.ts_format;
275 for (i = 0; i < LTZ_MAX; i++)
276 {
277 if (options->time_zone[i] == NULL)
278 options->time_zone[i] = g_strdup(cfg->template_options.time_zone[i]);
279 if (options->time_zone_info[i] == NULL)
280 options->time_zone_info[i] = time_zone_info_new(options->time_zone[i]);
281 }
282
283 if (options->frac_digits == -1)
284 options->frac_digits = cfg->template_options.frac_digits;
285 if (options->on_error == -1)
286 options->on_error = cfg->template_options.on_error;
287 options->use_fqdn = cfg->host_resolve_options.use_fqdn;
288 options->initialized = TRUE;
289 }
290
291 void
log_template_options_destroy(LogTemplateOptions * options)292 log_template_options_destroy(LogTemplateOptions *options)
293 {
294 gint i;
295
296 for (i = 0; i < LTZ_MAX; i++)
297 {
298 if (options->time_zone[i])
299 g_free(options->time_zone[i]);
300 if (options->time_zone_info[i])
301 time_zone_info_free(options->time_zone_info[i]);
302 }
303 options->initialized = FALSE;
304 }
305
306 void
log_template_options_defaults(LogTemplateOptions * options)307 log_template_options_defaults(LogTemplateOptions *options)
308 {
309 memset(options, 0, sizeof(LogTemplateOptions));
310 options->frac_digits = -1;
311 options->ts_format = -1;
312 options->on_error = -1;
313 options->use_fqdn = FALSE;
314 }
315
316 GQuark
log_template_error_quark(void)317 log_template_error_quark(void)
318 {
319 return g_quark_from_static_string("log-template-error-quark");
320 }
321
322 void
log_template_global_init(void)323 log_template_global_init(void)
324 {
325 log_macros_global_init();
326 }
327
328 void
log_template_global_deinit(void)329 log_template_global_deinit(void)
330 {
331 log_macros_global_deinit();
332 }
333
334 gboolean
log_template_on_error_parse(const gchar * strictness,gint * out)335 log_template_on_error_parse(const gchar *strictness, gint *out)
336 {
337 const gchar *p = strictness;
338 gboolean silently = FALSE;
339
340 if (!strictness)
341 {
342 *out = ON_ERROR_DROP_MESSAGE;
343 return TRUE;
344 }
345
346 if (strncmp(strictness, "silently-", strlen("silently-")) == 0)
347 {
348 silently = TRUE;
349 p = strictness + strlen("silently-");
350 }
351
352 if (strcmp(p, "drop-message") == 0)
353 *out = ON_ERROR_DROP_MESSAGE;
354 else if (strcmp(p, "drop-property") == 0)
355 *out = ON_ERROR_DROP_PROPERTY;
356 else if (strcmp(p, "fallback-to-string") == 0)
357 *out = ON_ERROR_FALLBACK_TO_STRING;
358 else
359 return FALSE;
360
361 if (silently)
362 *out |= ON_ERROR_SILENT;
363
364 return TRUE;
365 }
366
367 void
log_template_options_set_on_error(LogTemplateOptions * options,gint on_error)368 log_template_options_set_on_error(LogTemplateOptions *options, gint on_error)
369 {
370 options->on_error = on_error;
371 }
372