~ubuntu-branches/ubuntu/trusty/syslog-ng/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/value-pairs.c

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS), Gergely Nagy
  • Date: 2011-10-11 14:30:48 UTC
  • mfrom: (1.3.7)
  • Revision ID: package-import@ubuntu.com-20111011143048-r1iljux9xbvj3lwh
Tags: 3.3.1.dfsg-1
* New upstream release with important fixes from upstream git tree with
  non-free manpages removed.
* Drop syslog-ng.conf(5) (closes: #496521).
* syslog-ng(8) is generated, and does not mention -Q anymore
  (closes: #616069).
* Supports CAP_SYSLOG on recent kernels (closes: #630172).
* Does not use g_timeout_add_seconds anymore (closes: #609154).

[ Gergely Nagy <algernon@madhouse-project.org> ]
* Update debian/copyright to DEP-5 format.
* Simplified the logrotate file by merging identical entries.
* Include local configuration files from /etc/syslog-ng/conf.d/ (Closes:
  #609050).
* Update syslog-ng.conf to be fully 3.3 compliant.
* Compress both source and binaries (except the syslog-ng meta
  package) with xz, instead of gzip.
* Use dpkg triggers to restart syslog-ng when appropriate.
* Include DFSG-free manual pages for all binaries.
* Build with Hardening enabled.
* Mention syslog(3) in /etc/default/syslog-ng, instead of
  <linux/kernel.h> (Closes: #608605)
* Support 'status' in the init script.
  Patch from Peter Eisentraut <petere@debian.org> (Closes: #644458)
* Build-Depend on libevtlog-dev (>= 0.2.12-5~) for correct shlibs.
* Use [linux-any] in Build-Depends instead of hardcoded links.
  (Closes: #634715)
* Use $SYSLOGNG_OPTS in the init script when reloading syslog-ng.
  (Closes: #589081)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary
 
3
 * Copyright (c) 2011 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.h"
 
26
#include "logmsg.h"
 
27
#include "templates.h"
 
28
#include "cfg-parser.h"
 
29
#include "misc.h"
 
30
 
 
31
#include <string.h>
 
32
 
 
33
 
 
34
struct _ValuePairs
 
35
{
 
36
  GPatternSpec **excludes;
 
37
  GHashTable *vpairs;
 
38
 
 
39
  /* guint32 as CfgFlagHandler only supports 32 bit integers */
 
40
  guint32 scopes;
 
41
  guint32 exclude_size;
 
42
 
 
43
  /* Temporary */
 
44
  GString *res;
 
45
};
 
46
 
 
47
typedef enum
 
48
{
 
49
  VPS_NV_PAIRS        = 0x01,
 
50
  VPS_DOT_NV_PAIRS    = 0x02,
 
51
  VPS_RFC3164         = 0x04,
 
52
  VPS_RFC5424         = 0x08,
 
53
  VPS_ALL_MACROS      = 0x10,
 
54
  VPS_SELECTED_MACROS = 0x20,
 
55
  VPS_SDATA           = 0x40,
 
56
  VPS_EVERYTHING      = 0x7f,
 
57
} ValuePairScope;
 
58
 
 
59
enum
 
60
{
 
61
  VPT_MACRO,
 
62
  VPT_NVPAIR,
 
63
};
 
64
 
 
65
typedef struct
 
66
{
 
67
  gchar *name;
 
68
  gchar *alt_name;
 
69
  gint type;
 
70
  gint id;
 
71
} ValuePairSpec;
 
72
 
 
73
static ValuePairSpec rfc3164[] =
 
74
{
 
75
  /* there's one macro named DATE that'll be expanded specially */
 
76
  { "FACILITY" },
 
77
  { "PRIORITY" },
 
78
  { "HOST"     },
 
79
  { "PROGRAM"  },
 
80
  { "PID"      },
 
81
  { "MESSAGE"  },
 
82
  { "DATE", "R_DATE" },
 
83
  { 0 },
 
84
};
 
85
 
 
86
static ValuePairSpec rfc5424[] =
 
87
{
 
88
  { "MSGID", },
 
89
  { 0 },
 
90
};
 
91
 
 
92
static ValuePairSpec selected_macros[] =
 
93
{
 
94
  { "TAGS" },
 
95
  { "SOURCEIP" },
 
96
  { "SEQNUM" },
 
97
  { 0 },
 
98
};
 
99
 
 
100
static ValuePairSpec *all_macros;
 
101
static gboolean value_pair_sets_initialized;
 
102
 
 
103
static CfgFlagHandler value_pair_scope[] =
 
104
{
 
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 },
 
117
};
 
118
 
 
119
gboolean
 
120
value_pairs_add_scope(ValuePairs *vp, const gchar *scope)
 
121
{
 
122
  return cfg_process_flag(value_pair_scope, vp, scope);
 
123
}
 
124
 
 
125
void
 
126
value_pairs_add_exclude_glob(ValuePairs *vp, const gchar *pattern)
 
127
{
 
128
  gint i;
 
129
 
 
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);
 
133
}
 
134
 
 
135
void
 
136
value_pairs_add_pair(ValuePairs *vp, GlobalConfig *cfg, const gchar *key, const gchar *value)
 
137
{
 
138
  LogTemplate *t = NULL;
 
139
 
 
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);
 
143
}
 
144
 
 
145
/* runs over the name-value pairs requested by the user (e.g. with value_pairs_add_pair) */
 
146
static void
 
147
vp_pairs_foreach(gpointer key, gpointer value, gpointer user_data)
 
148
{
 
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];
 
153
 
 
154
  g_string_truncate(vp->res, 0);
 
155
  log_template_format((LogTemplate *)value, msg, NULL, LTZ_LOCAL,
 
156
                      seq_num, NULL, vp->res);
 
157
 
 
158
  if (!vp->res->str[0])
 
159
    return;
 
160
 
 
161
  g_hash_table_insert(scope_set, key, vp->res->str);
 
162
  g_string_steal(vp->res);
 
163
}
 
164
 
 
165
/* runs over the LogMessage nv-pairs, and inserts them unless excluded */
 
166
static gboolean
 
167
vp_msg_nvpairs_foreach(NVHandle handle, gchar *name,
 
168
                       const gchar *value, gssize value_len,
 
169
                       gpointer user_data)
 
170
{
 
171
  ValuePairs *vp = ((gpointer *)user_data)[0];
 
172
  GHashTable *scope_set = ((gpointer *)user_data)[5];
 
173
  gint j;
 
174
 
 
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))))
 
179
    {
 
180
      for (j = 0; j < vp->exclude_size; j++)
 
181
        {
 
182
          if (g_pattern_match_string(vp->excludes[j], name))
 
183
            return FALSE;
 
184
        }
 
185
 
 
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));
 
188
    }
 
