2009-05-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / audit.c
bloba3c5b80d51a54affc910e56a0f82e4a4ce2597a6
1 /* audit.c - GnuPG's audit subsystem
2 * Copyright (C) 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <assert.h>
26 #include "util.h"
27 #include "i18n.h"
28 #include "audit.h"
29 #include "audit-events.h"
31 /* A list to maintain a list of helptags. */
32 struct helptag_s
34 struct helptag_s *next;
35 const char *name;
37 typedef struct helptag_s *helptag_t;
40 /* One log entry. */
41 struct log_item_s
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;
51 typedef struct log_item_s *log_item_t;
55 /* The main audit object. */
56 struct audit_ctx_s
58 const char *failure; /* If set a description of the internal failure. */
59 audit_type_t type;
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. */
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. */
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);
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)
87 helptag_t item;
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;
101 /* Remove all help tags from the context. */
102 static void
103 clear_helptags (audit_ctx_t ctx)
105 while (ctx->helptags)
107 helptag_t tmp = ctx->helptags->next;
108 xfree (ctx->helptags);
109 ctx->helptags = tmp;
115 static const char *
116 event2str (audit_event_t event)
118 /* We need the cast so that compiler does not complain about an
119 always true comparison (>= 0) for an unsigned value. */
120 int idx = eventstr_msgidxof ((int)event);
121 if (idx == -1)
122 return "Unknown event";
123 else
124 return eventstr_msgstr + eventstr_msgidx[idx];
129 /* Create a new audit context. In case of an error NULL is returned
130 and errno set appropriately. */
131 audit_ctx_t
132 audit_new (void)
134 audit_ctx_t ctx;
136 ctx = xtrycalloc (1, sizeof *ctx);
138 return ctx;
142 /* Release an audit context. Passing NULL for CTX is allowed and does
143 nothing. */
144 void
145 audit_release (audit_ctx_t ctx)
147 int idx;
148 if (!ctx)
149 return;
150 if (ctx->log)
152 for (idx=0; idx < ctx->logused; idx++)
154 if (ctx->log[idx].string)
155 xfree (ctx->log[idx].string);
156 if (ctx->log[idx].cert)
157 ksba_cert_release (ctx->log[idx].cert);
159 xfree (ctx->log);
161 clear_helptags (ctx);
162 xfree (ctx);
166 /* Set the type for the audit operation. If CTX is NULL, this is a
167 dummy fucntion. */
168 void
169 audit_set_type (audit_ctx_t ctx, audit_type_t type)
171 if (!ctx || ctx->failure)
172 return; /* Audit not enabled or an internal error has occurred. */
174 if (ctx->type && ctx->type != type)
176 ctx->failure = "conflict in type initialization";
177 return;
179 ctx->type = type;
183 /* Create a new log item and put it into the table. Return that log
184 item on success; return NULL on memory failure and mark that in
185 CTX. */
186 static log_item_t
187 create_log_item (audit_ctx_t ctx)
189 log_item_t item, table;
190 size_t size;
192 if (!ctx->log)
194 size = 10;
195 table = xtrymalloc (size * sizeof *table);
196 if (!table)
198 ctx->failure = "Out of memory in create_log_item";
199 return NULL;
201 ctx->log = table;
202 ctx->logsize = size;
203 item = ctx->log + 0;
204 ctx->logused = 1;
206 else if (ctx->logused >= ctx->logsize)
208 size = ctx->logsize + 10;
209 table = xtryrealloc (ctx->log, size * sizeof *table);
210 if (!table)
212 ctx->failure = "Out of memory while reallocating in create_log_item";
213 return NULL;
215 ctx->log = table;
216 ctx->logsize = size;
217 item = ctx->log + ctx->logused++;
219 else
220 item = ctx->log + ctx->logused++;
222 item->event = AUDIT_NULL_EVENT;
223 item->err = 0;
224 item->have_err = 0;
225 item->intvalue = 0;
226 item->have_intvalue = 0;
227 item->string = NULL;
228 item->cert = NULL;
230 return item;
234 /* Add a new event to the audit log. If CTX is NULL, this function
235 does nothing. */
236 void
237 audit_log (audit_ctx_t ctx, audit_event_t event)
239 log_item_t item;
241 if (!ctx || ctx->failure)
242 return; /* Audit not enabled or an internal error has occurred. */
243 if (!event)
245 ctx->failure = "Invalid event passed to audit_log";
246 return;
248 if (!(item = create_log_item (ctx)))
249 return;
250 item->event = event;
253 /* Add a new event to the audit log. If CTX is NULL, this function
254 does nothing. This version also adds the result of the oepration
255 to the log.. */
256 void
257 audit_log_ok (audit_ctx_t ctx, audit_event_t event, gpg_error_t err)
259 log_item_t item;
261 if (!ctx || ctx->failure)
262 return; /* Audit not enabled or an internal error has occurred. */
263 if (!event)
265 ctx->failure = "Invalid event passed to audit_log_ok";
266 return;
268 if (!(item = create_log_item (ctx)))
269 return;
270 item->event = event;
271 item->err = err;
272 item->have_err = 1;
276 /* Add a new event to the audit log. If CTX is NULL, this function
277 does nothing. This version also add the integer VALUE to the log. */
278 void
279 audit_log_i (audit_ctx_t ctx, audit_event_t event, int value)
281 log_item_t item;
283 if (!ctx || ctx->failure)
284 return; /* Audit not enabled or an internal error has occurred. */
285 if (!event)
287 ctx->failure = "Invalid event passed to audit_log_i";
288 return;
290 if (!(item = create_log_item (ctx)))
291 return;
292 item->event = event;
293 item->intvalue = value;
294 item->have_intvalue = 1;
298 /* Add a new event to the audit log. If CTX is NULL, this function
299 does nothing. This version also add the integer VALUE to the log. */
300 void
301 audit_log_s (audit_ctx_t ctx, audit_event_t event, const char *value)
303 log_item_t item;
304 char *tmp;
306 if (!ctx || ctx->failure)
307 return; /* Audit not enabled or an internal error has occurred. */
308 if (!event)
310 ctx->failure = "Invalid event passed to audit_log_s";
311 return;
313 tmp = xtrystrdup (value? value : "");
314 if (!tmp)
316 ctx->failure = "Out of memory in audit_event";
317 return;
319 if (!(item = create_log_item (ctx)))
321 xfree (tmp);
322 return;
324 item->event = event;
325 item->string = tmp;
328 /* Add a new event to the audit log. If CTX is NULL, this function
329 does nothing. This version also adds the certificate CERT and the
330 result of an operation to the log. */
331 void
332 audit_log_cert (audit_ctx_t ctx, audit_event_t event,
333 ksba_cert_t cert, gpg_error_t err)
335 log_item_t item;
337 if (!ctx || ctx->failure)
338 return; /* Audit not enabled or an internal error has occurred. */
339 if (!event)
341 ctx->failure = "Invalid event passed to audit_log_cert";
342 return;
344 if (!(item = create_log_item (ctx)))
345 return;
346 item->event = event;
347 item->err = err;
348 item->have_err = 1;
349 if (cert)
351 ksba_cert_ref (cert);
352 item->cert = cert;
357 /* Write TEXT to the outstream. */
358 static void
359 writeout (audit_ctx_t ctx, const char *text)
361 if (ctx->use_html)
363 for (; *text; text++)
365 if (*text == '<')
366 es_fputs ("&lt;", ctx->outstream);
367 else if (*text == '&')
368 es_fputs ("&amp;", ctx->outstream);
369 else
370 es_putc (*text, ctx->outstream);
373 else
374 es_fputs (text, ctx->outstream);
378 /* Write TEXT to the outstream using a variable argument list. */
379 static void
380 writeout_v (audit_ctx_t ctx, const char *format, va_list arg_ptr)
382 char *buf;
384 estream_vasprintf (&buf, format, arg_ptr);
385 if (buf)
387 writeout (ctx, buf);
388 xfree (buf);
390 else
391 writeout (ctx, "[!!Out of core!!]");
395 /* Write TEXT as a paragraph. */
396 static void
397 writeout_para (audit_ctx_t ctx, const char *format, ...)
399 va_list arg_ptr;
401 if (ctx->use_html)
402 es_fputs ("<p>", ctx->outstream);
403 va_start (arg_ptr, format) ;
404 writeout_v (ctx, format, arg_ptr);
405 va_end (arg_ptr);
406 if (ctx->use_html)
407 es_fputs ("</p>\n", ctx->outstream);
408 else
409 es_fputc ('\n', ctx->outstream);
413 static void
414 enter_li (audit_ctx_t ctx)
416 if (ctx->use_html)
418 if (!ctx->indentlevel)
420 es_fputs ("<table border=\"0\">\n"
421 " <colgroup>\n"
422 " <col width=\"80%\" />\n"
423 " <col width=\"20%\" />\n"
424 " </colgroup>\n",
425 ctx->outstream);
428 ctx->indentlevel++;
432 static void
433 leave_li (audit_ctx_t ctx)
435 ctx->indentlevel--;
436 if (ctx->use_html)
438 if (!ctx->indentlevel)
439 es_fputs ("</table>\n", ctx->outstream);
444 /* Write TEXT as a list element. If OKTEXT is not NULL, append it to
445 the last line. */
446 static void
447 writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...)
449 va_list arg_ptr;
450 const char *color = NULL;
452 if (ctx->use_html && format && oktext)
454 if (!strcmp (oktext, "Yes")
455 || !strcmp (oktext, "good") )
456 color = "green";
457 else if (!strcmp (oktext, "No")
458 || !strcmp (oktext, "bad") )
459 color = "red";
462 if (format && oktext)
464 const char *s = NULL;
466 if (!strcmp (oktext, "Yes"))
467 oktext = _("Yes");
468 else if (!strcmp (oktext, "No"))
469 oktext = _("No");
470 else if (!strcmp (oktext, "good"))
472 /* TRANSLATORS: Copy the prefix between the vertical bars
473 verbatim. It will not be printed. */
474 oktext = _("|audit-log-result|Good");
476 else if (!strcmp (oktext, "bad"))
477 oktext = _("|audit-log-result|Bad");
478 else if (!strcmp (oktext, "unsupported"))
479 oktext = _("|audit-log-result|Not supported");
480 else if (!strcmp (oktext, "no-cert"))
481 oktext = _("|audit-log-result|No certificate");
482 else if (!strcmp (oktext, "error"))
483 oktext = _("|audit-log-result|Error");
484 else
485 s = "";
487 /* If we have set a prefix, skip it. */
488 if (!s && *oktext == '|' && (s=strchr (oktext+1,'|')))
489 oktext = s+1;
492 if (ctx->use_html)
494 int i;
496 es_fputs (" <tr><td><table><tr><td>", ctx->outstream);
497 if (color)
498 es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
499 else
500 es_fputs ("*", ctx->outstream);
501 for (i=1; i < ctx->indentlevel; i++)
502 es_fputs ("&nbsp;&nbsp;", ctx->outstream);
503 es_fputs ("</td><td>", ctx->outstream);
505 else
506 es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
507 if (format)
509 va_start (arg_ptr, format) ;
510 writeout_v (ctx, format, arg_ptr);
511 va_end (arg_ptr);
513 if (ctx->use_html)
514 es_fputs ("</td></tr></table>", ctx->outstream);
515 if (format && oktext)
517 if (ctx->use_html)
519 es_fputs ("</td><td>", ctx->outstream);
520 if (color)
521 es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
523 else
524 writeout (ctx, ": ");
525 writeout (ctx, oktext);
526 if (color)
527 es_fputs ("</font>", ctx->outstream);
530 if (ctx->use_html)
531 es_fputs ("</td></tr>\n", ctx->outstream);
532 else
533 es_fputc ('\n', ctx->outstream);
537 /* Write a remark line. */
538 static void
539 writeout_rem (audit_ctx_t ctx, const char *format, ...)
541 va_list arg_ptr;
543 if (ctx->use_html)
545 int i;
547 es_fputs (" <tr><td><table><tr><td>*", ctx->outstream);
548 for (i=1; i < ctx->indentlevel; i++)
549 es_fputs ("&nbsp;&nbsp;", ctx->outstream);
550 es_fputs ("&nbsp;&nbsp;&nbsp;</td><td> (", ctx->outstream);
553 else
554 es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
555 if (format)
557 va_start (arg_ptr, format) ;
558 writeout_v (ctx, format, arg_ptr);
559 va_end (arg_ptr);
561 if (ctx->use_html)
562 es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
563 else
564 es_fputs (")\n", ctx->outstream);
568 /* Return the first log item for EVENT. If STOPEVENT is not 0 never
569 look behind that event in the log. If STARTITEM is not NULL start
570 search _after_that item. */
571 static log_item_t
572 find_next_log_item (audit_ctx_t ctx, log_item_t startitem,
573 audit_event_t event, audit_event_t stopevent)
575 int idx;
577 for (idx=0; idx < ctx->logused; idx++)
579 if (startitem)
581 if (ctx->log + idx == startitem)
582 startitem = NULL;
584 else if (stopevent && ctx->log[idx].event == stopevent)
585 break;
586 else if (ctx->log[idx].event == event)
587 return ctx->log + idx;
589 return NULL;
593 static log_item_t
594 find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
596 return find_next_log_item (ctx, NULL, event, stopevent);
600 /* Helper to a format a serial number. */
601 static char *
602 format_serial (ksba_const_sexp_t sn)
604 const char *p = (const char *)sn;
605 unsigned long n;
606 char *endp;
608 if (!p)
609 return NULL;
610 if (*p != '(')
611 BUG (); /* Not a valid S-expression. */
612 n = strtoul (p+1, &endp, 10);
613 p = endp;
614 if (*p != ':')
615 BUG (); /* Not a valid S-expression. */
616 return bin2hex (p+1, n, NULL);
620 /* Return a malloced string with the serial number and the issuer DN
621 of the certificate. */
622 static char *
623 get_cert_name (ksba_cert_t cert)
625 char *result;
626 ksba_sexp_t sn;
627 char *issuer, *p;
629 if (!cert)
630 return xtrystrdup ("[no certificate]");
632 issuer = ksba_cert_get_issuer (cert, 0);
633 sn = ksba_cert_get_serial (cert);
634 if (issuer && sn)
636 p = format_serial (sn);
637 if (!p)
638 result = xtrystrdup ("[invalid S/N]");
639 else
641 result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
642 if (result)
644 *result = '#';
645 strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
647 xfree (p);
650 else
651 result = xtrystrdup ("[missing S/N or issuer]");
652 ksba_free (sn);
653 xfree (issuer);
654 return result;
657 /* Return a malloced string with the serial number and the issuer DN
658 of the certificate. */
659 static char *
660 get_cert_subject (ksba_cert_t cert, int idx)
662 char *result;
663 char *subject;
665 if (!cert)
666 return xtrystrdup ("[no certificate]");
668 subject = ksba_cert_get_subject (cert, idx);
669 if (subject)
671 result = xtrymalloc (strlen (subject) + 1 + 1);
672 if (result)
674 *result = '/';
675 strcpy (result+1, subject);
678 else
679 result = NULL;
680 xfree (subject);
681 return result;
685 /* List the given certificiate. If CERT is NULL, this is a NOP. */
686 static void
687 list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj)
689 char *name;
690 int idx;
692 name = get_cert_name (cert);
693 writeout_rem (ctx, "%s", name);
694 xfree (name);
695 if (with_subj)
697 enter_li (ctx);
698 for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
700 writeout_rem (ctx, "%s", name);
701 xfree (name);
703 leave_li (ctx);
708 /* List the chain of certificates from STARTITEM up to STOPEVENT. The
709 certifcates are written out as comments. */
710 static void
711 list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
713 log_item_t item;
715 startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
716 writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available"));
717 if (!startitem)
718 return;
720 item = find_next_log_item (ctx, startitem,
721 AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
722 if (!item)
723 writeout_rem (ctx, "%s", _("root certificate missing"));
724 else
726 list_cert (ctx, item->cert, 0);
728 item = startitem;
729 while ( ((item = find_next_log_item (ctx, item,
730 AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
732 list_cert (ctx, item->cert, 1);
738 /* Process an encrypt operation's log. */
739 static void
740 proc_type_encrypt (audit_ctx_t ctx)
742 log_item_t loopitem, item;
743 int recp_no, idx;
744 char numbuf[35];
745 int algo;
746 char *name;
748 item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
749 writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
751 enter_li (ctx);
753 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
754 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
756 item = find_log_item (ctx, AUDIT_SESSION_KEY, 0);
757 writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created"));
758 if (item)
760 algo = gcry_cipher_map_name (item->string);
761 if (algo)
762 writeout_rem (ctx, _("algorithm: %s"), gcry_cipher_algo_name (algo));
763 else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2"))
764 writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2");
765 else if (item->string)
766 writeout_rem (ctx, _("unsupported algorithm: %s"), item->string);
767 else
768 writeout_rem (ctx, _("seems to be not encrypted"));
771 item = find_log_item (ctx, AUDIT_GOT_RECIPIENTS, 0);
772 snprintf (numbuf, sizeof numbuf, "%d",
773 item && item->have_intvalue? item->intvalue : 0);
774 writeout_li (ctx, numbuf, "%s", _("Number of recipients"));
776 /* Loop over all recipients. */
777 loopitem = NULL;
778 recp_no = 0;
779 while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0)))
781 recp_no++;
782 writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
783 if (loopitem->cert)
785 name = get_cert_name (loopitem->cert);
786 writeout_rem (ctx, "%s", name);
787 xfree (name);
788 enter_li (ctx);
789 for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++)
791 writeout_rem (ctx, "%s", name);
792 xfree (name);
794 leave_li (ctx);
798 leave_li (ctx);
803 /* Process a sign operation's log. */
804 static void
805 proc_type_sign (audit_ctx_t ctx)
807 log_item_t item;
809 item = NULL;
810 writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
812 enter_li (ctx);
814 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
815 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
818 leave_li (ctx);
823 /* Process a decrypt operation's log. */
824 static void
825 proc_type_decrypt (audit_ctx_t ctx)
827 log_item_t item;
829 item = NULL;
830 writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded"));
832 enter_li (ctx);
834 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
835 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
838 leave_li (ctx);
843 /* Process a verification operation's log. */
844 static void
845 proc_type_verify (audit_ctx_t ctx)
847 log_item_t loopitem, item;
848 int signo, count, idx;
849 char numbuf[35];
851 /* If there is at least one signature status we claim that the
852 verifciation succeeded. This does not mean that the data has
853 verified okay. */
854 item = find_log_item (ctx, AUDIT_SIG_STATUS, 0);
855 writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded"));
856 enter_li (ctx);
858 item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
859 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
860 if (!item)
861 goto leave;
863 item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
864 writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
865 if (!item)
866 goto leave;
868 item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
869 writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded"));
870 if (!item)
872 item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG);
873 if (item)
874 writeout_rem (ctx, _("Bad hash algorithm: %s"),
875 item->string? item->string:"?");
877 goto leave;
880 /* Loop over all signatures. */
881 loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
882 assert (loopitem);
885 signo = loopitem->have_intvalue? loopitem->intvalue : -1;
887 item = find_next_log_item (ctx, loopitem,
888 AUDIT_SIG_STATUS, AUDIT_NEW_SIG);
889 writeout_li (ctx, item? item->string:"?", _("Signature %d"), signo);
890 item = find_next_log_item (ctx, loopitem,
891 AUDIT_SIG_NAME, AUDIT_NEW_SIG);
892 if (item)
893 writeout_rem (ctx, "%s", item->string);
894 enter_li (ctx);
896 /* List the certificate chain. */
897 list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
899 /* Show the result of the chain validation. */
900 item = find_next_log_item (ctx, loopitem,
901 AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG);
902 if (item && item->have_err)
904 writeout_li (ctx, item->err? "No":"Yes",
905 _("Certificate chain valid"));
906 if (item->err)
907 writeout_rem (ctx, "%s", gpg_strerror (item->err));
910 /* Show whether the root certificate is fine. */
911 item = find_next_log_item (ctx, loopitem,
912 AUDIT_ROOT_TRUSTED, AUDIT_CHAIN_STATUS);
913 if (item)
915 writeout_li (ctx, item->err?"No":"Yes", "%s",
916 _("Root certificate trustworthy"));
917 if (item->err)
919 add_helptag (ctx, "gpgsm.root-cert-not-trusted");
920 writeout_rem (ctx, "%s", gpg_strerror (item->err));
921 list_cert (ctx, item->cert, 0);
925 /* Show result of the CRL/OCSP check. */
926 writeout_li (ctx, "-", "%s", _("CRL/OCSP check of certificates"));
927 /* add_helptag (ctx, "gpgsm.ocsp-problem"); */
930 leave_li (ctx);
932 while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
935 leave:
936 /* Always list the certificates stored in the signature. */
937 item = NULL;
938 count = 0;
939 while ( ((item = find_next_log_item (ctx, item,
940 AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
941 count++;
942 snprintf (numbuf, sizeof numbuf, "%d", count);
943 writeout_li (ctx, numbuf, _("Included certificates"));
944 item = NULL;
945 while ( ((item = find_next_log_item (ctx, item,
946 AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
948 char *name = get_cert_name (item->cert);
949 writeout_rem (ctx, "%s", name);
950 xfree (name);
951 enter_li (ctx);
952 for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
954 writeout_rem (ctx, "%s", name);
955 xfree (name);
957 leave_li (ctx);
959 leave_li (ctx);
965 /* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
966 void
967 audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
969 int idx;
970 size_t n;
971 log_item_t item;
972 helptag_t helptag;
973 const char *s;
974 int show_raw = 0;
975 char *orig_codeset;
977 if (!ctx)
978 return;
980 orig_codeset = i18n_switchto_utf8 ();
982 /* We use an environment variable to include some debug info in the
983 log. */
984 if ((s = getenv ("gnupg_debug_audit")))
986 show_raw = 1;
987 if (!strcmp (s, "html"))
988 use_html = 1;
991 assert (!ctx->outstream);
992 ctx->outstream = out;
993 ctx->use_html = use_html;
994 ctx->indentlevel = 0;
995 clear_helptags (ctx);
997 if (use_html)
998 es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
1000 if (!ctx->log || !ctx->logused)
1002 writeout_para (ctx, _("No audit log entries."));
1003 goto leave;
1006 if (show_raw)
1008 int maxlen;
1010 for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
1012 n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);
1013 if (n > maxlen)
1014 maxlen = n;
1017 if (use_html)
1018 es_fputs ("<pre>\n", out);
1019 for (idx=0; idx < ctx->logused; idx++)
1021 es_fprintf (out, "log: %-*s",
1022 maxlen, event2str (ctx->log[idx].event));
1023 if (ctx->log[idx].have_intvalue)
1024 es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
1025 if (ctx->log[idx].string)
1027 es_fputs (" s=`", out);
1028 writeout (ctx, ctx->log[idx].string);
1029 es_fputs ("'", out);
1031 if (ctx->log[idx].cert)
1032 es_fprintf (out, " has_cert");
1033 if (ctx->log[idx].have_err)
1035 es_fputs (" err=`", out);
1036 writeout (ctx, gpg_strerror (ctx->log[idx].err));
1037 es_fputs ("'", out);
1039 es_fputs ("\n", out);
1041 if (use_html)
1042 es_fputs ("</pre>\n", out);
1043 else
1044 es_fputs ("\n", out);
1047 enter_li (ctx);
1048 switch (ctx->type)
1050 case AUDIT_TYPE_NONE:
1051 writeout_li (ctx, NULL, _("Unknown operation"));
1052 break;
1053 case AUDIT_TYPE_ENCRYPT:
1054 proc_type_encrypt (ctx);
1055 break;
1056 case AUDIT_TYPE_SIGN:
1057 proc_type_sign (ctx);
1058 break;
1059 case AUDIT_TYPE_DECRYPT:
1060 proc_type_decrypt (ctx);
1061 break;
1062 case AUDIT_TYPE_VERIFY:
1063 proc_type_verify (ctx);
1064 break;
1066 item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
1067 if (item && item->have_err)
1069 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
1070 if (item->err)
1072 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1073 add_helptag (ctx, "gnupg.agent-problem");
1076 item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
1077 if (item && item->have_err)
1079 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
1080 if (item->err)
1082 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1083 add_helptag (ctx, "gnupg.dirmngr-problem");
1086 leave_li (ctx);
1089 /* Show the help from the collected help tags. */
1090 if (ctx->helptags)
1092 if (use_html)
1094 es_fputs ("<hr/>\n", ctx->outstream);
1095 if (ctx->helptags->next)
1096 es_fputs ("<ul>\n", ctx->outstream);
1098 else
1099 es_fputs ("\n\n", ctx->outstream);
1101 for (helptag = ctx->helptags; helptag; helptag = helptag->next)
1103 char *text;
1105 if (use_html && ctx->helptags->next)
1106 es_fputs ("<li>\n", ctx->outstream);
1108 text = gnupg_get_help_string (helptag->name, 0);
1109 if (text)
1111 writeout_para (ctx, "%s", text);
1112 xfree (text);
1114 else
1115 writeout_para (ctx, _("No help available for `%s'."), helptag->name);
1116 if (use_html && ctx->helptags->next)
1117 es_fputs ("</li>\n", ctx->outstream);
1118 if (helptag->next)
1119 es_fputs ("\n", ctx->outstream);
1121 if (use_html && ctx->helptags && ctx->helptags->next)
1122 es_fputs ("</ul>\n", ctx->outstream);
1124 leave:
1125 if (use_html)
1126 es_fputs ("</div>\n", ctx->outstream);
1127 ctx->outstream = NULL;
1128 ctx->use_html = 0;
1129 clear_helptags (ctx);
1130 i18n_switchback (orig_codeset);