~ubuntu-branches/ubuntu/oneiric/gnupg2/oneiric-updates

« back to all changes in this revision

Viewing changes to common/audit.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* audit.c - GnuPG's audit subsystem
 
2
 *      Copyright (C) 2007 Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of GnuPG.
 
5
 *
 
6
 * GnuPG is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 3 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * GnuPG is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <config.h>
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <stdarg.h>
 
24
#include <assert.h>
 
25
 
 
26
#include "util.h"
 
27
#include "i18n.h"
 
28
#include "audit.h"
 
29
#include "audit-events.h"
 
30
 
 
31
/* A list to maintain a list of helptags.  */
 
32
struct helptag_s
 
33
{
 
34
  struct helptag_s *next;
 
35
  const char *name;
 
36
};
 
37
typedef struct helptag_s *helptag_t;
 
38
 
 
39
 
 
40
/* One log entry.  */
 
41
struct log_item_s
 
42
{
 
43
  audit_event_t event; /* The event.  */
 
44
  gpg_error_t err;     /* The logged error code.  */
 
45
  int intvalue;        /* A logged interger value.  */
 
46
  char *string;        /* A malloced string or NULL.  */
 
47
  ksba_cert_t cert;    /* A certifciate or NULL. */
 
48
  int have_err:1;
 
49
  int have_intvalue:1;
 
50
};
 
51
typedef struct log_item_s *log_item_t;
 
52
 
 
53
 
 
54
 
 
55
/* The main audit object.  */
 
56
struct audit_ctx_s
 
57
{
 
58
  const char *failure;  /* If set a description of the internal failure.  */
 
59
  audit_type_t type;
 
60
  
 
61
  log_item_t log;       /* The table with the log entries.  */
 
62
  size_t logsize;       /* The allocated size for LOG.  */
 
63
  size_t logused;       /* The used size of LOG.  */
 
64
 
 
65
  estream_t outstream;  /* The current output stream.  */
 
66
  int use_html;         /* The output shall be HTML formatted.  */
 
67
  int indentlevel;      /* Current level of indentation.  */
 
68
  helptag_t helptags;   /* List of help keys.  */
 
69
};
 
70
 
 
71
 
 
72
 
 
73
 
 
74
static void writeout_para (audit_ctx_t ctx, 
 
75
                           const char *format, ...) JNLIB_GCC_A_PRINTF(2,3);
 
76
static void writeout_li (audit_ctx_t ctx, const char *oktext,
 
77
                         const char *format, ...) JNLIB_GCC_A_PRINTF(3,4);
 
78
static void writeout_rem (audit_ctx_t ctx, 
 
79
                          const char *format, ...) JNLIB_GCC_A_PRINTF(2,3);
 
80
 
 
81
 
 
82
/* Add NAME to the list of help tags.  NAME needs to be a const string
 
83
   an this function merly stores this pointer.  */
 
84
static void 
 
85
add_helptag (audit_ctx_t ctx, const char *name)
 
86
{
 
87
  helptag_t item;
 
88
 
 
89
  for (item=ctx->helptags; item; item = item->next)
 
90
    if (!strcmp (item->name, name))
 
91
      return;  /* Already in the list.  */
 
92
  item = xtrycalloc (1, sizeof *item);
 
93
  if (!item)
 
94
    return;  /* Don't care about memory problems.  */
 
95
  item->name = name;
 
96
  item->next = ctx->helptags;
 
97
  ctx->helptags = item;
 
98
}
 
99
 
 
100
 
 
101
/* Remove all help tags from the context.  */
 
102
static void
 
103
clear_helptags (audit_ctx_t ctx)
 
104
{
 
105
  while (ctx->helptags)
 
106
    {
 
107
      helptag_t tmp = ctx->helptags->next;
 
108
      xfree (ctx->helptags);
 
109
      ctx->helptags = tmp;
 
110
    }
 
111
}
 
112
 
 
113
 
 
114
 
 
115
static const char *
 
116
event2str (audit_event_t event)
 
117
{
 
118
  int idx = eventstr_msgidxof (event);
 
119
  if (idx == -1)
 
120
    return "Unknown event";
 
121
  else
 
122
    return eventstr_msgstr + eventstr_msgidx[idx];
 
123
}
 
124
 
 
125
 
 
126
 
 
127
/* Create a new audit context.  In case of an error NULL is returned
 
128
   and errno set appropriately. */ 
 
129
audit_ctx_t
 
130
audit_new (void)
 
131
{
 
132
  audit_ctx_t ctx;
 
133
 
 
134
  ctx = xtrycalloc (1, sizeof *ctx);
 
135
 
 
136
  return ctx;
 
137
}
 
138
 
 
139
 
 
140
/* Release an audit context.  Passing NULL for CTX is allowed and does
 
141
   nothing.  */
 
142
void
 
143
audit_release (audit_ctx_t ctx)
 
