1 /*
2  * Copyright (c) 2020 Balabit
3  * Copyright (c) 2020 Balazs Scheidler <bazsi77@gmail.com>
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 
25 #include "eval.h"
26 #include "repr.h"
27 #include "macros.h"
28 #include "escaping.h"
29 #include "cfg.h"
30 
31 void
log_template_append_format_with_context(LogTemplate * self,LogMessage ** messages,gint num_messages,LogTemplateEvalOptions * options,GString * result)32 log_template_append_format_with_context(LogTemplate *self, LogMessage **messages, gint num_messages,
33                                         LogTemplateEvalOptions *options, GString *result)
34 {
35   GList *p;
36   LogTemplateElem *e;
37 
38   if (!options->opts)
39     options->opts = &self->cfg->template_options;
40 
41   for (p = self->compiled_template; p; p = g_list_next(p))
42     {
43       gint msg_ndx;
44 
45       e = (LogTemplateElem *) p->data;
46       if (e->text)
47         {
48           g_string_append_len(result, e->text, e->text_len);
49         }
50 
51       /* NOTE: msg_ref is 1 larger than the index specified by the user in
52        * order to make it distinguishable from the zero value.  Therefore
53        * the '>' instead of '>='
54        *
55        * msg_ref == 0 means that the user didn't specify msg_ref
56        * msg_ref >= 1 means that the user supplied the given msg_ref, 1 is equal to @0 */
57       if (e->msg_ref > num_messages)
58         continue;
59       msg_ndx = num_messages - e->msg_ref;
60 
61       /* value and macro can't understand a context, assume that no msg_ref means @0 */
62       if (e->msg_ref == 0)
63         msg_ndx--;
64 
65       switch (e->type)
66         {
67         case LTE_VALUE:
68         {
69           const gchar *value = NULL;
70           gssize value_len = -1;
71 
72           value = log_msg_get_value(messages[msg_ndx], e->value_handle, &value_len);
73           if (value && value[0])
74             result_append(result, value, value_len, self->escape);
75           else if (e->default_value)
76             result_append(result, e->default_value, -1, self->escape);
77           break;
78         }
79         case LTE_MACRO:
80         {
81           gint len = result->len;
82 
83           if (e->macro)
84             {
85               log_macro_expand(result, e->macro, self->escape, options, messages[msg_ndx]);
86               if (len == result->len && e->default_value)
87                 g_string_append(result, e->default_value);
88             }
89           break;
90         }
91         case LTE_FUNC:
92         {
93           if (1)
94             {
95               LogTemplateInvokeArgs args =
96               {
97                 e->msg_ref ? &messages[msg_ndx] : messages,
98                 e->msg_ref ? 1 : num_messages,
99                 options,
100               };
101 
102 
103               /* if a function call is called with an msg_ref, we only
104                * pass that given logmsg to argument resolution, otherwise
105                * we pass the whole set so the arguments can individually
106                * specify which message they want to resolve from
107                */
108               if (e->func.ops->eval)
109                 e->func.ops->eval(e->func.ops, e->func.state, &args);
110               e->func.ops->call(e->func.ops, e->func.state, &args, result);
111             }
112           break;
113         }
114         default:
115           g_assert_not_reached();
116           break;
117         }
118     }
119 }
120 
121 void
log_template_format_with_context(LogTemplate * self,LogMessage ** messages,gint num_messages,LogTemplateEvalOptions * options,GString * result)122 log_template_format_with_context(LogTemplate *self, LogMessage **messages, gint num_messages,
123                                  LogTemplateEvalOptions *options, GString *result)
124 {
125   g_string_truncate(result, 0);
126   log_template_append_format_with_context(self, messages, num_messages, options, result);
127 }
128 
129 void
log_template_append_format(LogTemplate * self,LogMessage * lm,LogTemplateEvalOptions * options,GString * result)130 log_template_append_format(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result)
131 {
132   log_template_append_format_with_context(self, &lm, 1, options, result);
133 }
134 
135 void
log_template_format(LogTemplate * self,LogMessage * lm,LogTemplateEvalOptions * options,GString * result)136 log_template_format(LogTemplate *self, LogMessage *lm, LogTemplateEvalOptions *options, GString *result)
137 {
138   g_string_truncate(result, 0);
139   log_template_append_format(self, lm, options, result);
140 }
141