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

« back to all changes in this revision

Viewing changes to src/pdbtool.c

  • Committer: Bazaar Package Importer
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2011-05-16 22:02:46 UTC
  • mfrom: (26.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110516220246-nknmeu831n49bx1z
* New upstream release, fixing infinite loop via PCRE and global. No CVE
  number yet, Vigil@nce id is 10648.
* Remove all patches, they were applied upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include "syslog-ng.h"
2
 
#include "messages.h"
3
 
#include "templates.h"
4
 
#include "misc.h"
5
 
#include "logpatterns.h"
6
 
#include "logparser.h"
7
 
#include "radix.h"
8
 
#include "tags.h"
9
 
#include "stats.h"
10
 
 
11
 
#include <stdio.h>
12
 
#include <string.h>
13
 
#include <stdlib.h>
14
 
 
15
 
#if HAVE_GETOPT_H
16
 
#include <getopt.h>
17
 
#endif
18
 
 
19
 
#include <locale.h>
20
 
 
21
 
#define BOOL(x) ((x) ? "TRUE" : "FALSE")
22
 
 
23
 
static gchar *full_colors[] =
24
 
{
25
 
  "\33[01;34m", /* blue */
26
 
  "\33[01;33m", /* yellow */
27
 
  "\33[01;32m", /* green */
28
 
  "\33[01;31m"  /* red */
29
 
};
30
 
 
31
 
static gchar *empty_colors[] =
32
 
{
33
 
  "", "", "", ""
34
 
};
35
 
 
36
 
#define COLOR_BLUE 0
37
 
#define COLOR_YELLOW 1
38
 
#define COLOR_GREEN 2
39
 
#define COLOR_RED 3
40
 
 
41
 
static gchar *no_color = "\33[01;0m";
42
 
static gchar **colors = empty_colors;
43
 
 
44
 
 
45
 
static gchar *patterndb_file = PATH_PATTERNDB_FILE;
46
 
static gboolean color_out = FALSE;
47
 
 
48
 
static gchar *merge_dir = NULL;
49
 
 
50
 
typedef struct _PdbToolMergeState
51
 
{
52
 
  GString *merged;
53
 
  gint version;
54
 
  gboolean in_rule;
55
 
} PdbToolMergeState;
56
 
 
57
 
void
58
 
pdbtool_merge_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names,
59
 
                                        const gchar **attribute_values, gpointer user_data, GError **error)
60
 
{
61
 
  PdbToolMergeState *state = (PdbToolMergeState *) user_data;
62
 
  gchar *buff;
63
 
  gint i;
64
 
 
65
 
  if (g_str_equal(element_name, "patterndb"))
66
 
    {
67
 
      for (i = 0; attribute_names[i]; i++)
68
 
        {
69
 
          if (g_str_equal(attribute_names[i], "version"))
70
 
            state->version = strtol(attribute_values[i], NULL, 10);
71
 
        }
72
 
      return;
73
 
    }
74
 
  else if (g_str_equal(element_name, "rule"))
75
 
    state->in_rule = TRUE;
76
 
 
77
 
  if (g_str_equal(element_name, "program"))
78
 
    g_string_append(state->merged, "<ruleset");
79
 
  else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "pattern"))
80
 
    g_string_append_printf(state->merged, "<patterns>\n<%s", element_name);
81
 
  else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "url"))
82
 
    g_string_append_printf(state->merged, "<urls>\n<%s", element_name);
83
 
  else
84
 
    g_string_append_printf(state->merged, "<%s", element_name);
85
 
 
86
 
  for (i = 0; attribute_names[i]; i++)
87
 
    {
88
 
      buff = g_markup_printf_escaped(" %s='%s'", attribute_names[i], attribute_values[i]);
89
 
      g_string_append_printf(state->merged, "%s", buff);
90
 
      g_free(buff);
91
 
    }
92
 
 
93
 
  g_string_append(state->merged, ">");
94
 
}
95
 
 
96
 
 
97
 
void
98
 
pdbtool_merge_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
99
 
