Start a new development branch.
[gnupg.git] / common / audit.c
blob436f0d25d110482c8a555ae0b90fd86f5caabfeb
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 operation
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, "disabled"))
483 oktext = _("|audit-log-result|Not enabled");
484 else if (!strcmp (oktext, "error"))
485 oktext = _("|audit-log-result|Error");
486 else
487 s = "";
489 /* If we have set a prefix, skip it. */
490 if (!s && *oktext == '|' && (s=strchr (oktext+1,'|')))
491 oktext = s+1;
494 if (ctx->use_html)
496 int i;
498 es_fputs (" <tr><td><table><tr><td>", ctx->outstream);
499 if (color)
500 es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
501 else
502 es_fputs ("*", ctx->outstream);
503 for (i=1; i < ctx->indentlevel; i++)
504 es_fputs ("&nbsp;&nbsp;", ctx->outstream);
505 es_fputs ("</td><td>", ctx->outstream);
507 else
508 es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
509 if (format)
511 va_start (arg_ptr, format) ;
512 writeout_v (ctx, format, arg_ptr);
513 va_end (arg_ptr);
515 if (ctx->use_html)
516 es_fputs ("</td></tr></table>", ctx->outstream);
517 if (format && oktext)
519 if (ctx->use_html)
521 es_fputs ("</td><td>", ctx->outstream);
522 if (color)
523 es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
525 else
526 writeout (ctx, ": ");
527 writeout (ctx, oktext);
528 if (color)
529 es_fputs ("</font>", ctx->outstream);
532 if (ctx->use_html)
533 es_fputs ("</td></tr>\n", ctx->outstream);
534 else
535 es_fputc ('\n', ctx->outstream);
539 /* Write a remark line. */
540 static void
541 writeout_rem (audit_ctx_t ctx, const char *format, ...)
543 va_list arg_ptr;
545 if (ctx->use_html)
547 int i;
549 es_fputs (" <tr><td><table><tr><td>*", ctx->outstream);
550 for (i=1; i < ctx->indentlevel; i++)
551 es_fputs ("&nbsp;&nbsp;", ctx->outstream);
552 es_fputs ("&nbsp;&nbsp;&nbsp;</td><td> (", ctx->outstream);
555 else
556 es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
557 if (format)
559 va_start (arg_ptr, format) ;
560 writeout_v (ctx, format, arg_ptr);
561 va_end (arg_ptr);
563 if (ctx->use_html)
564 es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
565 else
566 es_fputs (")\n", ctx->outstream);
570 /* Return the first log item for EVENT. If STOPEVENT is not 0 never
571 look behind that event in the log. If STARTITEM is not NULL start
572 search _after_that item. */
573 static log_item_t
574 find_next_log_item (audit_ctx_t ctx, log_item_t startitem,
575 audit_event_t event, audit_event_t stopevent)
577 int idx;
579 for (idx=0; idx < ctx->logused; idx++)
581 if (startitem)
583 if (ctx->log + idx == startitem)
584 startitem = NULL;
586 else if (stopevent && ctx->log[idx].event == stopevent)
587 break;
588 else if (ctx->log[idx].event == event)
589 return ctx->log + idx;
591 return NULL;
595 static log_item_t
596 find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
598 return find_next_log_item (ctx, NULL, event, stopevent);
602 /* Helper to a format a serial number. */
603 static char *
604 format_serial (ksba_const_sexp_t sn)
606 const char *p = (const char *)sn;
607 unsigned long n;
608 char *endp;
610 if (!p)
611 return NULL;
612 if (*p != '(')
613 BUG (); /* Not a valid S-expression. */
614 n = strtoul (p+1, &endp, 10);
615 p = endp;
616 if (*p != ':')
617 BUG (); /* Not a valid S-expression. */
618 return bin2hex (p+1, n, NULL);
622 /* Return a malloced string with the serial number and the issuer DN
623 of the certificate. */
624 static char *
625 get_cert_name (ksba_cert_t cert)
627 char *result;
628 ksba_sexp_t sn;
629 char *issuer, *p;
631 if (!cert)
632 return xtrystrdup ("[no certificate]");
634 issuer = ksba_cert_get_issuer (cert, 0);
635 sn = ksba_cert_get_serial (cert);
636 if (issuer && sn)
638 p = format_serial (sn);
639 if (!p)
640 result = xtrystrdup ("[invalid S/N]");
641 else
643 result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
644 if (result)
646 *result = '#';
647 strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
649 xfree (p);
652 else
653 result = xtrystrdup ("[missing S/N or issuer]");
654 ksba_free (sn);
655 xfree (issuer);
656 return result;
659 /* Return a malloced string with the serial number and the issuer DN
660 of the certificate. */
661 static char *
662 get_cert_subject (ksba_cert_t cert, int idx)
664 char *result;
665 char *subject;
667 if (!cert)
668 return xtrystrdup ("[no certificate]");
670 subject = ksba_cert_get_subject (cert, idx);
671 if (subject)
673 result = xtrymalloc (strlen (subject) + 1 + 1);
674 if (result)
676 *result = '/';
677 strcpy (result+1, subject);
680 else
681 result = NULL;
682 xfree (subject);
683 return result;
687 /* List the given certificiate. If CERT is NULL, this is a NOP. */
688 static void
689 list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj)
691 char *name;
692 int idx;
694 name = get_cert_name (cert);
695 writeout_rem (ctx, "%s", name);
696 xfree (name);
697 if (with_subj)
699 enter_li (ctx);
700 for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
702 writeout_rem (ctx, "%s", name);
703 xfree (name);
705 leave_li (ctx);
710 /* List the chain of certificates from STARTITEM up to STOPEVENT. The
711 certifcates are written out as comments. */
712 static void
713 list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
715 log_item_t item;
717 startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
718 writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available"));
719 if (!startitem)
720 return;
722 item = find_next_log_item (ctx, startitem,
723 AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
724 if (!item)
725 writeout_rem (ctx, "%s", _("root certificate missing"));
726 else
728 list_cert (ctx, item->cert, 0);
730 item = startitem;
731 while ( ((item = find_next_log_item (ctx, item,
732 AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
734 list_cert (ctx, item->cert, 1);
740 /* Process an encrypt operation's log. */
741 static void
742 proc_type_encrypt (audit_ctx_t ctx)
744 log_item_t loopitem, item;
745 int recp_no, idx;
746 char numbuf[35];
747 int algo;
748 char *name;
750 item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
751 writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
753 enter_li (ctx);
755 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
756 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
758 item = find_log_item (ctx, AUDIT_SESSION_KEY, 0);
759 writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created"));
760 if (item)
762 algo = gcry_cipher_map_name (item->string);
763 if (algo)
764 writeout_rem (ctx, _("algorithm: %s"), gcry_cipher_algo_name (algo));
765 else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2"))
766 writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2");
767 else if (item->string)
768 writeout_rem (ctx, _("unsupported algorithm: %s"), item->string);
769 else
770 writeout_rem (ctx, _("seems to be not encrypted"));
773 item = find_log_item (ctx, AUDIT_GOT_RECIPIENTS, 0);
774 snprintf (numbuf, sizeof numbuf, "%d",
775 item && item->have_intvalue? item->intvalue : 0);
776 writeout_li (ctx, numbuf, "%s", _("Number of recipients"));
778 /* Loop over all recipients. */
779 loopitem = NULL;
780 recp_no = 0;
781 while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0)))
783 recp_no++;
784 writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
785 if (loopitem->cert)
787 name = get_cert_name (loopitem->cert);
788 writeout_rem (ctx, "%s", name);
789 xfree (name);
790 enter_li (ctx);
791 for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++)
793 writeout_rem (ctx, "%s", name);
794 xfree (name);
796 leave_li (ctx);
800 leave_li (ctx);
805 /* Process a sign operation's log. */
806 static void
807 proc_type_sign (audit_ctx_t ctx)
809 log_item_t item;
811 item = NULL;
812 writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
814 enter_li (ctx);
816 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
817 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
820 leave_li (ctx);
825 /* Process a decrypt operation's log. */
826 static void
827 proc_type_decrypt (audit_ctx_t ctx)
829 log_item_t item;
831 item = NULL;
832 writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded"));
834 enter_li (ctx);
836 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
837 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
840 leave_li (ctx);
845 /* Process a verification operation's log. */
846 static void
847 proc_type_verify (audit_ctx_t ctx)
849 log_item_t loopitem, item;
850 int signo, count, idx;
851 char numbuf[35];
853 /* If there is at least one signature status we claim that the
854 verifciation succeeded. This does not mean that the data has
855 verified okay. */
856 item = find_log_item (ctx, AUDIT_SIG_STATUS, 0);
857 writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded"));
858 enter_li (ctx);
860 item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
861 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
862 if (!item)
863 goto leave;
865 item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
866 writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
867 if (!item)
868 goto leave;
870 item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
871 writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded"));
872 if (!item)
874 item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG);
875 if (item)
876 writeout_rem (ctx, _("Bad hash algorithm: %s"),
877 item->string? item->string:"?");
879 goto leave;
882 /* Loop over all signatures. */
883 loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
884 assert (loopitem);
887 signo = loopitem->have_intvalue? loopitem->intvalue : -1;
889 item = find_next_log_item (ctx, loopitem,
890 AUDIT_SIG_STATUS, AUDIT_NEW_SIG);
891 writeout_li (ctx, item? item->string:"?", _("Signature %d"), signo);
892 item = find_next_log_item (ctx, loopitem,
893 AUDIT_SIG_NAME, AUDIT_NEW_SIG);
894 if (item)
895 writeout_rem (ctx, "%s", item->string);
896 enter_li (ctx);
898 /* List the certificate chain. */
899 list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
901 /* Show the result of the chain validation. */
902 item = find_next_log_item (ctx, loopitem,
903 AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG);
904 if (item && item->have_err)
906 writeout_li (ctx, item->err? "No":"Yes",
907 _("Certificate chain valid"));
908 if (item->err)
909 writeout_rem (ctx, "%s", gpg_strerror (item->err));
912 /* Show whether the root certificate is fine. */
913 item = find_next_log_item (ctx, loopitem,
914 AUDIT_ROOT_TRUSTED, AUDIT_CHAIN_STATUS);
915 if (item)
917 writeout_li (ctx, item->err?"No":"Yes", "%s",
918 _("Root certificate trustworthy"));
919 if (item->err)
921 add_helptag (ctx, "gpgsm.root-cert-not-trusted");
922 writeout_rem (ctx, "%s", gpg_strerror (item->err));
923 list_cert (ctx, item->cert, 0);
927 /* Show result of the CRL/OCSP check. */
928 item = find_next_log_item (ctx, loopitem,
929 AUDIT_CRL_CHECK, AUDIT_NEW_SIG);
930 if (item)
932 const char *ok;
933 switch (gpg_err_code (item->err))
935 case 0: ok = "good"; break;
936 case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
937 case GPG_ERR_NOT_ENABLED: ok = "disabled"; break;
938 case GPG_ERR_NO_CRL_KNOWN:
939 ok = _("no CRL found for certificate");
940 break;
941 case GPG_ERR_CRL_TOO_OLD:
942 ok = _("the available CRL is too old");
943 break;
944 default: ok = gpg_strerror (item->err); break;
947 writeout_li (ctx, ok, "%s", _("CRL/OCSP check of certificates"));
948 if (item->err
949 && gpg_err_code (item->err) != GPG_ERR_CERT_REVOKED
950 && gpg_err_code (item->err) != GPG_ERR_NOT_ENABLED)
951 add_helptag (ctx, "gpgsm.crl-problem");
954 leave_li (ctx);
956 while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
959 leave:
960 /* Always list the certificates stored in the signature. */
961 item = NULL;
962 count = 0;
963 while ( ((item = find_next_log_item (ctx, item,
964 AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
965 count++;
966 snprintf (numbuf, sizeof numbuf, "%d", count);
967 writeout_li (ctx, numbuf, _("Included certificates"));
968 item = NULL;
969 while ( ((item = find_next_log_item (ctx, item,
970 AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
972 char *name = get_cert_name (item->cert);
973 writeout_rem (ctx, "%s", name);
974 xfree (name);
975 enter_li (ctx);
976 for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
978 writeout_rem (ctx, "%s", name);
979 xfree (name);
981 leave_li (ctx);
983 leave_li (ctx);
989 /* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
990 void
991 audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
993 int idx;
994 size_t n;
995 log_item_t item;
996 helptag_t helptag;
997 const char *s;
998 int show_raw = 0;
999 char *orig_codeset;
1001 if (!ctx)
1002 return;
1004 orig_codeset = i18n_switchto_utf8 ();
1006 /* We use an environment variable to include some debug info in the
1007 log. */
1008 if ((s = getenv ("gnupg_debug_audit")))
1010 show_raw = 1;
1011 if (!strcmp (s, "html"))
1012 use_html = 1;
1015 assert (!ctx->outstream);
1016 ctx->outstream = out;
1017 ctx->use_html = use_html;
1018 ctx->indentlevel = 0;
1019 clear_helptags (ctx);
1021 if (use_html)
1022 es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
1024 if (!ctx->log || !ctx->logused)
1026 writeout_para (ctx, _("No audit log entries."));
1027 goto leave;
1030 if (show_raw)
1032 int maxlen;
1034 for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
1036 n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);
1037 if (n > maxlen)
1038 maxlen = n;
1041 if (use_html)
1042 es_fputs ("<pre>\n", out);
1043 for (idx=0; idx < ctx->logused; idx++)
1045 es_fprintf (out, "log: %-*s",
1046 maxlen, event2str (ctx->log[idx].event));
1047 if (ctx->log[idx].have_intvalue)
1048 es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
1049 if (ctx->log[idx].string)
1051 es_fputs (" s=`", out);
1052 writeout (ctx, ctx->log[idx].string);
1053 es_fputs ("'", out);
1055 if (ctx->log[idx].cert)
1056 es_fprintf (out, " has_cert");
1057 if (ctx->log[idx].have_err)
1059 es_fputs (" err=`", out);
1060 writeout (ctx, gpg_strerror (ctx->log[idx].err));
1061 es_fputs ("'", out);
1063 es_fputs ("\n", out);
1065 if (use_html)
1066 es_fputs ("</pre>\n", out);
1067 else
1068 es_fputs ("\n", out);
1071 enter_li (ctx);
1072 switch (ctx->type)
1074 case AUDIT_TYPE_NONE:
1075 writeout_li (ctx, NULL, _("Unknown operation"));
1076 break;
1077 case AUDIT_TYPE_ENCRYPT:
1078 proc_type_encrypt (ctx);
1079 break;
1080 case AUDIT_TYPE_SIGN:
1081 proc_type_sign (ctx);
1082 break;
1083 case AUDIT_TYPE_DECRYPT:
1084 proc_type_decrypt (ctx);
1085 break;
1086 case AUDIT_TYPE_VERIFY:
1087 proc_type_verify (ctx);
1088 break;
1090 item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
1091 if (item && item->have_err)
1093 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
1094 if (item->err)
1096 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1097 add_helptag (ctx, "gnupg.agent-problem");
1100 item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
1101 if (item && item->have_err)
1103 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
1104 if (item->err)
1106 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1107 add_helptag (ctx, "gnupg.dirmngr-problem");
1110 leave_li (ctx);
1113 /* Show the help from the collected help tags. */
1114 if (ctx->helptags)
1116 if (use_html)
1118 es_fputs ("<hr/>\n", ctx->outstream);
1119 if (ctx->helptags->next)
1120 es_fputs ("<ul>\n", ctx->outstream);
1122 else
1123 es_fputs ("\n\n", ctx->outstream);
1125 for (helptag = ctx->helptags; helptag; helptag = helptag->next)
1127 char *text;
1129 if (use_html && ctx->helptags->next)
1130 es_fputs ("<li>\n", ctx->outstream);
1132 text = gnupg_get_help_string (helptag->name, 0);
1133 if (text)
1135 writeout_para (ctx, "%s", text);
1136 xfree (text);
1138 else
1139 writeout_para (ctx, _("No help available for `%s'."), helptag->name);
1140 if (use_html && ctx->helptags->next)
1141 es_fputs ("</li>\n", ctx->outstream);
1142 if (helptag->next)
1143 es_fputs ("\n", ctx->outstream);
1145 if (use_html && ctx->helptags && ctx->helptags->next)
1146 es_fputs ("</ul>\n", ctx->outstream);
1148 leave:
1149 if (use_html)
1150 es_fputs ("</div>\n", ctx->outstream);
1151 ctx->outstream = NULL;
1152 ctx->use_html = 0;
1153 clear_helptags (ctx);
1154 i18n_switchback (orig_codeset);