189
 
 
190
  return FALSE;
 
191
}
 
192
 
 
193
/* runs over a set of ValuePairSpec structs and merges them into the value-pair set */
 
194
static void
 
195
vp_merge_set(ValuePairs *vp, LogMessage *msg, gint32 seq_num, ValuePairSpec *set, GHashTable *dest)
 
196
{
 
197
  gint i;
 
198
 
 
199
  for (i = 0; set[i].name; i++)
 
200
    {
 
201
      gint j;
 
202
      gboolean exclude = FALSE;
 
203
 
 
204
      for (j = 0; j < vp->exclude_size; j++)
 
205
        {
 
206
          if (g_pattern_match_string(vp->excludes[j], set[i].name))
 
207
            exclude = TRUE;
 
208
        }
 
209
 
 
210
      if (exclude)
 
211
        continue;
 
212
 
 
213
      g_string_truncate(vp->res, 0);
 
214
      switch (set[i].type)
 
215
        {
 
216
        case VPT_MACRO:
 
217
          log_macro_expand(vp->res, set[i].id, FALSE, NULL, LTZ_LOCAL, seq_num, NULL, msg);
 
218
          break;
 
219
        case VPT_NVPAIR:
 
220
          {
 
221
            const gchar *nv;
 
222
            gssize len;
 
223
 
 
224
            nv = log_msg_get_value(msg, (NVHandle) set[i].id, &len);
 
225
            g_string_append_len(vp->res, nv, len);
 
226
            break;
 
227
          }
 
228
        default:
 
229
          g_assert_not_reached();
 
230
        }
 
231
 
 
232
      if (!vp->res->str[0])
 
233
        continue;
 
234
 
 
235
      g_hash_table_insert(dest, set[i].name, vp->res->str);
 
236
      g_string_steal(vp->res);
 
237
    }
 
238
}
 