{
100
 
  PdbToolMergeState *state = (PdbToolMergeState *) user_data;
101
 
  
102
 
  if (g_str_equal(element_name, "patterndb"))
103
 
    return;
104
 
  else if (g_str_equal(element_name, "rule"))
105
 
    state->in_rule = FALSE;
106
 
 
107
 
  if (g_str_equal(element_name, "program"))
108
 
    g_string_append(state->merged, "</ruleset>");
109
 
  else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "pattern"))
110
 
    g_string_append_printf(state->merged, "</%s>\n</patterns>", element_name);
111
 
  else if (state->version == 1 && state->in_rule && g_str_equal(element_name, "url"))
112
 
    g_string_append_printf(state->merged, "</%s>\n</urls>", element_name);
113
 
  else
114
 
    g_string_append_printf(state->merged, "</%s>", element_name);
115
 
}
116
 
 
117
 
void
118
 
pdbtool_merge_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
119
 
{
120
 
  PdbToolMergeState *state = (PdbToolMergeState *) user_data;
121
 
  gchar *buff = g_markup_printf_escaped("%s", text);
122
 
 
123
 
  g_string_append(state->merged, buff);
124
 
 
125
 
  g_free(buff);
126
 
}
127
 
 
128
 
GMarkupParser pdbtool_merge_parser =
129
 
{
130
 
  .start_element = pdbtool_merge_start_element,
131
 
  .end_element = pdbtool_merge_end_element,
132
 
  .text = pdbtool_merge_text,
133
 
  .passthrough = NULL,
134
 
  .error = NULL
135
 
};
136
 
 
137
 
static gboolean
138
 
pdbtool_merge_file(const gchar *filename, GString *merged)
139
 
{
140
 
  GMarkupParseContext *parse_ctx = NULL;
141
 
  gchar *full_name = g_build_filename(merge_dir, filename, NULL);
142
 
  PdbToolMergeState state;
143
 
  GError *error = NULL;
144
 
  gboolean success = TRUE;
145
 
  gchar *buff = NULL;
146
 
  gsize buff_len;
147
 
 
148
 
  if (!g_file_get_contents(full_name, &buff, &buff_len, &error))
149
 
    {
150
 
      fprintf(stderr, "Error reading pattern database file; filename='%s', error='%s'\n",
151
 
            filename, error ? error->message : "Unknown error");
152
 
      success = FALSE;
153
 
      goto error;
154
 
    }
155
 
 
156
 
  state.version = 0;
157
 
  state.merged = merged;
158
 
  state.in_rule = FALSE;
159
 
 
160
 
  parse_ctx = g_markup_parse_context_new(&pdbtool_merge_parser, 0, &state, NULL);
161
 
  if (!g_markup_parse_context_parse(parse_ctx, buff, buff_len, &error))
162
 
    {
163
 
      fprintf(stderr, "Error parsing pattern database file; filename='%s', error='%s'\n",
164
 
            filename, error ? error->message : "Unknown error");
165
 
      success = FALSE;
166
 
      goto error;
167
 
    }
168
 
 
169
 
  if (!g_markup_parse_context_end_parse(parse_ctx, &error))
170
 
    {
171
 
      fprintf(stderr, "Error parsing pattern database file; filename='%s', error='%s'\n",
172
 
            filename, error ? error->message : "Unknown error");
173
 
      success = FALSE;
174
 
      goto error;
175
 
    }
176
 
 
177
 
error:
178
 
  g_free(full_name);
179
 
 
180
 
  if (buff)
181
 
    g_free(buff);
182
 
 
183
 
  if (parse_ctx)
184
 
    g_markup_parse_context_free(parse_ctx);
185
 
 
186
 
  return success;
187
 
}
188
 
 
189
 
static gint
190
 
pdbtool_merge(int argc, char *argv[])
191
 