144
{
 
145
  int idx;
 
146
  if (!ctx)
 
147
    return;
 
148
  if (ctx->log)
 
149
    {
 
150
      for (idx=0; idx < ctx->logused; idx++)
 
151
        {
 
152
          if (ctx->log[idx].string)
 
153
            xfree (ctx->log[idx].string);
 
154
          if (ctx->log[idx].cert)
 
155
            ksba_cert_release (ctx->log[idx].cert);
 
156
        }
 
157
      xfree (ctx->log);
 
158
    }
 
159
  clear_helptags (ctx);
 
160
  xfree (ctx);
 
161
}
 
162
 
 
163
 
 
164
/* Set the type for the audit operation.  If CTX is NULL, this is a
 
165
   dummy fucntion.  */
 
166
void
 
167
audit_set_type (audit_ctx_t ctx, audit_type_t type)
 
168
{
 
169
  if (!ctx || ctx->failure)
 
170
    return;  /* Audit not enabled or an internal error has occurred. */
 
171
 
 
172
  if (ctx->type && ctx->type != type)
 
173
    {
 
174
      ctx->failure = "conflict in type initialization";
 
175
      return;
 
176
    }
 
177
  ctx->type = type;
 
178
}
 
179
 
 
180
 
 
181
/* Create a new log item and put it into the table.  Return that log
 
182
   item on success; return NULL on memory failure and mark that in
 
183
   CTX. */
 
184
static log_item_t
 
185
create_log_item (audit_ctx_t ctx)
 
186
{
 
187
  log_item_t item, table;
 
188
  size_t size;
 
189
 
 
190
  if (!ctx->log)
 
191
    {
 
192
      size = 10;
 
193
      table = xtrymalloc (size * sizeof *table);
 
194
      if (!table)
 
195
        {
 
196
          ctx->failure = "Out of memory in create_log_item";
 
197
          return NULL;
 
198
        }
 
199
      ctx->log = table;
 
200
      ctx->logsize = size;
 
201
      item = ctx->log + 0;
 
202
      ctx->logused = 1;
 
203
    }
 
204
  else if (ctx->logused >= ctx->logsize)
 
205
    {
 
206
      size = ctx->logsize + 10;
 
207
      table = xtryrealloc (ctx->log, size * sizeof *table);
 
208
      if (!table)
 
209
        {
 
210
          ctx->failure = "Out of memory while reallocating in create_log_item";
 
211
          return NULL;
 
212
        }
 
213
      ctx->log = table;
 
214
      ctx->logsize = size;
 
215
      item = ctx->log + ctx->logused++;
 
216
    }
 
217
  else
 
218
    item = ctx->log + ctx->logused++;
 
219
 
 
220
  item->event = AUDIT_NULL_EVENT;
 
221
  item->err = 0;
 
222
  item->have_err = 0;
 
223
  item->intvalue = 0;
 
224
  item->have_intvalue = 0;
 
225
  item->string = NULL;
 
226
  item->cert = NULL;
 
227
 
 
228
  return item;
 
229
 
 
230
}
 
231
 
 
232
/* Add a new event to the audit log.  If CTX is NULL, this function
 
233
   does nothing.  */
 
234
void
 
235
audit_log (audit_ctx_t ctx, audit_event_t event)
 
236
{
 
237
  log_item_t item;
 
238
 
 
239
  if (!ctx || ctx->failure)
 
240
    return;  /* Audit not enabled or an internal error has occurred. */
 
241
  if (!event)
 
242
    {
 
243
      ctx->failure = "Invalid event passed to audit_log";
 
244
      return;
 
245
    }
 
246
  if (!(item = create_log_item (ctx)))
 
247
    return;
 
248
  item->event = event;
 
249
}
 
250
 
 
251
/* Add a new event to the audit log.  If CTX is NULL, this function
 
252
   does nothing.  This version also adds the result of the oepration
 
253
   to the log.. */
 
254
void
 
255
audit_log_ok (audit_ctx_t ctx, audit_event_t event, gpg_error_t err)
 
256
{
 
257
  log_item_t item;
 
258
 
 
259
  if (!ctx || ctx->failure)
 
260
    return;  /* Audit not enabled or an internal error has occurred. */
 
261
  if (!event)
 
262
    {
 
263
      ctx->failure = "Invalid event passed to audit_log_ok";
 
264
      return;
 
265
    }
 
266
  if (!(item = create_log_item (ctx)))
 
267
    return;
 
268
  item->event = event;
 
269
  item->err = err;
 
270
  item->have_err = 1;
 
271
}
 
272
 
 
273
 
 
274
/* Add a new event to the audit log.  If CTX is NULL, this function
 
275
   does nothing.  This version also add the integer VALUE to the log.  */
 
276
void
 
277
audit_log_i (audit_ctx_t ctx, audit_event_t event, int value)
 
