1 /*
2 * Copyright (c) 2011-2015 Balabit
3 * Copyright (c) 2011-2014 Gergely Nagy <algernon@balabit.hu>
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 "value-pairs/internals.h"
26 #include "value-pairs/value-pairs.h"
27 #include "logmsg/logmsg.h"
28 #include "template/templates.h"
29 #include "template/macros.h"
30 #include "type-hinting.h"
31 #include "cfg-parser.h"
32 #include "string-list.h"
33 #include "scratch-buffers.h"
34 #include "cfg.h"
35
36 #include <ctype.h>
37
38 typedef struct
39 {
40 GPatternSpec *pattern;
41 gboolean include;
42 } VPPatternSpec;
43
44 typedef struct
45 {
46 gchar *name;
47 LogTemplate *template;
48 } VPPairConf;
49
50 typedef struct
51 {
52 /* we don't own any of the fields here, it is assumed that allocations are
53 * managed by the caller */
54
55 GString *name;
56 GString *value;
57 TypeHint type_hint;
58 } VPResultValue;
59
60 typedef struct
61 {
62 GTree *result_tree;
63
64 /* array of VPResultValue instances */
65 GArray *values;
66 } VPResults;
67
68
69 typedef enum
70 {
71 VPS_NV_PAIRS = 0x01,
72 VPS_DOT_NV_PAIRS = 0x02,
73 VPS_RFC3164 = 0x04,
74 VPS_RFC5424 = 0x08,
75 VPS_ALL_MACROS = 0x10,
76 VPS_SELECTED_MACROS = 0x20,
77 VPS_SDATA = 0x40,
78 VPS_EVERYTHING = 0x7f,
79 } ValuePairScope;
80
81 enum
82 {
83 VPT_MACRO,
84 VPT_NVPAIR,
85 };
86
87 typedef struct
88 {
89 const gchar *name;
90 const gchar *alt_name;
91 gint type;
92 gint id;
93 } ValuePairSpec;
94
95 static ValuePairSpec rfc3164[] =
96 {
97 /* there's one macro named DATE that'll be expanded specially */
98 { "FACILITY" },
99 { "PRIORITY" },
100 { "HOST" },
101 { "PROGRAM" },
102 { "PID" },
103 { "MESSAGE" },
104 { "DATE" },
105 { 0 },
106 };
107
108 static ValuePairSpec rfc5424[] =
109 {
110 { "MSGID", },
111 { 0 },
112 };
113
114 static ValuePairSpec selected_macros[] =
115 {
116 { "TAGS" },
117 { "SOURCEIP" },
118 { "SEQNUM" },
119 { 0 },
120 };
121
122 static ValuePairSpec *all_macros;
123
124 static CfgFlagHandler value_pair_scope[] =
125 {
126 { "nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_NV_PAIRS },
127 { "dot-nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_DOT_NV_PAIRS},
128 { "all-nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_NV_PAIRS | VPS_DOT_NV_PAIRS },
129 { "rfc3164", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 },
130 { "core", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 },
131 { "base", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 },
132 { "rfc5424", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC5424 },
133 { "syslog-proto", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC5424 },
134 { "all-macros", CFH_SET, offsetof(ValuePairs, scopes), VPS_ALL_MACROS },
135 { "selected-macros", CFH_SET, offsetof(ValuePairs, scopes), VPS_SELECTED_MACROS },
136 { "sdata", CFH_SET, offsetof(ValuePairs, scopes), VPS_SDATA },
137 { "everything", CFH_SET, offsetof(ValuePairs, scopes), VPS_EVERYTHING },
138 { NULL, 0, 0, 0},
139 };
140
141
142 static gboolean
vp_pattern_spec_eval(VPPatternSpec * self,const gchar * input)143 vp_pattern_spec_eval(VPPatternSpec *self, const gchar *input)
144 {
145 return g_pattern_match_string(self->pattern, input);
146 }
147
148 static void
vp_pattern_spec_free(VPPatternSpec * self)149 vp_pattern_spec_free(VPPatternSpec *self)
150 {
151 g_pattern_spec_free(self->pattern);
152 g_free(self);
153 }
154
155 static VPPatternSpec *
vp_pattern_spec_new(const gchar * pattern,gboolean include)156 vp_pattern_spec_new(const gchar *pattern, gboolean include)
157 {
158 VPPatternSpec *self = g_new0(VPPatternSpec, 1);
159
160 self->pattern = g_pattern_spec_new(pattern);
161 self->include = include;
162 return self;
163 }
164
165 static VPPairConf *
vp_pair_conf_new(const gchar * key,LogTemplate * value)166 vp_pair_conf_new(const gchar *key, LogTemplate *value)
167 {
168 VPPairConf *p = g_new(VPPairConf, 1);
169
170 p->name = g_strdup(key);
171 p->template = log_template_ref(value);
172 return p;
173 }
174
175 static void
vp_pair_conf_free(VPPairConf * vpc)176 vp_pair_conf_free(VPPairConf *vpc)
177 {
178 log_template_unref(vpc->template);
179 g_free(vpc->name);
180 g_free(vpc);
181 }
182
183 static void
vp_result_value_init(VPResultValue * rv,GString * name,TypeHint type_hint,GString * value)184 vp_result_value_init(VPResultValue *rv, GString *name, TypeHint type_hint, GString *value)
185 {
186 rv->type_hint = type_hint;
187 rv->name = name;
188 rv->value = value;
189 }
190
191 static void
vp_results_init(VPResults * results,GCompareFunc compare_func)192 vp_results_init(VPResults *results, GCompareFunc compare_func)
193 {
194 results->values = g_array_sized_new(FALSE, FALSE, sizeof(VPResultValue), 16);
195 results->result_tree = g_tree_new_full((GCompareDataFunc) compare_func, NULL,
196 NULL, NULL);
197 }
198
199 static void
vp_results_deinit(VPResults * results)200 vp_results_deinit(VPResults *results)
201 {
202 g_tree_destroy(results->result_tree);
203 g_array_free(results->values, TRUE);
204 }
205
206 static void
vp_results_insert(VPResults * results,GString * name,TypeHint type_hint,GString * value)207 vp_results_insert(VPResults *results, GString *name, TypeHint type_hint, GString *value)
208 {
209 VPResultValue *rv;
210 gint ndx = results->values->len;
211
212 g_array_set_size(results->values, ndx + 1);
213 rv = &g_array_index(results->values, VPResultValue, ndx);
214 vp_result_value_init(rv, name, type_hint, value);
215 /* GTree takes over ownership of name */
216 g_tree_insert(results->result_tree, name->str, GINT_TO_POINTER(ndx));
217 }
218
219 static GString *
vp_transform_apply(ValuePairs * vp,const gchar * key)220 vp_transform_apply (ValuePairs *vp, const gchar *key)
221 {
222 gint i;
223 GString *result = scratch_buffers_alloc();
224
225 g_string_assign(result, key);
226
227 if (vp->transforms->len == 0)
228 return result;
229
230 for (i = 0; i < vp->transforms->len; i++)
231 {
232 ValuePairsTransformSet *t = (ValuePairsTransformSet *) g_ptr_array_index(vp->transforms, i);
233
234 value_pairs_transform_set_apply(t, result);
235 }
236
237 return result;
238 }
239
240 /* runs over the name-value pairs requested by the user (e.g. with value_pairs_add_pair) */
241 static void
vp_pairs_foreach(gpointer data,gpointer user_data)242 vp_pairs_foreach(gpointer data, gpointer user_data)
243 {
244 ValuePairs *vp = ((gpointer *)user_data)[0];
245 LogMessage *msg = ((gpointer *)user_data)[2];
246 LogTemplateEvalOptions *options = ((gpointer *)user_data)[3];
247 VPResults *results = ((gpointer *)user_data)[5];
248 GString *sb = scratch_buffers_alloc();
249 VPPairConf *vpc = (VPPairConf *)data;
250
251 log_template_append_format((LogTemplate *)vpc->template, msg, options, sb);
252
253 if (vp->omit_empty_values && sb->len == 0)
254 return;
255 vp_results_insert(results, vp_transform_apply(vp, vpc->name), vpc->template->type_hint, sb);
256 }
257
258 /* runs over the LogMessage nv-pairs, and inserts them unless excluded */
259 static gboolean
vp_msg_nvpairs_foreach(NVHandle handle,gchar * name,const gchar * value,gssize value_len,gpointer user_data)260 vp_msg_nvpairs_foreach(NVHandle handle, gchar *name,
261 const gchar *value, gssize value_len,
262 gpointer user_data)
263 {
264 ValuePairs *vp = ((gpointer *)user_data)[0];
265 VPResults *results = ((gpointer *)user_data)[5];
266 guint j;
267 gboolean inc;
268 GString *sb;
269
270 if (vp->omit_empty_values && value_len == 0)
271 return FALSE;
272
273 inc = (name[0] == '.' && (vp->scopes & VPS_DOT_NV_PAIRS)) ||
274 (name[0] != '.' && (vp->scopes & VPS_NV_PAIRS)) ||
275 (log_msg_is_handle_sdata(handle) && (vp->scopes & (VPS_SDATA + VPS_RFC5424)));
276
277 for (j = 0; j < vp->patterns->len; j++)
278 {
279 VPPatternSpec *vps = (VPPatternSpec *) g_ptr_array_index(vp->patterns, j);
280 if (vp_pattern_spec_eval(vps, name))
281 inc = vps->include;
282 }
283
284 if (!inc)
285 return FALSE;
286
287 sb = scratch_buffers_alloc();
288
289 g_string_append_len(sb, value, value_len);
290 vp_results_insert(results, vp_transform_apply(vp, name), TYPE_HINT_STRING, sb);
291
292 return FALSE;
293 }
294
295 static gboolean
vp_find_in_set(ValuePairs * vp,const gchar * name,gboolean exclude)296 vp_find_in_set(ValuePairs *vp, const gchar *name, gboolean exclude)
297 {
298 guint j;
299 gboolean included = exclude;
300
301 for (j = 0; j < vp->patterns->len; j++)
302 {
303 VPPatternSpec *vps = (VPPatternSpec *) g_ptr_array_index(vp->patterns, j);
304
305 if (vp_pattern_spec_eval(vps, name))
306 included = vps->include;
307 }
308
309 return included;
310 }
311
312 static void
vp_merge_other_set(ValuePairs * vp,ValuePairSpec * set,gboolean exclude)313 vp_merge_other_set(ValuePairs *vp, ValuePairSpec *set, gboolean exclude)
314 {
315 gint i;
316
317 for (i = 0; set[i].name; i++)
318 {
319 if (!vp_find_in_set(vp, set[i].name, exclude))
320 continue;
321
322 g_ptr_array_add(vp->builtins, &set[i]);
323 }
324 }
325
326 /* runs over the all macros and merges the selected ones by the pattern into the value-pair set */
327 static void
vp_merge_macros(ValuePairs * vp)328 vp_merge_macros(ValuePairs *vp)
329 {
330 vp_merge_other_set(vp, all_macros, FALSE);
331 }
332
333 /* runs over a set of ValuePairSpec structs and merges them into the value-pair set */
334 static void
vp_merge_set(ValuePairs * vp,ValuePairSpec * set)335 vp_merge_set(ValuePairs *vp, ValuePairSpec *set)
336 {
337 vp_merge_other_set(vp, set, TRUE);
338 }
339
340
341 static void
vp_update_builtin_list_of_values(ValuePairs * vp)342 vp_update_builtin_list_of_values(ValuePairs *vp)
343 {
344 g_ptr_array_set_size(vp->builtins, 0);
345
346 if (vp->patterns->len > 0)
347 vp_merge_macros(vp);
348
349 if (vp->scopes & (VPS_RFC3164 + VPS_RFC5424 + VPS_SELECTED_MACROS))
350 vp_merge_set(vp, rfc3164);
351
352 if (vp->scopes & VPS_RFC5424)
353 vp_merge_set(vp, rfc5424);
354
355 if (vp->scopes & VPS_SELECTED_MACROS)
356 vp_merge_set(vp, selected_macros);
357
358 if (vp->scopes & VPS_ALL_MACROS)
359 vp_merge_set(vp, all_macros);
360 }
361
362 static void
vp_merge_builtins(ValuePairs * vp,VPResults * results,LogMessage * msg,LogTemplateEvalOptions * options)363 vp_merge_builtins(ValuePairs *vp, VPResults *results, LogMessage *msg, LogTemplateEvalOptions *options)
364 {
365 gint i;
366 GString *sb;
367
368 for (i = 0; i < vp->builtins->len; i++)
369 {
370 ValuePairSpec *spec = (ValuePairSpec *) g_ptr_array_index(vp->builtins, i);
371
372 sb = scratch_buffers_alloc();
373
374 switch (spec->type)
375 {
376 case VPT_MACRO:
377 log_macro_expand(sb, spec->id, FALSE, options, msg);
378 break;
379 case VPT_NVPAIR:
380 {
381 const gchar *nv;
382 gssize len;
383
384 nv = log_msg_get_value(msg, (NVHandle) spec->id, &len);
385 g_string_append_len(sb, nv, len);
386 break;
387 }
388 default:
389 g_assert_not_reached();
390 }
391
392 if (sb->len == 0)
393 {
394 continue;
395 }
396
397 vp_results_insert(results, vp_transform_apply(vp, spec->name), TYPE_HINT_STRING, sb);
398 }
399 }
400
401 static gboolean
vp_foreach_helper(const gchar * name,gpointer ndx_as_pointer,gpointer data)402 vp_foreach_helper(const gchar *name, gpointer ndx_as_pointer, gpointer data)
403 {
404 VPResults *results = ((gpointer *)data)[0];
405 gint ndx = GPOINTER_TO_INT(ndx_as_pointer);
406 VPResultValue *rv = &g_array_index(results->values, VPResultValue, ndx);
407 VPForeachFunc func = ((gpointer *)data)[1];
408 gpointer user_data = ((gpointer *)data)[2];
409 gboolean *r = ((gpointer *)data)[3];
410
411 *r &= !func(name, rv->type_hint,
412 rv->value->str,
413 rv->value->len, user_data);
414 return !*r;
415 }
416
417
418 gboolean
value_pairs_foreach_sorted(ValuePairs * vp,VPForeachFunc func,GCompareFunc compare_func,LogMessage * msg,LogTemplateEvalOptions * options,gpointer user_data)419 value_pairs_foreach_sorted (ValuePairs *vp, VPForeachFunc func,
420 GCompareFunc compare_func,
421 LogMessage *msg, LogTemplateEvalOptions *options,
422 gpointer user_data)
423 {
424 gpointer args[] = { vp, func, msg, options, user_data, NULL};
425 gboolean result = TRUE;
426 VPResults results;
427 gpointer helper_args[] = { &results, func, user_data, &result };
428 ScratchBuffersMarker mark;
429
430 scratch_buffers_mark(&mark);
431 vp_results_init(&results, compare_func);
432 args[5] = &results;
433
434 /*
435 * Build up the base set
436 */
437 if (vp->scopes & (VPS_NV_PAIRS + VPS_DOT_NV_PAIRS + VPS_SDATA + VPS_RFC5424) ||
438 vp->patterns->len > 0)
439 nv_table_foreach(msg->payload, logmsg_registry,
440 (NVTableForeachFunc) vp_msg_nvpairs_foreach, args);
441
442 vp_merge_builtins(vp, &results, msg, options);
443
444 /* Merge the explicit key-value pairs too */
445 g_ptr_array_foreach(vp->vpairs, (GFunc)vp_pairs_foreach, args);
446
447 /* Aaand we run it through the callback! */
448 g_tree_foreach(results.result_tree, (GTraverseFunc)vp_foreach_helper, helper_args);
449 vp_results_deinit(&results);
450 scratch_buffers_reclaim_marked(mark);
451
452 return result;
453 }
454
455 gboolean
value_pairs_foreach(ValuePairs * vp,VPForeachFunc func,LogMessage * msg,LogTemplateEvalOptions * options,gpointer user_data)456 value_pairs_foreach(ValuePairs *vp, VPForeachFunc func,
457 LogMessage *msg, LogTemplateEvalOptions *options,
458 gpointer user_data)
459 {
460 return value_pairs_foreach_sorted(vp, func, (GCompareFunc) strcmp,
461 msg, options, user_data);
462 }
463
464 /*******************************************************************************
465 * vp_stack (represented by vp_stack_t)
466 *
467 * A not very generic stack implementation used by vp_walker.
468 *******************************************************************************/
469
470 #define VP_STACK_INITIAL_SIZE 16
471
472 typedef struct
473 {
474 GPtrArray *elems;
475 } vp_stack_t;
476
477 static void
vp_stack_init(vp_stack_t * stack)478 vp_stack_init(vp_stack_t *stack)
479 {
480 stack->elems = g_ptr_array_sized_new(VP_STACK_INITIAL_SIZE);
481 }
482
483 static void
vp_stack_destroy(vp_stack_t * stack)484 vp_stack_destroy(vp_stack_t *stack)
485 {
486 g_ptr_array_free(stack->elems, TRUE);
487 }
488
489 static void
vp_stack_push(vp_stack_t * stack,gpointer data)490 vp_stack_push(vp_stack_t *stack, gpointer data)
491 {
492 g_ptr_array_add(stack->elems, data);
493 }
494
495 static gpointer
vp_stack_peek(vp_stack_t * stack)496 vp_stack_peek(vp_stack_t *stack)
497 {
498 if (stack->elems->len == 0)
499 return NULL;
500
501 return g_ptr_array_index(stack->elems, stack->elems->len - 1);
502 }
503
504 static gpointer
vp_stack_pop(vp_stack_t * stack)505 vp_stack_pop(vp_stack_t *stack)
506 {
507 gpointer data = NULL;
508
509 data = vp_stack_peek(stack);
510 if (data)
511 g_ptr_array_remove_index(stack->elems, stack->elems->len - 1);
512 return data;
513 }
514
515 static guint
vp_stack_height(vp_stack_t * stack)516 vp_stack_height(vp_stack_t *stack)
517 {
518 return stack->elems->len;
519 }
520
521 /*******************************************************************************
522 * vp_walker (represented by vp_walk_state_t),
523 *
524 * The stuff that translates name-value pairs to a tree with SAX like
525 * callbacks. (start/value/end)
526 *******************************************************************************/
527
528 typedef struct
529 {
530 gchar *key;
531 gchar *prefix;
532 gint prefix_len;
533
534 gpointer data;
535 } vp_walk_stack_data_t;
536
537 typedef struct
538 {
539 VPWalkCallbackFunc obj_start;
540 VPWalkCallbackFunc obj_end;
541 VPWalkValueCallbackFunc process_value;
542
543 gpointer user_data;
544 vp_stack_t stack;
545 } vp_walk_state_t;
546
547 static vp_walk_stack_data_t *
vp_walker_stack_push(vp_stack_t * stack,gchar * key,gchar * prefix)548 vp_walker_stack_push (vp_stack_t *stack,
549 gchar *key, gchar *prefix)
550 {
551 vp_walk_stack_data_t *nt = g_new(vp_walk_stack_data_t, 1);
552
553 nt->key = key;
554 nt->prefix = prefix;
555 nt->prefix_len = strlen(nt->prefix);
556 nt->data = NULL;
557
558 vp_stack_push(stack, nt);
559 return nt;
560 }
561
562 static vp_walk_stack_data_t *
vp_walker_stack_peek(vp_stack_t * stack)563 vp_walker_stack_peek(vp_stack_t *stack)
564 {
565 return (vp_walk_stack_data_t *) vp_stack_peek(stack);
566 }
567
568 static vp_walk_stack_data_t *
vp_walker_stack_pop(vp_stack_t * stack)569 vp_walker_stack_pop(vp_stack_t *stack)
570 {
571 return (vp_walk_stack_data_t *) vp_stack_pop(stack);
572 }
573
574 static void
vp_walker_free_stack_data(vp_walk_stack_data_t * t)575 vp_walker_free_stack_data(vp_walk_stack_data_t *t)
576 {
577 g_free(t->key);
578 g_free(t->prefix);
579 g_free(t);
580 }
581
582 static void
vp_walker_stack_unwind_containers_until(vp_walk_state_t * state,const gchar * name)583 vp_walker_stack_unwind_containers_until(vp_walk_state_t *state,
584 const gchar *name)
585 {
586 vp_walk_stack_data_t *t;
587
588 while ((t = vp_walker_stack_pop(&state->stack)) != NULL)
589 {
590 vp_walk_stack_data_t *p;
591
592 if (name && strncmp(name, t->prefix, t->prefix_len) == 0)
593 {
594 /* This one matched, put it back, PUT IT BACK! */
595 vp_stack_push(&state->stack, t);
596 break;
597 }
598
599 p = vp_walker_stack_peek(&state->stack);
600
601 if (p)
602 state->obj_end(t->key, t->prefix, &t->data,
603 p->prefix, &p->data,
604 state->user_data);
605 else
606 state->obj_end(t->key, t->prefix, &t->data,
607 NULL, NULL,
608 state->user_data);
609 vp_walker_free_stack_data(t);
610 }
611 }
612
613 static void
vp_walker_stack_unwind_all_containers(vp_walk_state_t * state)614 vp_walker_stack_unwind_all_containers(vp_walk_state_t *state)
615 {
616 vp_walker_stack_unwind_containers_until(state, NULL);
617 }
618
619 static const gchar *
vp_walker_skip_sdata_enterprise_id(const gchar * name)620 vp_walker_skip_sdata_enterprise_id(const gchar *name)
621 {
622 /* parse .SDATA.foo@1234.56.678 format, starting with the '@'
623 character. Assume that any numbers + dots form part of the
624 "foo@1234.56.678" key, even if they contain dots */
625 do
626 {
627 /* skip @ or . */
628 ++name;
629 name += strspn(name, "0123456789");
630 }
631 while (*name == '.' && isdigit(*(name + 1)));
632 return name;
633 }
634
635 static GPtrArray *
vp_walker_split_name_to_tokens(vp_walk_state_t * state,const gchar * name)636 vp_walker_split_name_to_tokens(vp_walk_state_t *state, const gchar *name)
637 {
638 const gchar *token_start = name;
639 const gchar *token_end = name;
640
641 GPtrArray *array = g_ptr_array_sized_new(VP_STACK_INITIAL_SIZE);
642
643 while (*token_end)
644 {
645 switch (*token_end)
646 {
647 case '@':
648 token_end = vp_walker_skip_sdata_enterprise_id(token_end);
649 break;
650 case '.':
651 if (token_start != token_end)
652 {
653 g_ptr_array_add(array, g_strndup(token_start, token_end - token_start));
654 ++token_end;
655 token_start = token_end;
656 break;
657 }
658 /* fall through, zero length token is not considered a separate token */
659 default:
660 ++token_end;
661 token_end += strcspn(token_end, "@.");
662 break;
663 }
664 }
665
666 if (token_start != token_end)
667 g_ptr_array_add(array, g_strndup(token_start, token_end - token_start));
668
669 if (array->len == 0)
670 {
671 g_ptr_array_free(array, TRUE);
672 return NULL;
673 }
674
675 return array;
676 }
677
678 static gchar *
vp_walker_name_combine_prefix(GPtrArray * tokens,gint until)679 vp_walker_name_combine_prefix(GPtrArray *tokens, gint until)
680 {
681 GString *s = scratch_buffers_alloc();
682 gchar *str;
683 gint i;
684
685 for (i = 0; i < until; i++)
686 {
687 g_string_append(s, g_ptr_array_index(tokens, i));
688 g_string_append_c(s, '.');
689 }
690 g_string_append(s, g_ptr_array_index(tokens, until));
691
692 str = g_strdup(s->str);
693 return str;
694 }
695
696 static gchar *
vp_walker_start_containers_for_name(vp_walk_state_t * state,const gchar * name)697 vp_walker_start_containers_for_name(vp_walk_state_t *state,
698 const gchar *name)
699 {
700 GPtrArray *tokens;
701 gchar *key = NULL;
702 guint i, start;
703
704 tokens = vp_walker_split_name_to_tokens(state, name);
705
706 start = vp_stack_height(&state->stack);
707 for (i = start; i < tokens->len - 1; i++)
708 {
709 vp_walk_stack_data_t *p, *nt;
710
711 p = vp_walker_stack_peek(&state->stack);
712 nt = vp_walker_stack_push(&state->stack,
713 g_strdup(g_ptr_array_index(tokens, i)),
714 vp_walker_name_combine_prefix(tokens, i));
715
716 if (p)
717 state->obj_start(nt->key, nt->prefix, &nt->data,
718 p->prefix, &p->data,
719 state->user_data);
720 else
721 state->obj_start(nt->key, nt->prefix, &nt->data,
722 NULL, NULL, state->user_data);
723 }
724
725 /* The last token is the key (well, second to last, last being
726 NULL), so treat that normally. */
727 key = g_ptr_array_index(tokens, tokens->len - 1);
728 g_ptr_array_index(tokens, tokens->len - 1) = NULL;
729
730 g_ptr_array_foreach(tokens, (GFunc)g_free, NULL);
731 g_ptr_array_free(tokens, TRUE);
732
733 return key;
734 }
735
736 static gboolean
value_pairs_walker(const gchar * name,TypeHint type,const gchar * value,gsize value_len,gpointer user_data)737 value_pairs_walker(const gchar *name, TypeHint type, const gchar *value, gsize value_len,
738 gpointer user_data)
739 {
740 vp_walk_state_t *state = (vp_walk_state_t *)user_data;
741 vp_walk_stack_data_t *data;
742 gchar *key;
743 gboolean result;
744
745 vp_walker_stack_unwind_containers_until(state, name);
746 key = vp_walker_start_containers_for_name(state, name);
747 data = vp_walker_stack_peek(&state->stack);
748
749 if (data != NULL)
750 result = state->process_value(key, data->prefix,
751 type, value, value_len,
752 &data->data,
753 state->user_data);
754 else
755 result = state->process_value(key, NULL,
756 type, value, value_len,
757 NULL,
758 state->user_data);
759
760 g_free(key);
761
762 return result;
763 }
764
765 static gint
vp_walk_cmp(const gchar * s1,const gchar * s2)766 vp_walk_cmp(const gchar *s1, const gchar *s2)
767 {
768 return strcmp(s2, s1);
769 }
770
771 /*******************************************************************************
772 * Public API
773 *******************************************************************************/
774
775 gboolean
value_pairs_walk(ValuePairs * vp,VPWalkCallbackFunc obj_start_func,VPWalkValueCallbackFunc process_value_func,VPWalkCallbackFunc obj_end_func,LogMessage * msg,LogTemplateEvalOptions * options,gpointer user_data)776 value_pairs_walk(ValuePairs *vp,
777 VPWalkCallbackFunc obj_start_func,
778 VPWalkValueCallbackFunc process_value_func,
779 VPWalkCallbackFunc obj_end_func,
780 LogMessage *msg, LogTemplateEvalOptions *options,
781 gpointer user_data)
782 {
783 vp_walk_state_t state;
784 gboolean result;
785
786 state.user_data = user_data;
787 state.obj_start = obj_start_func;
788 state.obj_end = obj_end_func;
789 state.process_value = process_value_func;
790 vp_stack_init(&state.stack);
791
792 state.obj_start(NULL, NULL, NULL, NULL, NULL, user_data);
793 result = value_pairs_foreach_sorted(vp, value_pairs_walker,
794 (GCompareFunc)vp_walk_cmp, msg,
795 options, &state);
796 vp_walker_stack_unwind_all_containers(&state);
797 state.obj_end(NULL, NULL, NULL, NULL, NULL, user_data);
798 vp_stack_destroy(&state.stack);
799
800 return result;
801 }
802
803 gboolean
value_pairs_add_scope(ValuePairs * vp,const gchar * scope)804 value_pairs_add_scope(ValuePairs *vp, const gchar *scope)
805 {
806 gboolean result;
807
808 if (strcmp(scope, "none") != 0)
809 {
810 result = cfg_process_flag(value_pair_scope, vp, scope);
811 vp_update_builtin_list_of_values(vp);
812 }
813 else
814 {
815 result = TRUE;
816 vp->scopes = 0;
817 vp_update_builtin_list_of_values(vp);
818 }
819 return result;
820 }
821
822 void
value_pairs_add_glob_pattern(ValuePairs * vp,const gchar * pattern,gboolean include)823 value_pairs_add_glob_pattern(ValuePairs *vp, const gchar *pattern,
824 gboolean include)
825 {
826 g_ptr_array_add(vp->patterns, vp_pattern_spec_new(pattern, include));
827 vp_update_builtin_list_of_values(vp);
828 }
829
830 void
value_pairs_add_glob_patterns(ValuePairs * vp,GList * patterns,gboolean include)831 value_pairs_add_glob_patterns(ValuePairs *vp, GList *patterns, gboolean include)
832 {
833 GList *l = patterns;
834
835 while (l)
836 {
837 value_pairs_add_glob_pattern(vp, (gchar *)l->data, include);
838 l = g_list_next (l);
839 }
840 string_list_free(patterns);
841 vp_update_builtin_list_of_values(vp);
842 }
843
844 void
value_pairs_add_pair(ValuePairs * vp,const gchar * key,LogTemplate * value)845 value_pairs_add_pair(ValuePairs *vp, const gchar *key, LogTemplate *value)
846 {
847 g_ptr_array_add(vp->vpairs, vp_pair_conf_new(key, value));
848 vp_update_builtin_list_of_values(vp);
849 }
850
851 void
value_pairs_add_transforms(ValuePairs * vp,ValuePairsTransformSet * vpts)852 value_pairs_add_transforms(ValuePairs *vp, ValuePairsTransformSet *vpts)
853 {
854 g_ptr_array_add(vp->transforms, vpts);
855 vp_update_builtin_list_of_values(vp);
856 }
857
858 ValuePairs *
value_pairs_new(void)859 value_pairs_new(void)
860 {
861 ValuePairs *vp;
862
863 vp = g_new0(ValuePairs, 1);
864 g_atomic_counter_set(&vp->ref_cnt, 1);
865 vp->builtins = g_ptr_array_new();
866 vp->vpairs = g_ptr_array_new();
867 vp->patterns = g_ptr_array_new();
868 vp->transforms = g_ptr_array_new();
869
870 return vp;
871 }
872
873 ValuePairs *
value_pairs_new_default(GlobalConfig * cfg)874 value_pairs_new_default(GlobalConfig *cfg)
875 {
876 ValuePairs *vp = value_pairs_new();
877
878 value_pairs_add_scope(vp, "selected-macros");
879 value_pairs_add_scope(vp, "nv-pairs");
880 value_pairs_add_scope(vp, "sdata");
881 return vp;
882 }
883
884 static void
value_pairs_free(ValuePairs * vp)885 value_pairs_free (ValuePairs *vp)
886 {
887 guint i;
888
889 for (i = 0; i < vp->vpairs->len; i++)
890 vp_pair_conf_free(g_ptr_array_index(vp->vpairs, i));
891
892 g_ptr_array_free(vp->vpairs, TRUE);
893
894 for (i = 0; i < vp->patterns->len; i++)
895 {
896 VPPatternSpec *vps = (VPPatternSpec *) g_ptr_array_index(vp->patterns, i);
897 vp_pattern_spec_free(vps);
898 }
899 g_ptr_array_free(vp->patterns, TRUE);
900
901 for (i = 0; i < vp->transforms->len; i++)
902 {
903 ValuePairsTransformSet *vpts = (ValuePairsTransformSet *) g_ptr_array_index(vp->transforms, i);
904 value_pairs_transform_set_free(vpts);
905 }
906 g_ptr_array_free(vp->transforms, TRUE);
907 g_ptr_array_free(vp->builtins, TRUE);
908 g_free(vp);
909 }
910
911 ValuePairs *
value_pairs_ref(ValuePairs * self)912 value_pairs_ref(ValuePairs *self)
913 {
914 g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0);
915
916 if (self)
917 {
918 g_atomic_counter_inc(&self->ref_cnt);
919 }
920 return self;
921 }
922
923 void
value_pairs_unref(ValuePairs * self)924 value_pairs_unref(ValuePairs *self)
925 {
926 if (self)
927 {
928 g_assert(g_atomic_counter_get(&self->ref_cnt) > 0);
929
930 if (g_atomic_counter_dec_and_test(&self->ref_cnt))
931 value_pairs_free(self);
932 }
933 }
934
935 static void
value_pairs_init_set(ValuePairSpec * set)936 value_pairs_init_set(ValuePairSpec *set)
937 {
938 gint i;
939
940 for (i = 0; set[i].name; i++)
941 {
942 guint id;
943 const gchar *name;
944
945 name = set[i].alt_name ? set[i].alt_name : set[i].name;
946
947 if ((id = log_macro_lookup(name, strlen(name))))
948 {
949 set[i].type = VPT_MACRO;
950 set[i].id = id;
951 }
952 else
953 {
954 set[i].type = VPT_NVPAIR;
955 set[i].id = log_msg_get_value_handle(name);
956 }
957 }
958 }
959
960 void
value_pairs_global_init(void)961 value_pairs_global_init(void)
962 {
963 gint i = 0;
964 GArray *a;
965
966 value_pairs_init_set(rfc3164);
967 value_pairs_init_set(rfc5424);
968 value_pairs_init_set(selected_macros);
969
970 a = g_array_new(TRUE, TRUE, sizeof(ValuePairSpec));
971 for (i = 0; macros[i].name; i++)
972 {
973 ValuePairSpec pair;
974
975 pair.name = macros[i].name;
976 pair.type = VPT_MACRO;
977 pair.id = macros[i].id;
978 g_array_append_val(a, pair);
979 }
980 all_macros = (ValuePairSpec *) g_array_free(a, FALSE);
981 }
982
983 void
value_pairs_global_deinit(void)984 value_pairs_global_deinit(void)
985 {
986 g_free(all_macros);
987 }
988