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