278
{
 
279
  log_item_t item;
 
280
 
 
281
  if (!ctx || ctx->failure)
 
282
    return;  /* Audit not enabled or an internal error has occurred. */
 
283
  if (!event)
 
284
    {
 
285
      ctx->failure = "Invalid event passed to audit_log_i";
 
286
      return;
 
287
    }
 
288
  if (!(item = create_log_item (ctx)))
 
289
    return;
 
290
  item->event = event;
 
291
  item->intvalue = value;
 
292
  item->have_intvalue = 1;
 
293
}
 
294
 
 
295
 
 
296
/* Add a new event to the audit log.  If CTX is NULL, this function
 
297
   does nothing.  This version also add the integer VALUE to the log.  */
 
298
void
 
299
audit_log_s (audit_ctx_t ctx, audit_event_t event, const char *value)
 
300
{
 
301
  log_item_t item;
 
302
  char *tmp;
 
303
 
 
304
  if (!ctx || ctx->failure)
 
305
    return;  /* Audit not enabled or an internal error has occurred. */
 
306
  if (!event)
 
307
    {
 
308
      ctx->failure = "Invalid event passed to audit_log_s";
 
309
      return;
 
310
    }
 
311
  tmp = xtrystrdup (value? value : "");
 
312
  if (!tmp)
 
313
    {
 
314
      ctx->failure = "Out of memory in audit_event";
 
315
      return;
 
316
    }
 
317
  if (!(item = create_log_item (ctx)))
 
318
    {
 
319
      xfree (tmp);
 
320
      return;
 
321
    }
 
322
  item->event = event;
 
323
  item->string = tmp;
 
324
}
 
325
 
 
326
/* Add a new event to the audit log.  If CTX is NULL, this function
 
327
   does nothing.  This version also adds the certificate CERT and the
 
328
   result of an operation to the log.  */
 
329
void
 
330
audit_log_cert (audit_ctx_t ctx, audit_event_t event, 
 
331
                ksba_cert_t cert, gpg_error_t err)
 
332
{
 
333
  log_item_t item;
 
334
 
 
335
  if (!ctx || ctx->failure)
 
336
    return;  /* Audit not enabled or an internal error has occurred. */
 
337
  if (!event)
 
338
    {
 
339
      ctx->failure = "Invalid event passed to audit_log_cert";
 
340
      return;
 
341
    }
 
342
  if (!(item = create_log_item (ctx)))
 
343
    return;
 
344
  item->event = event;
 
345
  item->err = err;
 
346
  item->have_err = 1;
 
347
  if (cert)
 
348
    {
 
349
      ksba_cert_ref (cert); 
 
350
      item->cert = cert;
 
351
    }
 
352
}
 
353
 
 
354
 
 
355
/* Write TEXT to the outstream.  */
 
356
static void 
 
357
writeout (audit_ctx_t ctx, const char *text)
 
358
{
 
359
  if (ctx->use_html)
 
360
    {
 
361
      for (; *text; text++)
 
362
        {
 
363
          if (*text == '<')
 
364
            es_fputs ("&lt;", ctx->outstream);
 
365
          else if (*text == '&')
 
366
            es_fputs ("&amp;", ctx->outstream);
 
367
          else
 
368
            es_putc (*text, ctx->outstream);
 
369
        }
 
370
    }
 
371
  else
 
372
    es_fputs (text, ctx->outstream);
 
373
}
 
374
 
 
375
 
 
376
/* Write TEXT to the outstream using a variable argument list.  */
 
377
static void 
 
378
writeout_v (audit_ctx_t ctx, const char *format, va_list arg_ptr)
 
379
{
 
380
  char *buf;
 
381
 
 
382
  estream_vasprintf (&buf, format, arg_ptr);
 
383
  if (buf)
 
384
    {
 
385
      writeout (ctx, buf);
 
386
      xfree (buf);
 
387
    }
 
388
  else
 
389
    writeout (ctx, "[!!Out of core!!]");
 
390
}
 
391
 
 
392
 
 
393
/* Write TEXT as a paragraph.  */
 
394
static void
 
395
writeout_para (audit_ctx_t ctx, const char *format, ...)
 
396
{
 
397
  va_list arg_ptr;
 
398
 
 
399
  if (ctx->use_html)
 
400
    es_fputs ("<p>", ctx->outstream);
 
401
  va_start (arg_ptr, format) ;
 
402
  writeout_v (ctx, format, arg_ptr);
 
403
  va_end (arg_ptr);
 
404
  if (ctx->use_html)
 
405
    es_fputs ("</p>\n", ctx->outstream);
 
406
  else
 
407
    es_fputc ('\n', ctx->outstream);
 
408
}
 
409
 
 
410
 
 
411
static void
 
412
enter_li (audit_ctx_t ctx)
 