{
192
 
  GDir *pdb_dir;
193
 
  GDate date;
194
 
  const gchar *filename;
195
 
  GError *error = NULL;
196
 
  GString *merged = NULL;
197
 
  gchar *buff;
198
 
  gboolean ok = TRUE;
199
 
 
200
 
  if (!merge_dir)
201
 
    {
202
 
      fprintf(stderr, "No directory is specified to merge from\n");
203
 
      return 1;
204
 
    }
205
 
 
206
 
  if (!patterndb_file)
207
 
    {
208
 
      fprintf(stderr, "No patterndb file is specified to merge to\n");
209
 
      return 1;
210
 
    }
211
 
 
212
 
  if ((pdb_dir = g_dir_open(merge_dir, 0, &error)) == NULL)
213
 
    {
214
 
      fprintf(stderr, "Error opening patterndb directory; errror='%s'\n", error ? error->message : "Unknown error");
215
 
      return 1;
216
 
    }
217
 
 
218
 
  merged = g_string_sized_new(4096);
219
 
  g_date_clear(&date, 1);
220
 
  g_date_set_time_t(&date, time (NULL)); 
221
 
 
222
 
  buff = g_markup_printf_escaped("<?xml version='1.0' encoding='UTF-8'?>\n<patterndb version='3' pub_date='%04d-%02d-%02d'>",
223
 
                                    g_date_get_year(&date), g_date_get_month(&date), g_date_get_day(&date));
224
 
  g_string_append(merged, buff);
225
 
  g_free(buff);
226
 
 
227
 
  while ((filename = g_dir_read_name(pdb_dir)) != NULL && ok)
228
 
    ok = pdbtool_merge_file(filename, merged);
229
 
 
230
 
  g_dir_close(pdb_dir);
231
 
 
232
 
  g_string_append(merged, "</patterndb>\n");
233
 
 
234
 
  if (ok)
235
 
    if (!g_file_set_contents(patterndb_file, merged->str, merged->len, &error))
236
 
      {
237
 
        fprintf(stderr, "Error storing patterndb; filename='%s', errror='%s'\n", patterndb_file, error ? error->message : "Unknown error");
238
 
        ok = FALSE;
239
 
      }
240
 
 
241
 
  g_string_free(merged, TRUE);
242
 
 
243
 
  return ok ? 0 : 1;
244
 
}
245
 
 
246
 
static GOptionEntry merge_options[] =
247
 
