Fixed some card related problems.
[gnupg.git] / common / audit.c
blob3bb128d519a9cfdbc15227294f17f954c515d6b6
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 color = "green";
456 else if (!strcmp (oktext, "No"))
457 color = "red";
460 if (format && oktext)
462 if (!strcmp (oktext, "Yes"))
463 oktext = _("Yes");
464 else if (!strcmp (oktext, "No"))
465 oktext = _("No");
468 if (ctx->use_html)
470 int i;
472 es_fputs (" <tr><td><table><tr><td>", ctx->outstream);
473 if (color)
474 es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
475 else
476 es_fputs ("*", ctx->outstream);
477 for (i=1; i < ctx->indentlevel; i++)
478 es_fputs ("&nbsp;&nbsp;", ctx->outstream);
479 es_fputs ("</td><td>", ctx->outstream);
481 else
482 es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
483 if (format)
485 va_start (arg_ptr, format) ;
486 writeout_v (ctx, format, arg_ptr);
487 va_end (arg_ptr);
489 if (ctx->use_html)
490 es_fputs ("</td></tr></table>", ctx->outstream);
491 if (format && oktext)
493 if (ctx->use_html)
495 es_fputs ("</td><td>", ctx->outstream);
496 if (color)
497 es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
499 else
500 writeout (ctx, ": ");
501 writeout (ctx, oktext);
502 if (color)
503 es_fputs ("</font>", ctx->outstream);
506 if (ctx->use_html)
507 es_fputs ("</td></tr>\n", ctx->outstream);
508 else
509 es_fputc ('\n', ctx->outstream);
513 /* Write a remark line. */
514 static void
515 writeout_rem (audit_ctx_t ctx, const char *format, ...)
517 va_list arg_ptr;
519 if (ctx->use_html)
521 int i;
523 es_fputs (" <tr><td><table><tr><td>*", ctx->outstream);
524 for (i=1; i < ctx->indentlevel; i++)
525 es_fputs ("&nbsp;&nbsp;", ctx->outstream);
526 es_fputs ("&nbsp;&nbsp;&nbsp;</td><td> (", ctx->outstream);
529 else
530 es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
531 if (format)
533 va_start (arg_ptr, format) ;
534 writeout_v (ctx, format, arg_ptr);
535 va_end (arg_ptr);
537 if (ctx->use_html)
538 es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
539 else
540 es_fputs (")\n", ctx->outstream);
544 /* Return the first log item for EVENT. If STOPEVENT is not 0 never
545 look behind that event in the log. If STARTITEM is not NULL start
546 search _after_that item. */
547 static log_item_t
548 find_next_log_item (audit_ctx_t ctx, log_item_t startitem,
549 audit_event_t event, audit_event_t stopevent)
551 int idx;
553 for (idx=0; idx < ctx->logused; idx++)
555 if (startitem)
557 if (ctx->log + idx == startitem)
558 startitem = NULL;
560 else if (stopevent && ctx->log[idx].event == stopevent)
561 break;
562 else if (ctx->log[idx].event == event)
563 return ctx->log + idx;
565 return NULL;
569 static log_item_t
570 find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
572 return find_next_log_item (ctx, NULL, event, stopevent);
576 /* Helper to a format a serial number. */
577 static char *
578 format_serial (ksba_const_sexp_t sn)
580 const char *p = (const char *)sn;
581 unsigned long n;
582 char *endp;
584 if (!p)
585 return NULL;
586 if (*p != '(')
587 BUG (); /* Not a valid S-expression. */
588 n = strtoul (p+1, &endp, 10);
589 p = endp;
590 if (*p != ':')
591 BUG (); /* Not a valid S-expression. */
592 return bin2hex (p+1, n, NULL);
596 /* Return a malloced string with the serial number and the issuer DN
597 of the certificate. */
598 static char *
599 get_cert_name (ksba_cert_t cert)
601 char *result;
602 ksba_sexp_t sn;
603 char *issuer, *p;
605 if (!cert)
606 return xtrystrdup ("[no certificate]");
608 issuer = ksba_cert_get_issuer (cert, 0);
609 sn = ksba_cert_get_serial (cert);
610 if (issuer && sn)
612 p = format_serial (sn);
613 if (!p)
614 result = xtrystrdup ("[invalid S/N]");
615 else
617 result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
618 if (result)
620 *result = '#';
621 strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
623 xfree (p);
626 else
627 result = xtrystrdup ("[missing S/N or issuer]");
628 ksba_free (sn);
629 xfree (issuer);
630 return result;
633 /* Return a malloced string with the serial number and the issuer DN
634 of the certificate. */
635 static char *
636 get_cert_subject (ksba_cert_t cert, int idx)
638 char *result;
639 char *subject;
641 if (!cert)
642 return xtrystrdup ("[no certificate]");
644 subject = ksba_cert_get_subject (cert, idx);
645 if (subject)
647 result = xtrymalloc (strlen (subject) + 1 + 1);
648 if (result)
650 *result = '/';
651 strcpy (result+1, subject);
654 else
655 result = NULL;
656 xfree (subject);
657 return result;
661 /* List the given certificiate. If CERT is NULL, this is a NOP. */
662 static void
663 list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj)
665 char *name;
666 int idx;
668 name = get_cert_name (cert);
669 writeout_rem (ctx, "%s", name);
670 xfree (name);
671 if (with_subj)
673 enter_li (ctx);
674 for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
676 writeout_rem (ctx, "%s", name);
677 xfree (name);
679 leave_li (ctx);
684 /* List the chain of certificates from STARTITEM up to STOPEVENT. The
685 certifcates are written out as comments. */
686 static void
687 list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
689 log_item_t item;
691 startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
692 writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available"));
693 if (!startitem)
694 return;
696 item = find_next_log_item (ctx, startitem,
697 AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
698 if (!item)
699 writeout_rem (ctx, "%s", _("root certificate missing"));
700 else
702 list_cert (ctx, item->cert, 0);
704 item = startitem;
705 while ( ((item = find_next_log_item (ctx, item,
706 AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
708 list_cert (ctx, item->cert, 1);
714 /* Process an encrypt operation's log. */
715 static void
716 proc_type_encrypt (audit_ctx_t ctx)
718 log_item_t loopitem, item;
719 int recp_no, idx;
720 char numbuf[35];
721 int algo;
722 char *name;
724 item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
725 writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
727 enter_li (ctx);
729 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
730 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
732 item = find_log_item (ctx, AUDIT_SESSION_KEY, 0);
733 writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created"));
734 if (item)
736 algo = gcry_cipher_map_name (item->string);
737 if (algo)
738 writeout_rem (ctx, _("algorithm: %s"), gcry_cipher_algo_name (algo));
739 else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2"))
740 writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2");
741 else if (item->string)
742 writeout_rem (ctx, _("unsupported algorithm: %s"), item->string);
743 else
744 writeout_rem (ctx, _("seems to be not encrypted"));
747 item = find_log_item (ctx, AUDIT_GOT_RECIPIENTS, 0);
748 snprintf (numbuf, sizeof numbuf, "%d",
749 item && item->have_intvalue? item->intvalue : 0);
750 writeout_li (ctx, numbuf, "%s", _("Number of recipients"));
752 /* Loop over all recipients. */
753 loopitem = NULL;
754 recp_no = 0;
755 while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0)))
757 recp_no++;
758 writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
759 if (loopitem->cert)
761 name = get_cert_name (loopitem->cert);
762 writeout_rem (ctx, "%s", name);
763 xfree (name);
764 enter_li (ctx);
765 for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++)
767 writeout_rem (ctx, "%s", name);
768 xfree (name);
770 leave_li (ctx);
774 leave_li (ctx);
779 /* Process a sign operation's log. */
780 static void
781 proc_type_sign (audit_ctx_t ctx)
783 log_item_t item;
785 item = NULL;
786 writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
788 enter_li (ctx);
790 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
791 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
794 leave_li (ctx);
799 /* Process a decrypt operation's log. */
800 static void
801 proc_type_decrypt (audit_ctx_t ctx)
803 log_item_t item;
805 item = NULL;
806 writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded"));
808 enter_li (ctx);
810 item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
811 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
814 leave_li (ctx);
819 /* Process a verification operation's log. */
820 static void
821 proc_type_verify (audit_ctx_t ctx)
823 log_item_t loopitem, item;
824 int signo, count, idx;
825 char numbuf[35];
827 /* If there is at least one signature status we claim that the
828 verifciation succeeded. This does not mean that the data has
829 verified okay. */
830 item = find_log_item (ctx, AUDIT_SIG_STATUS, 0);
831 writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded"));
832 enter_li (ctx);
834 item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
835 writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
836 if (!item)
837 goto leave;
839 item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
840 writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
841 if (!item)
842 goto leave;
844 item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
845 writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded"));
846 if (!item)
848 item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG);
849 if (item)
850 writeout_rem (ctx, _("Bad hash algorithm: %s"),
851 item->string? item->string:"?");
853 goto leave;
856 /* Loop over all signatures. */
857 loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
858 assert (loopitem);
861 signo = loopitem->have_intvalue? loopitem->intvalue : -1;
863 item = find_next_log_item (ctx, loopitem,
864 AUDIT_SIG_STATUS, AUDIT_NEW_SIG);
865 writeout_li (ctx, item? item->string:"?", _("Signature %d"), signo);
866 item = find_next_log_item (ctx, loopitem,
867 AUDIT_SIG_NAME, AUDIT_NEW_SIG);
868 if (item)
869 writeout_rem (ctx, "%s", item->string);
870 enter_li (ctx);
872 /* List the certificate chain. */
873 list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
875 /* Show the result of the chain validation. */
876 item = find_next_log_item (ctx, loopitem,
877 AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG);
878 if (item && item->have_err)
880 writeout_li (ctx, item->err? "No":"Yes",
881 _("Certificate chain valid"));
882 if (item->err)
883 writeout_rem (ctx, "%s", gpg_strerror (item->err));
886 /* Show whether the root certificate is fine. */
887 item = find_next_log_item (ctx, loopitem,
888 AUDIT_ROOT_TRUSTED, AUDIT_CHAIN_STATUS);
889 if (item)
891 writeout_li (ctx, item->err?"No":"Yes", "%s",
892 _("Root certificate trustworthy"));
893 if (item->err)
895 add_helptag (ctx, "gpgsm.root-cert-not-trusted");
896 writeout_rem (ctx, "%s", gpg_strerror (item->err));
897 list_cert (ctx, item->cert, 0);
901 /* Show result of the CRL/OCSP check. */
902 writeout_li (ctx, "-", "%s", _("CRL/OCSP check of certificates"));
903 /* add_helptag (ctx, "gpgsm.ocsp-problem"); */
906 leave_li (ctx);
908 while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
911 leave:
912 /* Always list the certificates stored in the signature. */
913 item = NULL;
914 count = 0;
915 while ( ((item = find_next_log_item (ctx, item,
916 AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
917 count++;
918 snprintf (numbuf, sizeof numbuf, "%d", count);
919 writeout_li (ctx, numbuf, _("Included certificates"));
920 item = NULL;
921 while ( ((item = find_next_log_item (ctx, item,
922 AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
924 char *name = get_cert_name (item->cert);
925 writeout_rem (ctx, "%s", name);
926 xfree (name);
927 enter_li (ctx);
928 for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
930 writeout_rem (ctx, "%s", name);
931 xfree (name);
933 leave_li (ctx);
935 leave_li (ctx);
941 /* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
942 void
943 audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
945 int idx;
946 size_t n;
947 log_item_t item;
948 helptag_t helptag;
949 const char *s;
950 int show_raw = 0;
951 char *orig_codeset;
953 if (!ctx)
954 return;
956 orig_codeset = i18n_switchto_utf8 ();
958 /* We use an environment variable to include some debug info in the
959 log. */
960 if ((s = getenv ("gnupg_debug_audit")))
962 show_raw = 1;
963 if (!strcmp (s, "html"))
964 use_html = 1;
967 assert (!ctx->outstream);
968 ctx->outstream = out;
969 ctx->use_html = use_html;
970 ctx->indentlevel = 0;
971 clear_helptags (ctx);
973 if (use_html)
974 es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
976 if (!ctx->log || !ctx->logused)
978 writeout_para (ctx, _("No audit log entries."));
979 goto leave;
982 if (show_raw)
984 int maxlen;
986 for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
988 n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);
989 if (n > maxlen)
990 maxlen = n;
993 if (use_html)
994 es_fputs ("<pre>\n", out);
995 for (idx=0; idx < ctx->logused; idx++)
997 es_fprintf (out, "log: %-*s",
998 maxlen, event2str (ctx->log[idx].event));
999 if (ctx->log[idx].have_intvalue)
1000 es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
1001 if (ctx->log[idx].string)
1003 es_fputs (" s=`", out);
1004 writeout (ctx, ctx->log[idx].string);
1005 es_fputs ("'", out);
1007 if (ctx->log[idx].cert)
1008 es_fprintf (out, " has_cert");
1009 if (ctx->log[idx].have_err)
1011 es_fputs (" err=`", out);
1012 writeout (ctx, gpg_strerror (ctx->log[idx].err));
1013 es_fputs ("'", out);
1015 es_fputs ("\n", out);
1017 if (use_html)
1018 es_fputs ("</pre>\n", out);
1019 else
1020 es_fputs ("\n", out);
1023 enter_li (ctx);
1024 switch (ctx->type)
1026 case AUDIT_TYPE_NONE:
1027 writeout_li (ctx, NULL, _("Unknown operation"));
1028 break;
1029 case AUDIT_TYPE_ENCRYPT:
1030 proc_type_encrypt (ctx);
1031 break;
1032 case AUDIT_TYPE_SIGN:
1033 proc_type_sign (ctx);
1034 break;
1035 case AUDIT_TYPE_DECRYPT:
1036 proc_type_decrypt (ctx);
1037 break;
1038 case AUDIT_TYPE_VERIFY:
1039 proc_type_verify (ctx);
1040 break;
1042 item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
1043 if (item && item->have_err)
1045 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
1046 if (item->err)
1048 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1049 add_helptag (ctx, "gnupg.agent-problem");
1052 item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
1053 if (item && item->have_err)
1055 writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
1056 if (item->err)
1058 writeout_rem (ctx, "%s", gpg_strerror (item->err));
1059 add_helptag (ctx, "gnupg.dirmngr-problem");
1062 leave_li (ctx);
1065 /* Show the help from the collected help tags. */
1066 if (ctx->helptags)
1068 if (use_html)
1070 es_fputs ("<hr/>\n", ctx->outstream);
1071 if (ctx->helptags->next)
1072 es_fputs ("<ul>\n", ctx->outstream);
1074 else
1075 es_fputs ("\n\n", ctx->outstream);
1077 for (helptag = ctx->helptags; helptag; helptag = helptag->next)
1079 char *text;
1081 if (use_html && ctx->helptags->next)
1082 es_fputs ("<li>\n", ctx->outstream);
1084 text = gnupg_get_help_string (helptag->name, 0);
1085 if (text)
1087 writeout_para (ctx, "%s", text);
1088 xfree (text);
1090 else
1091 writeout_para (ctx, _("No help available for `%s'."), helptag->name);
1092 if (use_html && ctx->helptags->next)
1093 es_fputs ("</li>\n", ctx->outstream);
1094 if (helptag->next)
1095 es_fputs ("\n", ctx->outstream);
1097 if (use_html && ctx->helptags && ctx->helptags->next)
1098 es_fputs ("</ul>\n", ctx->outstream);
1100 leave:
1101 if (use_html)
1102 es_fputs ("</div>\n", ctx->outstream);
1103 ctx->outstream = NULL;
1104 ctx->use_html = 0;
1105 clear_helptags (ctx);
1106 i18n_switchback (orig_codeset);