413
{
 
414
  if (ctx->use_html)
 
415
    {
 
416
      if (!ctx->indentlevel)
 
417
        {
 
418
          es_fputs ("<table border=\"0\">\n"
 
419
                    "  <colgroup>\n"
 
420
                    "    <col width=\"80%\" />\n"
 
421
                    "    <col width=\"20%\" />\n"
 
422
                    "   </colgroup>\n",
 
423
                    ctx->outstream);
 
424
        }
 
425
    }
 
426
  ctx->indentlevel++;
 
427
}
 
428
 
 
429
 
 
430
static void
 
431
leave_li (audit_ctx_t ctx)
 
432
{
 
433
  ctx->indentlevel--;
 
434
  if (ctx->use_html)
 
435
    {
 
436
      if (!ctx->indentlevel)
 
437
        es_fputs ("</table>\n", ctx->outstream);
 
438
    }
 
439
}
 
440
 
 
441
  
 
442
/* Write TEXT as a list element.  If OKTEXT is not NULL, append it to
 
443
   the last line. */
 
444
static void
 
445
writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...)
 
446
{
 
447
  va_list arg_ptr;
 
448
  const char *color = NULL;
 
449
 
 
450
  if (ctx->use_html && format && oktext)
 
451
    {
 
452
      if (!strcmp (oktext, "Yes"))
 
453
        color = "green";
 
454
      else if (!strcmp (oktext, "No"))
 
455
        color = "red";
 
456
    }
 
457
 
 
458
  if (ctx->use_html)
 
459
    {
 
460
      int i;
 
461
 
 
462
      es_fputs ("  <tr><td><table><tr><td>", ctx->outstream);
 
463
      if (color)
 
464
        es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
 
465
      else
 
466
        es_fputs ("*", ctx->outstream);
 
467
      for (i=1; i < ctx->indentlevel; i++)
 
468
        es_fputs ("&nbsp;&nbsp;", ctx->outstream);
 
469
      es_fputs ("</td><td>", ctx->outstream);
 
470
    }
 
471
  else
 
472
    es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
 
473
  if (format)
 
474
    {
 
475
      va_start (arg_ptr, format) ;
 
476
      writeout_v (ctx, format, arg_ptr);
 
477
      va_end (arg_ptr);
 
478
    }
 
479
  if (ctx->use_html)
 
480
    es_fputs ("</td></tr></table>", ctx->outstream);
 
481
  if (format && oktext)
 
482
    {
 
483
      if (ctx->use_html)
 
484
        {
 
485
          es_fputs ("</td><td>", ctx->outstream);
 
486
          if (color)
 
487
            es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
 
488
        }
 
489
      else  
 
490
        writeout (ctx, ":         ");
 
491
      writeout (ctx, oktext);
 
492
      if (color)
 
493
        es_fputs ("</font>", ctx->outstream);
 
494
    }
 
495
  
 
496
  if (ctx->use_html)
 
497
    es_fputs ("</td></tr>\n", ctx->outstream);
 
498
  else
 
499
    es_fputc ('\n', ctx->outstream);
 
500
}
 
501
 
 
502
 
 
503
/* Write a remark line.  */
 
504
static void
 
505
writeout_rem (audit_ctx_t ctx, const char *format, ...)
 
506
{
 
507
  va_list arg_ptr;
 
508
 
 
509
  if (ctx->use_html)
 
510
    {
 
511
      int i;
 
512
 
 
513
      es_fputs ("  <tr><td><table><tr><td>*", ctx->outstream);
 
514
      for (i=1; i < ctx->indentlevel; i++)
 
515
        es_fputs ("&nbsp;&nbsp;", ctx->outstream);
 
516
      es_fputs ("&nbsp;&nbsp;&nbsp;</td><td> (", ctx->outstream);
 
517
 
 
518
    }
 
519
  else
 
520
    es_fprintf (ctx->outstream, "* %*s  (", (ctx->indentlevel-1)*2, "");
 
521
  if (format)
 
522
    {
 
523
      va_start (arg_ptr, format) ;
 
524
      writeout_v (ctx, format, arg_ptr);
 
525
      va_end (arg_ptr);
 
526
    }
 
527
  if (ctx->use_html)
 
528
    es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
 
529
  else
 
530
    es_fputs (")\n", ctx->outstream);
 
531
}
 
532
 
 
533
 
 
534
/* Return the first log item for EVENT.  If STOPEVENT is not 0 never
 
535
   look behind that event in the log. If STARTITEM is not NULL start
 
536
   search _after_that item.  */
 
537
static log_item_t
 
538
find_next_log_item (audit_ctx_t ctx, log_item_t startitem, 
 
539
                    audit_event_t event, audit_event_t stopevent)
 