239
 
 
240
void
 
241
value_pairs_foreach (ValuePairs *vp, VPForeachFunc func,
 
242
                     LogMessage *msg, gint32 seq_num, gpointer user_data)
 
243
{
 
244
  gpointer args[] = { vp, func, msg, GINT_TO_POINTER (seq_num), user_data, NULL };
 
245
  GHashTable *scope_set;
 
246
 
 
247
  scope_set = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
 
248
                                    (GDestroyNotify) g_free);
 
249
 
 
250
  args[5] = scope_set;
 
251
 
 
252
  /*
 
253
   * Build up the base set
 
254
   */
 
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);
 
258
 
 
259
  if (vp->scopes & (VPS_RFC3164 + VPS_RFC5424 + VPS_SELECTED_MACROS))
 
260
    vp_merge_set(vp, msg, seq_num, rfc3164, scope_set);
 
261
 
 
262
  if (vp->scopes & VPS_RFC5424)
 
263
    vp_merge_set(vp, msg, seq_num, rfc5424, scope_set);
 
264
 
 
265
  if (vp->scopes & VPS_SELECTED_MACROS)
 
266
    vp_merge_set(vp, msg, seq_num, selected_macros, scope_set);
 
267
 
 
268
  if (vp->scopes & VPS_ALL_MACROS)
 
269
    vp_merge_set(vp, msg, seq_num, all_macros, scope_set);
 
270
 
 
271
  /* Merge the explicit key-value pairs too */
 
272
  g_hash_table_foreach(vp->vpairs, (GHFunc) vp_pairs_foreach, args);
 
273
 
 
274
  /* Aaand we run it through the callback! */
 
275
  g_hash_table_foreach(scope_set, (GHFunc)func, user_data);
 
276
 
 
277
  g_hash_table_destroy(scope_set);
 
278
}
 
279
 
 
280
 
 
281
static void
 
282
value_pairs_init_set(ValuePairSpec *set)
 
283
{
 
284
  gint i;
 
285
 
 
286
  for (i = 0; set[i].name; i++)
 
287
    {
 
288
      guint id;
 
289
      gchar *name;
 
290
 
 
291
      name = set[i].alt_name ? set[i].alt_name : set[i].name;
 
292
 
 
293
      if ((id = log_macro_lookup(name, strlen(name))))
 
294
        {
 
295
          set[i].type = VPT_MACRO;
 
296
          set[i].id = id;
 
297
        }
 
298
      else
 
299
        {
 
300
          set[i].type = VPT_NVPAIR;
 
301
          set[i].id = log_msg_get_value_handle(name);
 
302
        }
 
303
    }
 
304
}
 
305
 
 
306
ValuePairs *
 
307
value_pairs_new(void)
 
308
{
 
309
  ValuePairs *vp;
 
310
  gint i = 0;
 
311
  GArray *a;
 
312
 
 
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);
 
317
 
 
318
  if (!value_pair_sets_initialized)
 
319
    {
 
320
 
 
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
 
325
       * else. */
 
326
 
 
327
      value_pairs_init_set(rfc3164);
 
328
      value_pairs_init_set(rfc5424);
 
329
      value_pairs_init_set(selected_macros);
 
330
 
 
331
      a = g_array_new(TRUE, TRUE, sizeof(ValuePairSpec));
 
332
      for (i = 0; macros[i].name; i++)
 
333
        {
 
334
          ValuePairSpec pair;
 
335
 
 
336
          pair.name = macros[i].name;
 
337
          pair.type = VPT_MACRO;
 
338
          pair.id = macros[i].id;
 
339
          g_array_append_val(a, pair);
 
340
        }
 
341
      all_macros = (ValuePairSpec *) g_array_free(a, FALSE);
 
342
 
 
343
      value_pair_sets_initialized = TRUE;
 
344
    }
 
345
 
 
346
  return vp;
 
347
}
 
348
 
 
349
void
 
350
value_pairs_free (ValuePairs *vp)
 
351
{
 
352
  gint i;
 
353
 
 
354
  g_hash_table_destroy(vp->vpairs);
 
355
 
 
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);
 
360
  g_free(vp);
 
361
}
 
362
 
 
363
/* parse a value-pair specification from a command-line like environment */
 
364
static gboolean
 
