2
* Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary
3
* Copyright (c) 2011 Gergely Nagy <algernon@balabit.hu>
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.
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.
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
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.
25
#include "value-pairs.h"
27
#include "templates.h"
28
#include "cfg-parser.h"
36
GPatternSpec **excludes;
39
/* guint32 as CfgFlagHandler only supports 32 bit integers */
50
VPS_DOT_NV_PAIRS = 0x02,
53
VPS_ALL_MACROS = 0x10,
54
VPS_SELECTED_MACROS = 0x20,
56
VPS_EVERYTHING = 0x7f,
73
static ValuePairSpec rfc3164[] =
75
/* there's one macro named DATE that'll be expanded specially */
86
static ValuePairSpec rfc5424[] =
92
static ValuePairSpec selected_macros[] =
100
static ValuePairSpec *all_macros;
101
static gboolean value_pair_sets_initialized;
103
static CfgFlagHandler value_pair_scope[] =
105
{ "nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_NV_PAIRS },
106
{ "dot-nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_DOT_NV_PAIRS},
107
{ "all-nv-pairs", CFH_SET, offsetof(ValuePairs, scopes), VPS_NV_PAIRS | VPS_DOT_NV_PAIRS },
108
{ "rfc3164", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 },
109
{ "core", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 },
110
{ "base", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC3164 },
111
{ "rfc5424", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC5424 },
112
{ "syslog-proto", CFH_SET, offsetof(ValuePairs, scopes), VPS_RFC5424 },
113
{ "all-macros", CFH_SET, offsetof(ValuePairs, scopes), VPS_ALL_MACROS },
114
{ "selected-macros", CFH_SET, offsetof(ValuePairs, scopes), VPS_SELECTED_MACROS },
115
{ "sdata", CFH_SET, offsetof(ValuePairs, scopes), VPS_SDATA },
116
{ "everything", CFH_SET, offsetof(ValuePairs, scopes), VPS_EVERYTHING },
120
value_pairs_add_scope(ValuePairs *vp, const gchar *scope)
122
return cfg_process_flag(value_pair_scope, vp, scope);
126
value_pairs_add_exclude_glob(ValuePairs *vp, const gchar *pattern)
130
i = vp->exclude_size++;
131
vp->excludes = g_renew(GPatternSpec *, vp->excludes, vp->exclude_size);
132
vp->excludes[i] = g_pattern_spec_new(pattern);
136
value_pairs_add_pair(ValuePairs *vp, GlobalConfig *cfg, const gchar *key, const gchar *value)
138
LogTemplate *t = NULL;
140
t = log_template_new(cfg, NULL);
141
log_template_compile(t, value, NULL);
142
g_hash_table_insert(vp->vpairs, g_strdup(key), t);
145
/* runs over the name-value pairs requested by the user (e.g. with value_pairs_add_pair) */
147
vp_pairs_foreach(gpointer key, gpointer value, gpointer user_data)
149
ValuePairs *vp = ((gpointer *)user_data)[0];
150
LogMessage *msg = ((gpointer *)user_data)[2];
151
gint32 seq_num = GPOINTER_TO_INT (((gpointer *)user_data)[3]);
152
GHashTable *scope_set = ((gpointer *)user_data)[5];
154
g_string_truncate(vp->res, 0);
155
log_template_format((LogTemplate *)value, msg, NULL, LTZ_LOCAL,
156
seq_num, NULL, vp->res);
158
if (!vp->res->str[0])
161
g_hash_table_insert(scope_set, key, vp->res->str);
162
g_string_steal(vp->res);
165
/* runs over the LogMessage nv-pairs, and inserts them unless excluded */
167
vp_msg_nvpairs_foreach(NVHandle handle, gchar *name,
168
const gchar *value, gssize value_len,
171
ValuePairs *vp = ((gpointer *)user_data)[0];
172
GHashTable *scope_set = ((gpointer *)user_data)[5];
175
/* NOTE: dot-nv-pairs include SDATA too */
176
if (((name[0] == '.' && (vp->scopes & VPS_DOT_NV_PAIRS)) ||
177
(name[0] != '.' && (vp->scopes & VPS_NV_PAIRS)) ||
178
(log_msg_is_handle_sdata(handle) && (vp->scopes & VPS_SDATA))))
180
for (j = 0; j < vp->exclude_size; j++)
182
if (g_pattern_match_string(vp->excludes[j], name))
186
/* NOTE: the key is a borrowed reference in the hash, and value is freed */
187
g_hash_table_insert(scope_set, name, g_strndup(value, value_len));
193
/* runs over a set of ValuePairSpec structs and merges them into the value-pair set */
195
vp_merge_set(ValuePairs *vp, LogMessage *msg, gint32 seq_num, ValuePairSpec *set, GHashTable *dest)
199
for (i = 0; set[i].name; i++)
202
gboolean exclude = FALSE;
204
for (j = 0; j < vp->exclude_size; j++)
206
if (g_pattern_match_string(vp->excludes[j], set[i].name))
213
g_string_truncate(vp->res, 0);
217
log_macro_expand(vp->res, set[i].id, FALSE, NULL, LTZ_LOCAL, seq_num, NULL, msg);
224
nv = log_msg_get_value(msg, (NVHandle) set[i].id, &len);
225
g_string_append_len(vp->res, nv, len);
229
g_assert_not_reached();
232
if (!vp->res->str[0])
235
g_hash_table_insert(dest, set[i].name, vp->res->str);
236
g_string_steal(vp->res);
241
value_pairs_foreach (ValuePairs *vp, VPForeachFunc func,
242
LogMessage *msg, gint32 seq_num, gpointer user_data)
244
gpointer args[] = { vp, func, msg, GINT_TO_POINTER (seq_num), user_data, NULL };
245
GHashTable *scope_set;
247
scope_set = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
248
(GDestroyNotify) g_free);
253
* Build up the base set
255
if (vp->scopes & (VPS_NV_PAIRS + VPS_DOT_NV_PAIRS + VPS_SDATA))
256
nv_table_foreach(msg->payload, logmsg_registry,
257
(NVTableForeachFunc) vp_msg_nvpairs_foreach, args);
259
if (vp->scopes & (VPS_RFC3164 + VPS_RFC5424 + VPS_SELECTED_MACROS))
260
vp_merge_set(vp, msg, seq_num, rfc3164, scope_set);
262
if (vp->scopes & VPS_RFC5424)
263
vp_merge_set(vp, msg, seq_num, rfc5424, scope_set);
265
if (vp->scopes & VPS_SELECTED_MACROS)
266
vp_merge_set(vp, msg, seq_num, selected_macros, scope_set);
268
if (vp->scopes & VPS_ALL_MACROS)
269
vp_merge_set(vp, msg, seq_num, all_macros, scope_set);
271
/* Merge the explicit key-value pairs too */
272
g_hash_table_foreach(vp->vpairs, (GHFunc) vp_pairs_foreach, args);
274
/* Aaand we run it through the callback! */
275
g_hash_table_foreach(scope_set, (GHFunc)func, user_data);
277
g_hash_table_destroy(scope_set);
282
value_pairs_init_set(ValuePairSpec *set)
286
for (i = 0; set[i].name; i++)
291
name = set[i].alt_name ? set[i].alt_name : set[i].name;
293
if ((id = log_macro_lookup(name, strlen(name))))
295
set[i].type = VPT_MACRO;
300
set[i].type = VPT_NVPAIR;
301
set[i].id = log_msg_get_value_handle(name);
307
value_pairs_new(void)
313
vp = g_new0(ValuePairs, 1);
314
vp->res = g_string_sized_new(256);
315
vp->vpairs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
316
(GDestroyNotify) log_template_unref);
318
if (!value_pair_sets_initialized)
321
/* NOTE: that we're being only called during config parsing,
322
* thus this code is never threaded. And we only want to perform
323
* it once anyway. If it would be threaded, we'd need to convert
324
* this to a value_pairs_init() function called before anything
327
value_pairs_init_set(rfc3164);
328
value_pairs_init_set(rfc5424);
329
value_pairs_init_set(selected_macros);
331
a = g_array_new(TRUE, TRUE, sizeof(ValuePairSpec));
332
for (i = 0; macros[i].name; i++)
336
pair.name = macros[i].name;
337
pair.type = VPT_MACRO;
338
pair.id = macros[i].id;
339
g_array_append_val(a, pair);
341
all_macros = (ValuePairSpec *) g_array_free(a, FALSE);
343
value_pair_sets_initialized = TRUE;
350
value_pairs_free (ValuePairs *vp)
354
g_hash_table_destroy(vp->vpairs);
356
for (i = 0; i < vp->exclude_size; i++)
357
g_pattern_spec_free(vp->excludes[i]);
358
g_free(vp->excludes);
359
g_string_free(vp->res, TRUE);
363
/* parse a value-pair specification from a command-line like environment */
365
vp_cmdline_parse_scope(const gchar *option_name, const gchar *value,
366
gpointer data, GError **error)
368
gpointer *args = (gpointer *) data;
369
ValuePairs *vp = (ValuePairs *) args[1];
371
if (!value_pairs_add_scope (vp, value))
373
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
374
"Unknon value-pairs scope, scope=%s", value);
381
vp_cmdline_parse_exclude(const gchar *option_name, const gchar *value,
382
gpointer data, GError **error)
384
gpointer *args = (gpointer *) data;
385
ValuePairs *vp = (ValuePairs *) args[1];
387
value_pairs_add_exclude_glob(vp, value);
392
vp_cmdline_parse_key(const gchar *option_name, const gchar *value,
393
gpointer data, GError **error)
395
gpointer *args = (gpointer *) data;
396
ValuePairs *vp = (ValuePairs *) args[1];
397
GlobalConfig *cfg = (GlobalConfig *) args[0];
398
gchar *k = g_strconcat ("$", value, NULL);
400
value_pairs_add_pair(vp, cfg, value, k);
407
vp_cmdline_parse_pair (const gchar *option_name, const gchar *value,
408
gpointer data, GError **error)
410
gpointer *args = (gpointer *) data;
411
ValuePairs *vp = (ValuePairs *) args[1];
412
GlobalConfig *cfg = (GlobalConfig *) args[0];
415
if (!g_strstr_len (value, strlen (value), "="))
417
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
418
"Error parsing value-pairs' key=value pair");
422
kv = g_strsplit(value, "=", 2);
423
value_pairs_add_pair (vp, cfg, kv[0], kv[1]);
433
value_pairs_new_from_cmdline (GlobalConfig *cfg,
434
gint cargc, gchar **cargv,
439
GOptionEntry vp_options[] = {
440
{ "scope", 's', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_scope,
442
{ "exclude", 'x', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_exclude,
444
{ "key", 'k', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_key,
446
{ "pair", 'p', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair,
448
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair,
453
gint argc = cargc + 1;
456
gpointer user_data_args[2];
458
vp = value_pairs_new();
459
user_data_args[0] = cfg;
460
user_data_args[1] = vp;
462
argv = g_new (gchar *, argc + 1);
463
for (i = 0; i < argc; i++)
464
argv[i + 1] = cargv[i];
465
argv[0] = "value-pairs";
468
ctx = g_option_context_new ("value-pairs");
469
og = g_option_group_new (NULL, NULL, NULL, user_data_args, NULL);
470
g_option_group_add_entries (og, vp_options);
471
g_option_context_set_main_group (ctx, og);
473
if (!g_option_context_parse (ctx, &argc, &argv, error))
475
value_pairs_free (vp);
476
g_option_context_free (ctx);
480
g_option_context_free (ctx);