540
{
 
541
  int idx;
 
542
 
 
543
  for (idx=0; idx < ctx->logused; idx++)
 
544
    {
 
545
      if (startitem)
 
546
        {
 
547
          if (ctx->log + idx == startitem)
 
548
            startitem = NULL;
 
549
        }
 
550
      else if (stopevent && ctx->log[idx].event == stopevent)
 
551
        break;
 
552
      else if (ctx->log[idx].event == event)
 
553
        return ctx->log + idx;
 
554
    }
 
555
  return NULL;
 
556
}
 
557
 
 
558
 
 
559
static log_item_t
 
560
find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
 
561
{
 
562
  return find_next_log_item (ctx, NULL, event, stopevent);
 
563
}
 
564
 
 
565
 
 
566
/* Helper to a format a serial number.  */
 
567
static char *
 
568
format_serial (ksba_const_sexp_t sn)
 
569
{
 
570
  const char *p = (const char *)sn;
 
571
  unsigned long n;
 
572
  char *endp;
 
573
 
 
574
  if (!p)
 
575
    return NULL;
 
576
  if (*p != '(')
 
577
    BUG (); /* Not a valid S-expression. */
 
578
  n = strtoul (p+1, &endp, 10);
 
579
  p = endp;
 
580
  if (*p != ':')
 
581
    BUG (); /* Not a valid S-expression. */
 
582
  return bin2hex (p+1, n, NULL);
 
583
}
 
584
 
 
585
 
 
586
/* Return a malloced string with the serial number and the issuer DN
 
587
   of the certificate.  */
 
588
static char *
 
589
get_cert_name (ksba_cert_t cert)
 
590
{
 
591
  char *result;
 
592
  ksba_sexp_t sn;
 
593
  char *issuer, *p;
 
594
 
 
595
  if (!cert)
 
596
    return xtrystrdup ("[no certificate]");
 
597
 
 
598
  issuer = ksba_cert_get_issuer (cert, 0);
 
599
  sn = ksba_cert_get_serial (cert);
 
600
  if (issuer && sn)
 
601
    {
 
602
      p = format_serial (sn);
 
603
      if (!p)
 
604
        result = xtrystrdup ("[invalid S/N]");
 
605
      else
 
606
        {
 
607
          result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
 
608
          if (result)
 
609
            {
 
610
              *result = '#';
 
611
              strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
 
612
            }
 
613
          xfree (p);
 
614
        }
 
615
    }
 
616
  else
 
617
    result = xtrystrdup ("[missing S/N or issuer]");
 
618
  ksba_free (sn);
 
619
  xfree (issuer);
 
620
  return result;
 
621
}
 
622
 
 
623
/* Return a malloced string with the serial number and the issuer DN
 
624
   of the certificate.  */
 
625
static char *
 
626
get_cert_subject (ksba_cert_t cert, int idx)
 
627
{
 
628
  char *result;
 
629
  char *subject;
 
630
 
 
631
  if (!cert)
 
632
    return xtrystrdup ("[no certificate]");
 
633
 
 
634
  subject = ksba_cert_get_subject (cert, idx);
 
635
  if (subject)
 
636
    {
 
637
      result = xtrymalloc (strlen (subject) + 1 + 1);
 
638
      if (result)
 
639
        {
 
640
          *result = '/';
 
641
          strcpy (result+1, subject);
 
642
        }
 
643
    }
 
644
  else
 
645
    result = NULL;
 
646
  xfree (subject);
 
647
  return result;
 
648
}
 
649
 
 
650
 
 
651
/* List the given certificiate.  If CERT is NULL, this is a NOP.  */
 
652
static void
 
653
list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj)
 
654
{
 
655
  char *name;
 
656
  int idx;
 
657
 
 
658
  name = get_cert_name (cert);
 
659
  writeout_rem (ctx, "%s", name);
 
660
  xfree (name);
 
661
  if (with_subj)
 
662
    {
 
663
      enter_li (ctx);
 
664
      for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
 
665
        {
 
666
          writeout_rem (ctx, "%s", name);
 
667
          xfree (name);
 
668
        }
 
669
      leave_li (ctx);
 
670
    }
 
671
}
 
672
 
 
673
 
 
674
/* List the chain of certificates from STARTITEM up to STOPEVENT.  The
 
675
   certifcates are written out as comments.  */
 
676
static void
 
677
list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
 
