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 
25 #include "filter-re.h"
26 #include "str-utils.h"
27 #include "messages.h"
28 #include "scratch-buffers.h"
29 #include <string.h>
30 
31 typedef struct _FilterRE
32 {
33   FilterExprNode super;
34   NVHandle value_handle;
35   LogMatcherOptions matcher_options;
36   LogMatcher *matcher;
37 } FilterRE;
38 
39 
40 static gboolean
filter_re_eval_string(FilterExprNode * s,LogMessage * msg,gint value_handle,const gchar * str,gssize str_len)41 filter_re_eval_string(FilterExprNode *s, LogMessage *msg, gint value_handle, const gchar *str, gssize str_len)
42 {
43   FilterRE *self = (FilterRE *) s;
44   gboolean result;
45 
46   if (str_len < 0)
47     str_len = strlen(str);
48   msg_trace("match() evaluation started",
49             evt_tag_str("input", str),
50             evt_tag_str("pattern", self->matcher->pattern),
51             evt_tag_str("value", log_msg_get_value_name(value_handle, NULL)),
52             evt_tag_printf("msg", "%p", msg));
53   result = log_matcher_match(self->matcher, msg, value_handle, str, str_len);
54   return result ^ s->comp;
55 }
56 
57 static gboolean
filter_re_eval(FilterExprNode * s,LogMessage ** msgs,gint num_msg,LogTemplateEvalOptions * options)58 filter_re_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options)
59 {
60   FilterRE *self = (FilterRE *) s;
61   NVTable *payload;
62   const gchar *value;
63   LogMessage *msg = msgs[num_msg - 1];
64   gssize len = 0;
65   gboolean rc;
66 
67   payload = nv_table_ref(msg->payload);
68   value = log_msg_get_value(msg, self->value_handle, &len);
69   APPEND_ZERO(value, value, len);
70 
71   rc = filter_re_eval_string(s, msg, self->value_handle, value, len);
72 
73   nv_table_unref(payload);
74   return rc;
75 }
76 
77 static void
filter_re_free(FilterExprNode * s)78 filter_re_free(FilterExprNode *s)
79 {
80   FilterRE *self = (FilterRE *) s;
81 
82   log_matcher_unref(self->matcher);
83   log_matcher_options_destroy(&self->matcher_options);
84 }
85 
86 static gboolean
filter_re_init(FilterExprNode * s,GlobalConfig * cfg)87 filter_re_init(FilterExprNode *s, GlobalConfig *cfg)
88 {
89   FilterRE *self = (FilterRE *) s;
90 
91   if (self->matcher_options.flags & LMF_STORE_MATCHES)
92     self->super.modify = TRUE;
93 
94   return TRUE;
95 }
96 
97 LogMatcherOptions *
filter_re_get_matcher_options(FilterExprNode * s)98 filter_re_get_matcher_options(FilterExprNode *s)
99 {
100   FilterRE *self = (FilterRE *) s;
101 
102   return &self->matcher_options;
103 }
104 
105 gboolean
filter_re_compile_pattern(FilterExprNode * s,const gchar * re,GError ** error)106 filter_re_compile_pattern(FilterExprNode *s, const gchar *re, GError **error)
107 {
108   FilterRE *self = (FilterRE *) s;
109 
110   log_matcher_options_init(&self->matcher_options);
111   self->matcher = log_matcher_new(&self->matcher_options);
112   return log_matcher_compile(self->matcher, re, error);
113 }
114 
115 static void
filter_re_init_instance(FilterRE * self,NVHandle value_handle)116 filter_re_init_instance(FilterRE *self, NVHandle value_handle)
117 {
118   filter_expr_node_init_instance(&self->super);
119   self->value_handle = value_handle;
120   self->super.init = filter_re_init;
121   self->super.eval = filter_re_eval;
122   self->super.free_fn = filter_re_free;
123   self->super.type = "regexp";
124   log_matcher_options_defaults(&self->matcher_options);
125   self->matcher_options.flags |= LMF_MATCH_ONLY;
126 }
127 
128 FilterExprNode *
filter_re_new(NVHandle value_handle)129 filter_re_new(NVHandle value_handle)
130 {
131   FilterRE *self = g_new0(FilterRE, 1);
132 
133   filter_re_init_instance(self, value_handle);
134   return &self->super;
135 }
136 
137 FilterExprNode *
filter_source_new(void)138 filter_source_new(void)
139 {
140   FilterRE *self = (FilterRE *) filter_re_new(LM_V_SOURCE);
141 
142   if (!log_matcher_options_set_type(&self->matcher_options, "string"))
143     {
144       /* this can only happen if the plain text string matcher will cease to exist */
145       g_assert_not_reached();
146     }
147   return &self->super;
148 }
149 
150 typedef struct _FilterMatch
151 {
152   FilterRE super;
153   LogTemplate *template;
154 } FilterMatch;
155 
156 gboolean
filter_match_is_usage_obsolete(FilterExprNode * s)157 filter_match_is_usage_obsolete(FilterExprNode *s)
158 {
159   FilterMatch *self = (FilterMatch *) s;
160 
161   return self->super.value_handle == 0 && self->template == NULL;
162 }
163 
164 void
filter_match_set_value_handle(FilterExprNode * s,NVHandle value_handle)165 filter_match_set_value_handle(FilterExprNode *s, NVHandle value_handle)
166 {
167   FilterMatch *self = (FilterMatch *) s;
168 
169   self->super.value_handle = value_handle;
170 }
171 
172 void
filter_match_set_template_ref(FilterExprNode * s,LogTemplate * template)173 filter_match_set_template_ref(FilterExprNode *s, LogTemplate *template)
174 {
175   FilterMatch *self = (FilterMatch *) s;
176 
177   log_template_unref(self->template);
178   self->template = template;
179 }
180 
181 static gboolean
filter_match_eval_against_program_pid_msg(FilterExprNode * s,LogMessage ** msgs,gint num_msg,LogTemplateEvalOptions * options)182 filter_match_eval_against_program_pid_msg(FilterExprNode *s, LogMessage **msgs, gint num_msg,
183                                           LogTemplateEvalOptions *options)
184 {
185   FilterMatch *self = (FilterMatch *) s;
186 
187   const gchar *pid;
188   gssize pid_len;
189   gchar *str;
190   gboolean res;
191   LogMessage *msg = msgs[num_msg - 1];
192 
193   pid = log_msg_get_value(msg, LM_V_PID, &pid_len);
194 
195   /* compatibility mode */
196   str = g_strdup_printf("%s%s%s%s: %s",
197                         log_msg_get_value(msg, LM_V_PROGRAM, NULL),
198                         pid_len > 0 ? "[" : "",
199                         pid,
200                         pid_len > 0 ? "]" : "",
201                         log_msg_get_value(msg, LM_V_MESSAGE, NULL));
202   res = filter_re_eval_string(&self->super.super, msg, LM_V_NONE, str, -1);
203   g_free(str);
204   return res;
205 }
206 
207 static gboolean
filter_match_eval_against_template(FilterExprNode * s,LogMessage ** msgs,gint num_msg,LogTemplateEvalOptions * options)208 filter_match_eval_against_template(FilterExprNode *s, LogMessage **msgs, gint num_msg, LogTemplateEvalOptions *options)
209 {
210   FilterMatch *self = (FilterMatch *) s;
211 
212   LogMessage *msg = msgs[num_msg - 1];
213   GString *buffer;
214 
215   buffer = scratch_buffers_alloc();
216 
217   log_template_format(self->template, msg, options, buffer);
218   return filter_re_eval_string(&self->super.super, msg, LM_V_NONE, buffer->str, buffer->len);
219 }
220 
221 static gboolean
filter_match_eval_against_trivial_template(FilterExprNode * s,LogMessage ** msgs,gint num_msg,LogTemplateEvalOptions * options)222 filter_match_eval_against_trivial_template(FilterExprNode *s, LogMessage **msgs, gint num_msg,
223                                            LogTemplateEvalOptions *options)
224 {
225   FilterMatch *self = (FilterMatch *) s;
226 
227   LogMessage *msg = msgs[num_msg - 1];
228   NVTable *payload;
229   const gchar *value;
230   gssize len = 0;
231   gboolean rc;
232 
233   payload = nv_table_ref(msg->payload);
234   value = log_template_get_trivial_value(self->template, msg, &len);
235   APPEND_ZERO(value, value, len);
236 
237   rc = filter_re_eval_string(&self->super.super, msg, LM_V_NONE, value, len);
238 
239   nv_table_unref(payload);
240   return rc;
241 }
242 
243 static void
filter_match_determine_eval_function(FilterMatch * self)244 filter_match_determine_eval_function(FilterMatch *self)
245 {
246   if (self->super.value_handle)
247     self->super.super.eval = filter_re_eval;
248   else if (self->template && log_template_is_trivial(self->template))
249     self->super.super.eval = filter_match_eval_against_trivial_template;
250   else if (self->template)
251     self->super.super.eval = filter_match_eval_against_template;
252   else
253     self->super.super.eval = filter_match_eval_against_program_pid_msg;
254 }
255 
256 static gboolean
filter_match_init(FilterExprNode * s,GlobalConfig * cfg)257 filter_match_init(FilterExprNode *s, GlobalConfig *cfg)
258 {
259   FilterMatch *self = (FilterMatch *) s;
260 
261   if (!filter_re_init(s, cfg))
262     return FALSE;
263 
264   filter_match_determine_eval_function(self);
265 
266   return TRUE;
267 }
268 
269 static void
filter_match_free(FilterExprNode * s)270 filter_match_free(FilterExprNode *s)
271 {
272   FilterMatch *self = (FilterMatch *) s;
273 
274   log_template_unref(self->template);
275   filter_re_free(&self->super.super);
276 }
277 
278 FilterExprNode *
filter_match_new(void)279 filter_match_new(void)
280 {
281   FilterMatch *self = g_new0(FilterMatch, 1);
282 
283   filter_re_init_instance(&self->super, 0);
284   self->super.super.init = filter_match_init;
285   self->super.super.free_fn = filter_match_free;
286   return &self->super.super;
287 }
288