2008-02-09 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / audit.c
blob59f881cd58bed8724841a2591c81134505121f30
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 int idx = eventstr_msgidxof (event);
119 if (idx == -1)
120 return "Unknown event";
121 else
122 return eventstr_msgstr + eventstr_msgidx[idx];
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)
132 audit_ctx_t ctx;
134 ctx = xtrycalloc (1, sizeof *ctx);
136 return ctx;
140 /* Release an audit context. Passing NULL for CTX is allowed and does
141 nothing. */
142 void
143 audit_release (audit_ctx_t ctx)
145 int idx;
146 if (!ctx)
147 return;
148 if (ctx->log)
150 for (idx=0; idx < ctx->logused; idx++)
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);
157 xfree (ctx->log);
159 clear_helptags (ctx);
160 xfree (ctx);
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)
169 if (!ctx || ctx->failure)
170 return; /* Audit not enabled or an internal error has occurred. */
172 if (ctx->type && ctx->type != type)
174 ctx->failure = "conflict in type initialization";
175 return;
177 ctx->type = type;
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)
187 log_item_t item, table;
188 size_t size;
190 if (!ctx->log)
192 size = 10;
193 table = xtrymalloc (size * sizeof *table);
194 if (!table)
196 ctx->failure = "Out of memory in create_log_item";
197 return NULL;
199 ctx->log = table;
200 ctx->logsize = size;
201 item = ctx->log + 0;
202 ctx->logused = 1;
204 else if (ctx->logused >= ctx->logsize)
206 size = ctx->logsize + 10;
207 table = xtryrealloc (ctx->log, size * sizeof *table);
208 if (!table)
210 ctx->failure = "Out of memory while reallocating in create_log_item";
211 return NULL;
213 ctx->log = table;
214 ctx->logsize = size;
215 item = ctx->log + ctx->logused++;
217 else
218 item = ctx->log + ctx->logused++;
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;
228 return item;
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)
237 log_item_t item;
239 if (!ctx || ctx->failure)
240 return; /* Audit not enabled or an internal error has occurred. */
241 if (!event)
243 ctx->failure = "Invalid event passed to audit_log";
244 return;
246 if (!(item = create_log_item (ctx)))
247 return;
248 item->event = event;
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)
257 log_item_t item;
259 if (!ctx || ctx->failure)
260 return; /* Audit not enabled or an internal error has occurred. */
261 if (!event)
263 ctx->failure = "Invalid event passed to audit_log_ok";
264 return;
266 if (!(item = create_log_item (ctx)))
267 return;
268 item->event = event;
269 item->err = err;
270 item->have_err = 1;
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)
279 log_item_t item;
281 if (!ctx || ctx->failure)
282 return; /* Audit not enabled or an internal error has occurred. */
283 if (!event)
285 ctx->failure = "Invalid event passed to audit_log_i";
286 return;
288 if (!(item = create_log_item (ctx)))
289 return;
290 item->event = event;
291 item->intvalue = value;
292 item->have_intvalue = 1;
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)
301 log_item_t item;
302 char *tmp;
304 if (!ctx || ctx->failure)
305 return; /* Audit not enabled or an internal error has occurred. */
306 if (!event)
308 ctx->failure = "Invalid event passed to audit_log_s";
309 return;
311 tmp = xtrystrdup (value? value : "");
312 if (!tmp)
314 ctx->failure = "Out of memory in audit_event";
315 return;
317 if (!(item = create_log_item (ctx)))
319 xfree (tmp);
320 return;
322 item->event = event;
323 item->string = tmp;
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)
333 log_item_t item;
335 if (!ctx || ctx->failure)
336 return; /* Audit not enabled or an internal error has occurred. */
337 if (!event)
339 ctx->failure = "Invalid event passed to audit_log_cert";
340 return;
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)
349 ksba_cert_ref (cert);
350 item->cert = cert;
355 /* Write TEXT to the outstream. */
356 static void
357 writeout (audit_ctx_t ctx, const char *text)
359 if (ctx->use_html)
361 for (; *text; text++)
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);
371 else
372 es_fputs (text, ctx->outstream);
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)
380 char *buf;
382 estream_vasprintf (&buf, format, arg_ptr);
383 if (buf)
385 writeout (ctx, buf);
386 xfree (buf);
388 else
389 writeout (ctx, "[!!Out of core!!]");
393 /* Write TEXT as a paragraph. */
394 static void
395 writeout_para (audit_ctx_t ctx, const char *format, ...)
397 va_list arg_ptr;
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);
411 static void
412 enter_li (audit_ctx_t ctx)
414 if (ctx->use_html)
416 if (!ctx->indentlevel)
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);
426 ctx->indentlevel++;
430 static void
431 leave_li (audit_ctx_t ctx)
433 ctx->indentlevel--;
434 if (ctx->use_html)
436 if (!ctx->indentlevel)
437 es_fputs ("</table>\n", ctx->outstream);
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, ...)
447 va_list arg_ptr;
448 const char *color = NULL;
450 if (ctx->use_html && format && oktext)
452 if (!strcmp (oktext, "Yes"))
453 color = "green";
454 else if (!strcmp (oktext, "No"))
455 color = "red";
458 if (ctx->use_html)
460 int i;
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);
471 else
472 es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
473 if (format)
475 va_start (arg_ptr, format) ;
476 writeout_v (ctx, format, arg_ptr);
477 va_end (arg_ptr);
479 if (ctx->use_html)
480 es_fputs ("</td></tr></table>", ctx->outstream);
481 if (format && oktext)
483 if (ctx->use_html)
485 es_fputs ("</td><td>", ctx->outstream);
486 if (color)
487 es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
489 else
490 writeout (ctx, ": ");
491 writeout (ctx, oktext);
492 if (color)
493 es_fputs ("</font>", ctx->outstream);
496 if (ctx->use_html)
497 es_fputs ("</td></tr>\n", ctx->outstream);
498 else
499 es_fputc ('\n', ctx->outstream);
503 /* Write a remark line. */
504 static void
505 writeout_rem (audit_ctx_t ctx, const char *format, ...)
507 va_list arg_ptr;
509 if (ctx->use_html)
511 int i;
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);
519 else
520 es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
521 if (format)
523 va_start (arg_ptr, format) ;
524 writeout_v (ctx, format, arg_ptr);
525 va_end (arg_ptr);
527 if (ctx->use_html)
528 es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
529 else
530 es_fputs (")\n", ctx->outstream);
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)
541 int idx;
543 for (idx=0; idx < ctx->logused; idx++)
545 if (startitem)
547 if (ctx->log + idx == startitem)
548 startitem = NULL;
550 else if (stopevent && ctx->log[idx].event == stopevent)
551 break;
552 else if (ctx->log[idx].event == event)
553 return ctx->log + idx;
555 return NULL;
559 static log_item_t
560 find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
562 return find_next_log_item (ctx, NULL, event, stopevent);
566 /* Helper to a format a serial number. */
567 static char *
568 format_serial (ksba_const_sexp_t sn)
570 const char *p = (const char *)sn;
571 unsigned long n;
572 char *endp;
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);
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)
591 char *result;
592 ksba_sexp_t sn;
593 char *issuer, *p;
595 if (!cert)
596 return xtrystrdup ("[no certificate]");
598 issuer = ksba_cert_get_issuer (cert, 0);
599 sn = ksba_cert_get_serial (cert);
600 if (issuer && sn)
602 p = format_serial (sn);
603 if (!p)
604 result = xtrystrdup ("[invalid S/N]");
605 else
607 result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
608 if (result)
610 *result = '#';
611 strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
613 xfree (p);
616 else
617 result = xtrystrdup ("[missing S/N or issuer]");
618 ksba_free (sn);
619 xfree (issuer);
620 return result;
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)
628 char *result;
629 char *subject;
631 if (!cert)
632 return xtrystrdup ("[no certificate]");
634 subject = ksba_cert_get_subject (cert, idx);
635 if (subject)
637 result = xtrymalloc (strlen (subject) + 1 + 1);
638 if (result)
640 *result = '/';
641 strcpy (result+1, subject);
644 else
645 result = NULL;
646 xfree (subject);
647 return result;
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)
655 char *name;
656 int idx;
658 name = get_cert_name (cert);
659 writeout_rem (ctx, "%s", name);
660 xfree (name);
661 if (with_subj)
663 enter_li (ctx);
664 for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
666 writeout_rem (ctx, "%s", name);
667 xfree (name);
669 leave_li (ctx);
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)
679 log_item_t item;
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;
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
692 list_cert (ctx, item->cert, 0);
694 item = startitem;
695 while ( ((item = find_next_log_item (ctx, item,
696 AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
698 list_cert (ctx, item->cert, 1);
704 /* Process an encrypt operation's log. */
705 static void
706 proc_type_encrypt (audit_ctx_t ctx)
708 log_item_t loopitem, item;
709 int recp_no, idx;
710 char numbuf[35];
711 int algo;
712 char *name;
714 item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
715 writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
717 enter_li (ctx);
719 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
720 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
722 item = find_log_item (ctx, AUDIT_SESSION_KEY, 0);
723 writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created"));
724 if (item)
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"));
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"));
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)))
747 recp_no++;
748 writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
749 if (loopitem->cert)
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++)
757 writeout_rem (ctx, "%s", name);
758 xfree (name);
760 leave_li (ctx);
764 leave_li (ctx);
769 /* Process a sign operation's log. */
770 static void
771 proc_type_sign (audit_ctx_t ctx)
773 log_item_t item;
775 item = NULL;
776 writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
778 enter_li (ctx);
780 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
781 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
784 leave_li (ctx);
789 /* Process a decrypt operation's log. */
790 static void
791 proc_type_decrypt (audit_ctx_t ctx)
793 log_item_t item;
795 item = NULL;
796 writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded"));
798 enter_li (ctx);
800 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
801 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
804 leave_li (ctx);
809 /* Process a verification operation's log. */
810 static void
811 proc_type_verify (audit_ctx_t ctx)
813 log_item_t loopitem, item;
814 int signo, count, idx;
815 char numbuf[35];
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);
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;
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;
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)
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:"?");
843 goto leave;
846 /* Loop over all signatures. */
847 loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
848 assert (loopitem);
851 signo = loopitem->have_intvalue? loopitem->intvalue : -1;
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);
862 /* List the certificate chain. */
863 list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
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)
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));
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)
881 writeout_li (ctx, item->err?"No":"Yes", "%s",
882 _("Root certificate trustworthy"));
883 if (item->err)
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);
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"); */
896 leave_li (ctx);
898 while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
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))))
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++)
920 writeout_rem (ctx, "%s", name);
921 xfree (name);
923 leave_li (ctx);
925 leave_li (ctx);
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)
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;
942 if (!ctx)
943 return;
945 /* We use an environment variable to include some debug info in the
946 log. */
947 if ((s = getenv ("gnupg_debug_audit")))
949 show_raw = 1;
950 if (!strcmp (s, "html"))
951 use_html = 1;
954 assert (!ctx->outstream);
955 ctx->outstream = out;
956 ctx->use_html = use_html;
957 ctx->indentlevel = 0;
958 clear_helptags (ctx);
960 if (use_html)
961 es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
963 if (!ctx->log || !ctx->logused)
965 writeout_para (ctx, _("No audit log entries."));
966 goto leave;
969 if (show_raw)
971 int maxlen;
973 for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
975 n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);
976 if (n > maxlen)
977 maxlen = n;
980 if (use_html)
981 es_fputs ("<pre>\n", out);
982 for (idx=0; idx < ctx->logused; idx++)
984 es_fprintf (out, "log: %-*s",
985 maxlen, event2str (ctx->log[idx].event));
986 if (ctx->log[idx].have_intvalue)
987 es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
988 if (ctx->log[idx].string)
990 es_fputs (" s=`", out);
991 writeout (ctx, ctx->log[idx].string);
992 es_fputs ("'", out);
994 if (ctx->log[idx].cert)
995 es_fprintf (out, " has_cert");
996 if (ctx->log[idx].have_err)
998 es_fputs (" err=`", out);
999 writeout (ctx, gpg_strerror (ctx->log[idx].err));
1000 es_fputs ("'", out);
1002 es_fputs ("\n", out);
1004 if (use_html)
1005 es_fputs ("</pre>\n", out);
1006 else
1007 es_fputs ("\n", out);
1010 enter_li (ctx);
1011 switch (ctx->type)
1013 case AUDIT_TYPE_NONE:
1014 writeout_li (ctx, NULL, _("Unknown operation"));
1015 break;
1016 case AUDIT_TYPE_ENCRYPT:
1017 proc_type_encrypt (ctx);
1018 break;
1019 case AUDIT_TYPE_SIGN:
1020 proc_type_sign (ctx);
1021 break;
1022 case AUDIT_TYPE_DECRYPT:
1023 proc_type_decrypt (ctx);
1024 break;
1025 case AUDIT_TYPE_VERIFY:
1026 proc_type_verify (ctx);
1027 break;
1029 item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
1030 if (item && item->have_err)
1032 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
1033 if (item->err)
1035 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1036 add_helptag (ctx, "gnupg.agent-problem");
1039 item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
1040 if (item && item->have_err)
1042 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
1043 if (item->err)
1045 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1046 add_helptag (ctx, "gnupg.dirmngr-problem");
1049 leave_li (ctx);
1052 /* Show the help from the collected help tags. */
1053 if (ctx->helptags)
1055 if (use_html)
1057 es_fputs ("<hr/>\n", ctx->outstream);
1058 if (ctx->helptags->next)
1059 es_fputs ("<ul>\n", ctx->outstream);
1061 else
1062 es_fputs ("\n\n", ctx->outstream);
1064 for (helptag = ctx->helptags; helptag; helptag = helptag->next)
1066 char *text;
1068 if (use_html && ctx->helptags->next)
1069 es_fputs ("<li>\n", ctx->outstream);
1071 text = gnupg_get_help_string (helptag->name, 0);
1072 if (text)
1074 writeout_para (ctx, "%s", text);
1075 xfree (text);
1077 else
1078 writeout_para (ctx, _("No help available for `%s'."), helptag->name);
1079 if (use_html && ctx->helptags->next)
1080 es_fputs ("</li>\n", ctx->outstream);
1081 if (helptag->next)
1082 es_fputs ("\n", ctx->outstream);
1084 if (use_html && ctx->helptags && ctx->helptags->next)
1085 es_fputs ("</ul>\n", ctx->outstream);
1087 leave:
1088 if (use_html)
1089 es_fputs ("</div>\n", ctx->outstream);
1090 ctx->outstream = NULL;
1091 ctx->use_html = 0;
1092 clear_helptags (ctx);