678
{
 
679
  log_item_t item;
 
680
 
 
681
  startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
 
682
  writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available"));
 
683
  if (!startitem)
 
684
    return; 
 
685
 
 
686
  item = find_next_log_item (ctx, startitem, 
 
687
                             AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
 
688
  if (!item)
 
689
    writeout_rem (ctx, "%s", _("root certificate missing"));
 
690
  else
 
691
    {
 
692
      list_cert (ctx, item->cert, 0);
 
693
    }
 
694
  item = startitem;
 
695
  while ( ((item = find_next_log_item (ctx, item, 
 
696
                                       AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
 
697
    {
 
698
      list_cert (ctx, item->cert, 1);
 
699
    }
 
700
}
 
701
 
 
702
 
 
703
 
 
704
/* Process an encrypt operation's log.  */
 
705
static void
 
706
proc_type_encrypt (audit_ctx_t ctx)
 
707
{
 
708
  log_item_t loopitem, item;
 
709
  int recp_no, idx;
 
710
  char numbuf[35];
 
711
  int algo;
 
712
  char *name;
 
713
 
 
714
  item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
 
715
  writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
 
716
 
 
717
  enter_li (ctx);
 
718
 
 
719
  item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
 
720
  writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
 
721
 
 
722
  item = find_log_item (ctx, AUDIT_SESSION_KEY, 0);
 
723
  writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created"));
 
724
  if (item)
 
725
    {
 
726
      algo = gcry_cipher_map_name (item->string);
 
727
      if (algo)
 
728
        writeout_rem (ctx, _("algorithm: %s"), gcry_cipher_algo_name (algo));
 
729
      else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2"))
 
730
        writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2");
 
731
      else if (item->string)
 
732
        writeout_rem (ctx, _("unsupported algorithm: %s"), item->string);
 
733
      else
 
734
        writeout_rem (ctx, _("seems to be not encrypted"));
 
735
    }
 
736
 
 
737
  item = find_log_item (ctx, AUDIT_GOT_RECIPIENTS, 0);
 
738
  snprintf (numbuf, sizeof numbuf, "%d", 
 
739
            item && item->have_intvalue? item->intvalue : 0);
 
740
  writeout_li (ctx, numbuf, "%s", _("Number of recipients"));
 
741
 
 
742
  /* Loop over all recipients.  */
 
743
  loopitem = NULL;
 
744
  recp_no = 0;
 
745
  while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0)))
 
746
    {
 
747
      recp_no++;
 
748
      writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
 
749
      if (loopitem->cert)
 
750
        {
 
751
          name = get_cert_name (loopitem->cert);
 
752
          writeout_rem (ctx, "%s", name);
 
753
          xfree (name);
 
754
          enter_li (ctx);
 
755
          for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++)
 
756
            {
 
757
              writeout_rem (ctx, "%s", name);
 
758
              xfree (name);
 
759
            }
 
760
          leave_li (ctx);
 
761
        }
 
762
    }
 
763
 
 
764
  leave_li (ctx);
 
765
}
 
766
 
 
767
 
 
768
 
 
769
/* Process a sign operation's log.  */
 
770
static void
 
771
proc_type_sign (audit_ctx_t ctx)
 
772
{
 
773
  log_item_t item;
 
774
 
 
775
  item = NULL;
 
776
  writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
 
777
 
 
778
  enter_li (ctx);
 
779
 
 
780
  item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
 
781
  writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
 
782
 
 
783
 
 
784
  leave_li (ctx);
 
785
}
 
786
 
 
787
 
 
788
 
 
789
/* Process a decrypt operation's log.  */
 
790
static void
 
791
proc_type_decrypt (audit_ctx_t ctx)
 
792
{
 
793
  log_item_t item;
 
794
 
 
795
  item = NULL;
 
796
  writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded"));
 
797
 
 
798
  enter_li (ctx);
 
799
 
 
800
  item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
 
801
  writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
 
802
 
 
803
 
 
804
  leave_li (ctx);
 
805
}
 
806
 
 
807
 
 
808
 
 
809
/* Process a verification operation's log.  */
 
810
static void
 
811
proc_type_verify (audit_ctx_t ctx)
 
812
{
 
813
  log_item_t loopitem, item;
 
814
  int signo, count, idx;
 
815
  char numbuf[35];
 
816
 
 
817
  /* If there is at least one signature status we claim that the
 
818
     verifciation succeeded.  This does not mean that the data has
 
819
     verified okay.  */
 
820
  item = find_log_item (ctx, AUDIT_SIG_STATUS, 0);
 
821
  writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded"));
 
822
  enter_li (ctx);
 
823
 
 
824
  item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
 
825
  writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
 
826
  if (!item)
 
827
    goto leave;
 
828
 
 
829
  item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
 
830
  writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
 
831
  if (!item)
 
832
    goto leave;
 
833
 
 
834
  item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
 
835
  writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded"));
 
836
  if (!item)
 
837
    {
 
838
      item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG);
 
839
      if (item)
 
840
        writeout_rem (ctx, _("Bad hash algorithm: %s"), 
 
841
                      item->string? item->string:"?");
 
842
 
 
843
      goto leave;
 
844
    }
 
845
 
 
846
  /* Loop over all signatures.  */
 
847
  loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
 
848
  assert (loopitem);
 
849
  do
 
850
    {
 
851
      signo = loopitem->have_intvalue? loopitem->intvalue : -1;
 
852
 
 
853
      item = find_next_log_item (ctx, loopitem,
 
854
                                 AUDIT_SIG_STATUS, AUDIT_NEW_SIG);
 
855
      writeout_li (ctx, item? item->string:"?", _("Signature %d"), signo);
 
856
      item = find_next_log_item (ctx, loopitem,
 
857
                                 AUDIT_SIG_NAME, AUDIT_NEW_SIG);
 
858
      if (item)
 
859
        writeout_rem (ctx, "%s", item->string);
 
860
      enter_li (ctx);
 
861
      
 
862
      /* List the certificate chain.  */
 
863
      list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
 
864
 
 
865
      /* Show the result of the chain validation.  */
 
866
      item = find_next_log_item (ctx, loopitem,
 
867
                                 AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG);
 
868
      if (item && item->have_err)
 
869
        {
 
870
          writeout_li (ctx, item->err? "No":"Yes", 
 
871
                       _("Certificate chain valid"));
 
872
          if (item->err)
 
873
            writeout_rem (ctx, "%s", gpg_strerror (item->err));
 
874
        }
 
875
      
 
876
      /* Show whether the root certificate is fine.  */
 
877
      item = find_next_log_item (ctx, loopitem,
 
878
                                 AUDIT_ROOT_TRUSTED, AUDIT_CHAIN_STATUS);
 
879
      if (item)
 
880
        {
 
881
          writeout_li (ctx, item->err?"No":"Yes", "%s",
 
882
                       _("Root certificate trustworthy"));
 
883
          if (item->err)
 
884
            {
 
885
              add_helptag (ctx, "gpgsm.root-cert-not-trusted");
 
886
              writeout_rem (ctx, "%s", gpg_strerror (item->err));
 
887
              list_cert (ctx, item->cert, 0);
 
888
            }
 
889
        }
 
890
 
 
891
      /* Show result of the CRL/OCSP check.  */
 
892
      writeout_li (ctx, "-", "%s", _("CRL/OCSP check of certificates"));
 
893
 /*      add_helptag (ctx, "gpgsm.ocsp-problem"); */
 
894
 
 
895
 
 
896
      leave_li (ctx);
 
897
    }
 
898
  while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
 
899
 
 
900
 
 
901
 leave:
 
902
  /* Always list the certificates stored in the signature.  */
 
903
  item = NULL;
 
904
  count = 0;
 
905
  while ( ((item = find_next_log_item (ctx, item, 
 
906
                                       AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
 
907
    count++;
 
908
  snprintf (numbuf, sizeof numbuf, "%d", count);
 
909
  writeout_li (ctx, numbuf, _("Included certificates"));
 
910
  item = NULL;
 
911
  while ( ((item = find_next_log_item (ctx, item, 
 
912
                                       AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
 
913
    {
 
914
      char *name = get_cert_name (item->cert);
 
915
      writeout_rem (ctx, "%s", name);
 
916
      xfree (name);
 
917
      enter_li (ctx);
 
918
      for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
 
919
        {
 
920
          writeout_rem (ctx, "%s", name);
 
921
          xfree (name);
 
922
        }
 
923
      leave_li (ctx);
 
924
    }
 
925
  leave_li (ctx);
 
926
}
 
927
 
 
928
 
 
929
 
 
930
 
 
931
/* Print the formatted audit result.    THIS IS WORK IN PROGRESS.  */
 
932
void
 
933
audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
 
934
{
 
935
  int idx;
 
936
  size_t n;
 
937
  log_item_t item;
 
938
  helptag_t helptag;
 
939
  const char *s;
 
940
  int show_raw = 0;
 
941
  char *orig_codeset;
 
942
  
 
943
  if (!ctx)
 
944
    return;
 
945
 
 
946
  orig_codeset = i18n_switchto_utf8 ();
 
947
 
 
948
  /* We use an environment variable to include some debug info in the
 
949
     log.  */
 
950
  if ((s = getenv ("gnupg_debug_audit")))
 
951
    {
 
952
      show_raw = 1;
 
953
      if (!strcmp (s, "html"))
 
954
        use_html = 1;
 
955
    }
 
956
 
 
957
  assert (!ctx->outstream);
 
958
  ctx->outstream = out;
 
959
  ctx->use_html = use_html;
 
960
  ctx->indentlevel = 0;
 
961
  clear_helptags (ctx);
 
962
 
 
963
  if (use_html)
 
964
    es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
 
965
 
 
966
  if (!ctx->log || !ctx->logused)
 
967
    {
 
968
      writeout_para (ctx, _("No audit log entries."));
 
969
      goto leave;
 
970
    }
 
971
 
 
972
  if (show_raw)
 
973
    {
 
974
      int maxlen;
 
975
 
 
976
      for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
 
977
        {
 
978
          n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);    
 
979
          if (n > maxlen)
 
980
            maxlen = n;
 
981
        }
 
982
      
 
983
      if (use_html)
 
984
        es_fputs ("<pre>\n", out);
 
985
      for (idx=0; idx < ctx->logused; idx++)
 
986
        {
 
987
          es_fprintf (out, "log: %-*s", 
 
988
                      maxlen, event2str (ctx->log[idx].event));
 
989
          if (ctx->log[idx].have_intvalue)
 
990
            es_fprintf (out, " i=%d", ctx->log[idx].intvalue); 
 
991
          if (ctx->log[idx].string)
 
992
            {
 
993
              es_fputs (" s=`", out); 
 
994
              writeout (ctx, ctx->log[idx].string); 
 
995
              es_fputs ("'", out); 
 
996
            }
 
997
          if (ctx->log[idx].cert)
 
998
            es_fprintf (out, " has_cert"); 
 
999
          if (ctx->log[idx].have_err)
 
1000
            {
 
1001
              es_fputs (" err=`", out);
 
1002
              writeout (ctx, gpg_strerror (ctx->log[idx].err)); 
 
1003
              es_fputs ("'", out);
 
1004
            }
 
1005
          es_fputs ("\n", out);
 
1006
        }
 
1007
      if (use_html)
 
1008
        es_fputs ("</pre>\n", out);
 
1009
      else
 
1010
        es_fputs ("\n", out);
 
1011
    }
 
1012
 
 
1013
  enter_li (ctx);
 
1014
  switch (ctx->type)
 
1015
    {
 
1016
    case AUDIT_TYPE_NONE:
 
1017
      writeout_li (ctx, NULL, _("Unknown operation"));
 
1018
      break;
 
1019
    case AUDIT_TYPE_ENCRYPT:
 
1020
      proc_type_encrypt (ctx);
 
1021
      break;
 
1022
    case AUDIT_TYPE_SIGN:
 
1023
      proc_type_sign (ctx);
 
1024
      break;
 
1025
    case AUDIT_TYPE_DECRYPT:
 
1026
      proc_type_decrypt (ctx);
 
1027
      break;
 
1028
    case AUDIT_TYPE_VERIFY:
 
1029
      proc_type_verify (ctx);
 
1030
      break;
 
1031
    }
 
1032
  item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
 
1033
  if (item && item->have_err)
 
1034
    {
 
1035
      writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
 
1036
      if (item->err)
 
1037
        {
 
1038
          writeout_rem (ctx, "%s", gpg_strerror (item->err));
 
1039
          add_helptag (ctx, "gnupg.agent-problem");
 
1040
        }
 
1041
    }
 
1042
  item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
 
1043
  if (item && item->have_err)
 
1044
    {
 
1045
      writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
 
1046
      if (item->err)
 
1047
        {
 
1048
          writeout_rem (ctx, "%s", gpg_strerror (item->err));
 
1049
          add_helptag (ctx, "gnupg.dirmngr-problem");
 
1050
        }
 
1051
    }
 
1052
  leave_li (ctx);
 
1053
 
 
1054
 
 
1055
  /* Show the help from the collected help tags.  */
 
1056
  if (ctx->helptags)
 
1057
    {
 
1058
      if (use_html)
 
1059
        {
 
1060
          es_fputs ("<hr/>\n", ctx->outstream);
 
1061
          if (ctx->helptags->next)
 
1062
            es_fputs ("<ul>\n", ctx->outstream);
 
1063
        }
 
1064
      else
 
1065
        es_fputs ("\n\n", ctx->outstream);
 
1066
    }
 
1067
  for (helptag = ctx->helptags; helptag; helptag = helptag->next)
 
1068
    {
 
1069
      char *text;
 
1070
 
 
1071
      if (use_html && ctx->helptags->next)
 
1072
        es_fputs ("<li>\n", ctx->outstream);
 
1073
 
 
1074
      text = gnupg_get_help_string (helptag->name, 0);
 
1075
      if (text)
 
1076
        {
 
1077
          writeout_para (ctx, "%s", text);
 
1078
          xfree (text);
 
1079
        }
 
1080
      else
 
1081
        writeout_para (ctx, _("No help available for `%s'."), helptag->name);
 
1082
      if (use_html && ctx->helptags->next)
 
1083
        es_fputs ("</li>\n", ctx->outstream);
 
1084
      if (helptag->next)
 
1085
        es_fputs ("\n", ctx->outstream);
 
1086
    }
 
1087
  if (use_html && ctx->helptags && ctx->helptags->next)
 
1088
    es_fputs ("</ul>\n", ctx->outstream);
 
1089
 
 
1090
 leave:
 
1091
  if (use_html)
 
1092
    es_fputs ("</div>\n", ctx->outstream);
 
1093
  ctx->outstream = NULL;
 
1094
  ctx->use_html = 0;
 
1095
  clear_helptags (ctx);
 
1096
  i18n_switchback (orig_codeset);
 
1097
}
 
1098