{
248
 
  { "directory", 'D', 0, G_OPTION_ARG_STRING, &merge_dir,
249
 
    "Directory from merge pattern databases", "<directory>" },
250
 
  { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
251
 
};
252
 
 
253
 
static gchar *match_program = NULL;
254
 
static gchar *match_message = NULL;
255
 
static gboolean debug_pattern = FALSE;
256
 
static gboolean debug_pattern_parse = FALSE;
257
 
 
258
 
gboolean
259
 
pdbtool_match_values(NVHandle handle, const gchar *name, const gchar *value, gssize length, gpointer user_data)
260
 
{
261
 
  gint *ret = user_data;
262
 
 
263
 
  printf("%s=%.*s\n", name, (gint) length, value);
264
 
  if (g_str_equal(name, ".classifier.rule_id"))
265
 
    *ret = 0;
266
 
  return FALSE;
267
 
}
268
 
 
269
 
static gint
270
 
pdbtool_match(int argc, char *argv[])
271
 
{
272
 
  LogPatternDatabase patterndb;
273
 
  LogMessage *msg = log_msg_new_empty();
274
 
  GSList *dbg_list = NULL, *p;
275
 
  RDebugInfo *dbg_info;
276
 
  gint i = 0, pos = 0;
277
 
  gint ret = 1;
278
 
  const gchar *name;
279
 
  gssize name_len;
280
 
 
281
 
  if (!match_message)
282
 
    {
283
 
      fprintf(stderr, "No message is given\n");
284
 
      return ret;
285
 
    }
286
 
 
287
 
  memset(&patterndb, 0x0, sizeof(LogPatternDatabase));
288
 
 
289
 
  if (!log_pattern_database_load(&patterndb, patterndb_file))
290
 
    return ret;
291
 
 
292
 
  log_msg_set_value(msg, LM_V_MESSAGE, match_message, strlen(match_message));
293
 
  if (match_program && match_program[0])
294
 
    log_msg_set_value(msg, LM_V_PROGRAM, match_program, strlen(match_program));
295
 
 
296
 
  log_db_parser_process_lookup(&patterndb, msg, debug_pattern ? &dbg_list : NULL);
297
 
 
298
 
  if (debug_pattern && !debug_pattern_parse)
299
 
    {
300
 
      printf("Pattern matching part:\n");
301
 
      p = dbg_list;
302
 
      while (p)
303
 
        {
304
 
          dbg_info = p->data;
305
 
 
306
 
          pos += dbg_info->i;
307
 
 
308
 
          if (dbg_info->pnode)
309
 
            {
310
 
              name = nv_registry_get_handle_name(logmsg_registry, dbg_info->pnode->handle, &name_len);
311
 
 
312
 
              printf("%s@%s:%s=%.*s@%s",
313
 
                    colors[COLOR_YELLOW],
314
 
                    r_parser_type_name(dbg_info->pnode->type),
315
 
                    name_len ? name : "",
316
 
                    name_len ? dbg_info->match_len : 0,
317
 
                    name_len ? match_message + dbg_info->match_off : "",
318
 
                    no_color
319
 
                  );
320
 
            }
321
 
          else if (dbg_info->i == dbg_info->node->keylen)
322
 
            {
323
 
              printf("%s%s%s", colors[COLOR_GREEN], dbg_info->node->key, no_color);
324
 
            }
325
 
          else
326
 
            {
327
 
              printf("%s%.*s%s", colors[COLOR_RED], dbg_info->i, dbg_info->node->key, no_color);
328
 
            }
329
 
 
330
 
          p = p->next;
331
 
        }
332
 
      printf("%s%s%s", colors[COLOR_BLUE], match_message + pos, no_color);
333
 
 
334
 
      printf("\nMatching part:\n");
335
 
    }
336
 
 
337
 
  if (debug_pattern && debug_pattern_parse)
338
 
    printf("PDBTOOL_HEADER=i:len:key;keylen:match_off;match_len:parser_type:parser_name\n");
339
 
 
340
 
  pos = 0;
341
 
  while (dbg_list)
342
 
    {
343
 
      /* NOTE: if i is smaller than node->keylen than we did not match the full node
344
 
       * so matching failed on this node, we need to highlight it somehow
345
 
       */
346
 
      dbg_info = dbg_list->data;
347
 
      if (debug_pattern_parse)
348
 
        {
349
 
          if (dbg_info->pnode)
350
 
            name = nv_registry_get_handle_name(logmsg_registry, dbg_info->pnode->handle, &name_len);
351
 
 
352
 
          printf("PDBTOOL_DEBUG=%d:%d:%d:%d:%d:%s:%s\n",
353
 
                i++, dbg_info->i, dbg_info->node->keylen, dbg_info->match_off, dbg_info->match_len,
354
 
                dbg_info->pnode ? r_parser_type_name(dbg_info->pnode->type) : "",
355
 
                dbg_info->pnode && name_len ? name : ""
356
 
                );
357
 
        }
358
 
      else
359
 
        {
360
 
          if (dbg_info->i == dbg_info->node->keylen || dbg_info->pnode)
361
 
            printf("%s%.*s%s", dbg_info->pnode ? colors[COLOR_YELLOW] : colors[COLOR_GREEN], dbg_info->i, match_message + pos, no_color);
362
 
          else
363
 
            printf("%s%.*s%s", colors[COLOR_RED], dbg_info->i, match_message + pos, no_color);
364
 
          pos += dbg_info->i;
365
 
        }
366
 
 
367
 
      g_free(dbg_info);
368
 
      dbg_list = g_slist_delete_link(dbg_list, dbg_list);
369
 
    }
370
 
 
371
 
  if (debug_pattern && !debug_pattern_parse)
372
 
    printf("\nValues:\n");
373
 
 
374
 
  nv_table_foreach(msg->payload, logmsg_registry, pdbtool_match_values, &ret);
375
 
 
376
 
  log_pattern_database_free(&patterndb);
377
 
  log_msg_unref(msg);
378
 
  return ret;
379
 
}
380
 
 
381
 
static GOptionEntry match_options[] =
382
 
{
383
 
  { "program", 'P', 0, G_OPTION_ARG_STRING, &match_program,
384
 
    "Program name to match as $PROGRAM", "<program>" },
385
 
  { "message", 'M', 0, G_OPTION_ARG_STRING, &match_message,
386
 
    "Message to match as $MSG", "<message>" },
387
 
  { "debug-pattern", 'D', 0, G_OPTION_ARG_NONE, &debug_pattern,
388
 
    "Print debuging information on pattern matching", NULL },
389
 
  { "csv-out", 'C', 0, G_OPTION_ARG_NONE, &debug_pattern_parse,
390
 
    "Output debuging information in parseable format", NULL },
391
 
  { "color-out", 'c', 0, G_OPTION_ARG_NONE, &color_out,
392
 
    "Color terminal output", NULL },
393
 
  { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
394
 
};
395
 
 
396
 
static gboolean dump_program_tree = FALSE;
397
 
 
398
 
void
399
 
pdbtool_walk_tree(RNode *root, gint level, gboolean program)
400
 
{
401
 
  gint i;
402
 
 
403
 
  for (i = 0; i < level; i++)
404
 
    printf(" ");
405
 
 
406
 
  if (root->parser)
407
 
    printf("@%s:%s@ ", r_parser_type_name(root->parser->type), log_msg_get_value_name(root->parser->handle, NULL));
408
 
  printf("'%s' ", root->key ? root->key : "");
409
 
 
410
 
  if (root->value)
411
 
    {
412
 
      if (!program)
413
 
        printf("rule_id='%s'", ((LogDBResult*)root->value)->rule_id);
414
 
      else
415
 
        printf("RULES");
416
 
    }
417
 
 
418
 
  printf("\n");
419
 
 
420
 
  for (i = 0; i < root->num_children; i++)
421
 
    pdbtool_walk_tree(root->children[i], level + 1, program);
422
 
 
423
 
  for (i = 0; i < root->num_pchildren; i++)
424
 
    pdbtool_walk_tree(root->pchildren[i], level + 1, program);
425
 
}
426
 
 
427
 
static gint
428
 
pdbtool_dump(int argc, char *argv[])
429
 
{
430
 
 LogPatternDatabase patterndb;
431
 
 
432
 
 memset(&patterndb, 0x0, sizeof(LogPatternDatabase));
433
 
 
434
 
 if (!log_pattern_database_load(&patterndb, patterndb_file))
435
 
   return 1;
436
 
 
437
 
 if (dump_program_tree)
438
 
   pdbtool_walk_tree(patterndb.programs, 0, TRUE);
439
 
 else if (match_program)
440
 
   {
441
 
     RNode *ruleset = r_find_node(patterndb.programs, g_strdup(match_program), g_strdup(match_program), strlen(match_program), NULL);
442
 
     if (ruleset && ruleset->value)
443
 
       pdbtool_walk_tree(((LogDBProgram *)ruleset->value)->rules, 0, FALSE);
444
 
   }
445
 
 
446
 
 return 0;
447
 
}
448
 
 
449
 
static GOptionEntry dump_options[] =
450
 
{
451
 
  { "program", 'P', 0, G_OPTION_ARG_STRING, &match_program,
452
 
    "Program name ($PROGRAM) to dump", "<program>" },
453
 
  { "program-tree", 'T', 0, G_OPTION_ARG_NONE, &dump_program_tree,
454
 
    "Dump the program ($PROGRAM) tree", NULL },
455
 
  { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
456
 
};
457
 
 
458
 
 
459
 
 
460
 
const gchar *
461
 
pdbtool_mode(int *argc, char **argv[])
462
 
{
463
 
  gint i;
464
 
  const gchar *mode;
465
 
 
466
 
  for (i = 1; i < (*argc); i++)
467
 
    {
468
 
      if ((*argv)[i][0] != '-')
469
 
        {
470
 
          mode = (*argv)[i];
471
 
          memmove(&(*argv)[i], &(*argv)[i+1], ((*argc) - i) * sizeof(gchar *));
472
 
          (*argc)--;
473
 
          return mode;
474
 
        }
475
 
    }
476
 
  return NULL;
477
 
}
478
 
 
479
 
static GOptionEntry pdbtool_options[] =
480
 
{
481
 
  { "pdb",       'p', 0, G_OPTION_ARG_STRING, &patterndb_file,
482
 
    "Name of the patterndb file", "<patterndb_file>" },
483
 
  { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL }
484
 
};
485
 
 
486
 
static struct
487
 
{
488
 
  const gchar *mode;
489
 
  const GOptionEntry *options;
490
 
  const gchar *description;
491
 
  gint (*main)(gint argc, gchar *argv[]);
492
 
} modes[] =
493
 
{
494
 
  { "match", match_options, "Match a message against the pattern database", pdbtool_match },
495
 
  { "dump", dump_options, "Dump pattern datebase tree", pdbtool_dump },
496
 
  { "merge", merge_options, "Merge pattern databases", pdbtool_merge },
497
 
  { NULL, NULL },
498
 
};
499
 
 
500
 
void
501
 
usage(void)
502
 
{
503
 
  gint mode;
504
 
 
505
 
  fprintf(stderr, "Syntax: pdbtool <command> [options]\nPossible commands are:\n");
506
 
  for (mode = 0; modes[mode].mode; mode++)
507
 
    {
508
 
      fprintf(stderr, "    %-12s %s\n", modes[mode].mode, modes[mode].description);
509
 
    }
510
 
  exit(1);
511
 
}
512
 
 
513
 
int
514
 
main(int argc, char *argv[])
515
 
{
516
 
  const gchar *mode_string;
517
 
  GOptionContext *ctx;
518
 
  gint mode, ret = 0;
519
 
  GError *error = NULL;
520
 
 
521
 
  stats_init();
522
 
  log_tags_init();
523
 
  log_msg_registry_init();
524
 
  log_db_parser_global_init();
525
 
  mode_string = pdbtool_mode(&argc, &argv);
526
 
  if (!mode_string)
527
 
    {
528
 
      usage();
529
 
    }
530
 
 
531
 
  ctx = NULL;
532
 
  for (mode = 0; modes[mode].mode; mode++)
533
 
    {
534
 
      if (strcmp(modes[mode].mode, mode_string) == 0)
535
 
        {
536
 
          ctx = g_option_context_new(mode_string);
537
 
          g_option_context_set_summary(ctx, modes[mode].description);
538
 
          g_option_context_add_main_entries(ctx, modes[mode].options, NULL);
539
 
          g_option_context_add_main_entries(ctx, pdbtool_options, NULL);
540
 
          msg_add_option_group(ctx);
541
 
          break;
542
 
        }
543
 
    }
544
 
  if (!ctx)
545
 
    {
546
 
      fprintf(stderr, "Unknown command\n");
547
 
      usage();
548
 
    }
549
 
 
550
 
  setlocale(LC_ALL, "");
551
 
  if (!g_option_context_parse(ctx, &argc, &argv, &error))
552
 
    {
553
 
      fprintf(stderr, "Error parsing command line arguments: %s\n", error ? error->message : "Invalid arguments");
554
 
      g_clear_error(&error);
555
 
      g_option_context_free(ctx);
556
 
      return 1;
557
 
    }
558
 
  g_option_context_free(ctx);
559
 
 
560
 
  msg_init(TRUE);
561
 
 
562
 
  if (color_out)
563
 
    colors = full_colors;
564
 
 
565
 
  ret = modes[mode].main(argc, argv);
566
 
  stats_destroy();
567
 
  log_tags_deinit();
568
 
 
569
 
  msg_deinit();
570
 
  return ret;
571
 
}