365
vp_cmdline_parse_scope(const gchar *option_name, const gchar *value,
 
366
                       gpointer data, GError **error)
 
367
{
 
368
  gpointer *args = (gpointer *) data;
 
369
  ValuePairs *vp = (ValuePairs *) args[1];
 
370
 
 
371
  if (!value_pairs_add_scope (vp, value))
 
372
    {
 
373
      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
 
374
                   "Unknon value-pairs scope, scope=%s", value);
 
375
      return FALSE;
 
376
    }
 
377
  return TRUE;
 
378
}
 
379
 
 
380
static gboolean
 
381
vp_cmdline_parse_exclude(const gchar *option_name, const gchar *value,
 
382
                         gpointer data, GError **error)
 
383
{
 
384
  gpointer *args = (gpointer *) data;
 
385
  ValuePairs *vp = (ValuePairs *) args[1];
 
386
 
 
387
  value_pairs_add_exclude_glob(vp, value);
 
388
  return TRUE;
 
389
}
 
390
 
 
391
static gboolean
 
392
vp_cmdline_parse_key(const gchar *option_name, const gchar *value,
 
393
                      gpointer data, GError **error)
 
394
{
 
395
  gpointer *args = (gpointer *) data;
 
396
  ValuePairs *vp = (ValuePairs *) args[1];
 
397
  GlobalConfig *cfg = (GlobalConfig *) args[0];
 
398
  gchar *k = g_strconcat ("$", value, NULL);
 
399
 
 
400
  value_pairs_add_pair(vp, cfg, value, k);
 
401
  g_free (k);
 
402
 
 
403
  return TRUE;
 
404
}
 
405
 
 
406
static gboolean
 
407
vp_cmdline_parse_pair (const gchar *option_name, const gchar *value,
 
408
                       gpointer data, GError **error)
 
409
{
 
410
  gpointer *args = (gpointer *) data;
 
411
  ValuePairs *vp = (ValuePairs *) args[1];
 
412
  GlobalConfig *cfg = (GlobalConfig *) args[0];
 
413
  gchar **kv;
 
414
 
 
415
  if (!g_strstr_len (value, strlen (value), "="))
 
416
    {
 
417
      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
 
418
                   "Error parsing value-pairs' key=value pair");
 
419
      return FALSE;
 
420
    }
 
421
 
 
422
  kv = g_strsplit(value, "=", 2);
 
423
  value_pairs_add_pair (vp, cfg, kv[0], kv[1]);
 
424
 
 
425
  g_free (kv[0]);
 
426
  g_free (kv[1]);
 
427
  g_free (kv);
 
428
 
 
429
  return TRUE;
 
430
}
 
431
 
 
432
ValuePairs *
 
433
value_pairs_new_from_cmdline (GlobalConfig *cfg,
 
434
                              gint cargc, gchar **cargv,
 
435
                              GError **error)
 
436
{
 
437
  ValuePairs *vp;
 
438
  GOptionContext *ctx;
 
439
  GOptionEntry vp_options[] = {
 
440
    { "scope", 's', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_scope,
 
441
      NULL, NULL },
 
442
    { "exclude", 'x', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_exclude,
 
443
      NULL, NULL },
 
444
    { "key", 'k', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_key,
 
445
      NULL, NULL },
 
446
    { "pair", 'p', 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair,
 
447
      NULL, NULL },
 
448
    { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_CALLBACK, vp_cmdline_parse_pair,
 
449
      NULL, NULL },
 
450
    { NULL }
 
451
  };
 
452
  gchar **argv;
 
453
  gint argc = cargc + 1;
 
454
  gint i;
 
455
  GOptionGroup *og;
 
456
  gpointer user_data_args[2];
 
457
 
 
458
  vp = value_pairs_new();
 
459
  user_data_args[0] = cfg;
 
460
  user_data_args[1] = vp;
 
461
 
 
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";
 
466
  argv[argc] = NULL;
 
467
 
 
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);
 
472
 
 
473
  if (!g_option_context_parse (ctx, &argc, &argv, error))
 
474
    {
 
475
      value_pairs_free (vp);
 
476
      g_option_context_free (ctx);
 
477
      g_free (argv);
 
478
      return NULL;
 
479
    }
 
480
  g_option_context_free (ctx);
 
481
 
 
482
  return vp;
 
483
}