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/>.
29 #include "audit-events.h"
31 /* A list to maintain a list of helptags. */
34 struct helptag_s
*next
;
37 typedef struct helptag_s
*helptag_t
;
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. */
51 typedef struct log_item_s
*log_item_t
;
55 /* The main audit object. */
58 const char *failure
; /* If set a description of the internal failure. */
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. */
85 add_helptag (audit_ctx_t ctx
, const char *name
)
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
);
94 return; /* Don't care about memory problems. */
96 item
->next
= ctx
->helptags
;
101 /* Remove all help tags from the context. */
103 clear_helptags (audit_ctx_t ctx
)
105 while (ctx
->helptags
)
107 helptag_t tmp
= ctx
->helptags
->next
;
108 xfree (ctx
->helptags
);
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
);
122 return "Unknown event";
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. */
136 ctx
= xtrycalloc (1, sizeof *ctx
);
142 /* Release an audit context. Passing NULL for CTX is allowed and does
145 audit_release (audit_ctx_t ctx
)
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
);
161 clear_helptags (ctx
);
166 /* Set the type for the audit operation. If CTX is NULL, this is a
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";
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
187 create_log_item (audit_ctx_t ctx
)
189 log_item_t item
, table
;
195 table
= xtrymalloc (size
* sizeof *table
);
198 ctx
->failure
= "Out of memory in create_log_item";
206 else if (ctx
->logused
>= ctx
->logsize
)
208 size
= ctx
->logsize
+ 10;
209 table
= xtryrealloc (ctx
->log
, size
* sizeof *table
);
212 ctx
->failure
= "Out of memory while reallocating in create_log_item";
217 item
= ctx
->log
+ ctx
->logused
++;
220 item
= ctx
->log
+ ctx
->logused
++;
222 item
->event
= AUDIT_NULL_EVENT
;
226 item
->have_intvalue
= 0;
234 /* Add a new event to the audit log. If CTX is NULL, this function
237 audit_log (audit_ctx_t ctx
, audit_event_t event
)
241 if (!ctx
|| ctx
->failure
)
242 return; /* Audit not enabled or an internal error has occurred. */
245 ctx
->failure
= "Invalid event passed to audit_log";
248 if (!(item
= create_log_item (ctx
)))
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
257 audit_log_ok (audit_ctx_t ctx
, audit_event_t event
, gpg_error_t err
)
261 if (!ctx
|| ctx
->failure
)
262 return; /* Audit not enabled or an internal error has occurred. */
265 ctx
->failure
= "Invalid event passed to audit_log_ok";
268 if (!(item
= create_log_item (ctx
)))
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. */
279 audit_log_i (audit_ctx_t ctx
, audit_event_t event
, int value
)
283 if (!ctx
|| ctx
->failure
)
284 return; /* Audit not enabled or an internal error has occurred. */
287 ctx
->failure
= "Invalid event passed to audit_log_i";
290 if (!(item
= create_log_item (ctx
)))
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. */
301 audit_log_s (audit_ctx_t ctx
, audit_event_t event
, const char *value
)
306 if (!ctx
|| ctx
->failure
)
307 return; /* Audit not enabled or an internal error has occurred. */
310 ctx
->failure
= "Invalid event passed to audit_log_s";
313 tmp
= xtrystrdup (value
? value
: "");
316 ctx
->failure
= "Out of memory in audit_event";
319 if (!(item
= create_log_item (ctx
)))
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. */
332 audit_log_cert (audit_ctx_t ctx
, audit_event_t event
,
333 ksba_cert_t cert
, gpg_error_t err
)
337 if (!ctx
|| ctx
->failure
)
338 return; /* Audit not enabled or an internal error has occurred. */
341 ctx
->failure
= "Invalid event passed to audit_log_cert";
344 if (!(item
= create_log_item (ctx
)))
351 ksba_cert_ref (cert
);
357 /* Write TEXT to the outstream. */
359 writeout (audit_ctx_t ctx
, const char *text
)
363 for (; *text
; text
++)
366 es_fputs ("<", ctx
->outstream
);
367 else if (*text
== '&')
368 es_fputs ("&", ctx
->outstream
);
370 es_putc (*text
, ctx
->outstream
);
374 es_fputs (text
, ctx
->outstream
);
378 /* Write TEXT to the outstream using a variable argument list. */
380 writeout_v (audit_ctx_t ctx
, const char *format
, va_list arg_ptr
)
384 estream_vasprintf (&buf
, format
, arg_ptr
);
391 writeout (ctx
, "[!!Out of core!!]");
395 /* Write TEXT as a paragraph. */
397 writeout_para (audit_ctx_t ctx
, const char *format
, ...)
402 es_fputs ("<p>", ctx
->outstream
);
403 va_start (arg_ptr
, format
) ;
404 writeout_v (ctx
, format
, arg_ptr
);
407 es_fputs ("</p>\n", ctx
->outstream
);
409 es_fputc ('\n', ctx
->outstream
);
414 enter_li (audit_ctx_t ctx
)
418 if (!ctx
->indentlevel
)
420 es_fputs ("<table border=\"0\">\n"
422 " <col width=\"80%\" />\n"
423 " <col width=\"20%\" />\n"
433 leave_li (audit_ctx_t ctx
)
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
447 writeout_li (audit_ctx_t ctx
, const char *oktext
, const char *format
, ...)
450 const char *color
= NULL
;
452 if (ctx
->use_html
&& format
&& oktext
)
454 if (!strcmp (oktext
, "Yes")
455 || !strcmp (oktext
, "good") )
457 else if (!strcmp (oktext
, "No")
458 || !strcmp (oktext
, "bad") )
462 if (format
&& oktext
)
464 const char *s
= NULL
;
466 if (!strcmp (oktext
, "Yes"))
468 else if (!strcmp (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");
487 /* If we have set a prefix, skip it. */
488 if (!s
&& *oktext
== '|' && (s
=strchr (oktext
+1,'|')))
496 es_fputs (" <tr><td><table><tr><td>", ctx
->outstream
);
498 es_fprintf (ctx
->outstream
, "<font color=\"%s\">*</font>", color
);
500 es_fputs ("*", ctx
->outstream
);
501 for (i
=1; i
< ctx
->indentlevel
; i
++)
502 es_fputs (" ", ctx
->outstream
);
503 es_fputs ("</td><td>", ctx
->outstream
);
506 es_fprintf (ctx
->outstream
, "* %*s", (ctx
->indentlevel
-1)*2, "");
509 va_start (arg_ptr
, format
) ;
510 writeout_v (ctx
, format
, arg_ptr
);
514 es_fputs ("</td></tr></table>", ctx
->outstream
);
515 if (format
&& oktext
)
519 es_fputs ("</td><td>", ctx
->outstream
);
521 es_fprintf (ctx
->outstream
, "<font color=\"%s\">", color
);
524 writeout (ctx
, ": ");
525 writeout (ctx
, oktext
);
527 es_fputs ("</font>", ctx
->outstream
);
531 es_fputs ("</td></tr>\n", ctx
->outstream
);
533 es_fputc ('\n', ctx
->outstream
);
537 /* Write a remark line. */
539 writeout_rem (audit_ctx_t ctx
, const char *format
, ...)
547 es_fputs (" <tr><td><table><tr><td>*", ctx
->outstream
);
548 for (i
=1; i
< ctx
->indentlevel
; i
++)
549 es_fputs (" ", ctx
->outstream
);
550 es_fputs (" </td><td> (", ctx
->outstream
);
554 es_fprintf (ctx
->outstream
, "* %*s (", (ctx
->indentlevel
-1)*2, "");
557 va_start (arg_ptr
, format
) ;
558 writeout_v (ctx
, format
, arg_ptr
);
562 es_fputs (")</td></tr></table></td></tr>\n", ctx
->outstream
);
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. */
572 find_next_log_item (audit_ctx_t ctx
, log_item_t startitem
,
573 audit_event_t event
, audit_event_t stopevent
)
577 for (idx
=0; idx
< ctx
->logused
; idx
++)
581 if (ctx
->log
+ idx
== startitem
)
584 else if (stopevent
&& ctx
->log
[idx
].event
== stopevent
)
586 else if (ctx
->log
[idx
].event
== event
)
587 return ctx
->log
+ idx
;
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. */
602 format_serial (ksba_const_sexp_t sn
)
604 const char *p
= (const char *)sn
;
611 BUG (); /* Not a valid S-expression. */
612 n
= strtoul (p
+1, &endp
, 10);
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. */
623 get_cert_name (ksba_cert_t cert
)
630 return xtrystrdup ("[no certificate]");
632 issuer
= ksba_cert_get_issuer (cert
, 0);
633 sn
= ksba_cert_get_serial (cert
);
636 p
= format_serial (sn
);
638 result
= xtrystrdup ("[invalid S/N]");
641 result
= xtrymalloc (strlen (p
) + strlen (issuer
) + 2 + 1);
645 strcpy (stpcpy (stpcpy (result
+1, p
),"/"), issuer
);
651 result
= xtrystrdup ("[missing S/N or issuer]");
657 /* Return a malloced string with the serial number and the issuer DN
658 of the certificate. */
660 get_cert_subject (ksba_cert_t cert
, int idx
)
666 return xtrystrdup ("[no certificate]");
668 subject
= ksba_cert_get_subject (cert
, idx
);
671 result
= xtrymalloc (strlen (subject
) + 1 + 1);
675 strcpy (result
+1, subject
);
685 /* List the given certificiate. If CERT is NULL, this is a NOP. */
687 list_cert (audit_ctx_t ctx
, ksba_cert_t cert
, int with_subj
)
692 name
= get_cert_name (cert
);
693 writeout_rem (ctx
, "%s", name
);
698 for (idx
=0; (name
= get_cert_subject (cert
, idx
)); idx
++)
700 writeout_rem (ctx
, "%s", name
);
708 /* List the chain of certificates from STARTITEM up to STOPEVENT. The
709 certifcates are written out as comments. */
711 list_certchain (audit_ctx_t ctx
, log_item_t startitem
, audit_event_t stopevent
)
715 startitem
= find_next_log_item (ctx
, startitem
, AUDIT_CHAIN_BEGIN
,stopevent
);
716 writeout_li (ctx
, startitem
? "Yes":"No", _("Certificate chain available"));
720 item
= find_next_log_item (ctx
, startitem
,
721 AUDIT_CHAIN_ROOTCERT
, AUDIT_CHAIN_END
);
723 writeout_rem (ctx
, "%s", _("root certificate missing"));
726 list_cert (ctx
, item
->cert
, 0);
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. */
740 proc_type_encrypt (audit_ctx_t ctx
)
742 log_item_t loopitem
, item
;
748 item
= find_log_item (ctx
, AUDIT_ENCRYPTION_DONE
, 0);
749 writeout_li (ctx
, item
?"Yes":"No", "%s", _("Data encryption succeeded"));
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"));
760 algo
= gcry_cipher_map_name (item
->string
);
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
);
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. */
779 while ((loopitem
=find_next_log_item (ctx
, loopitem
, AUDIT_ENCRYPTED_TO
, 0)))
782 writeout_li (ctx
, NULL
, _("Recipient %d"), recp_no
);
785 name
= get_cert_name (loopitem
->cert
);
786 writeout_rem (ctx
, "%s", name
);
789 for (idx
=0; (name
= get_cert_subject (loopitem
->cert
, idx
)); idx
++)
791 writeout_rem (ctx
, "%s", name
);
803 /* Process a sign operation's log. */
805 proc_type_sign (audit_ctx_t ctx
)
810 writeout_li (ctx
, item
?"Yes":"No", "%s", _("Data signing succeeded"));
814 item
= find_log_item (ctx
, AUDIT_GOT_DATA
, 0);
815 writeout_li (ctx
, item
? "Yes":"No", "%s", _("Data available"));
823 /* Process a decrypt operation's log. */
825 proc_type_decrypt (audit_ctx_t ctx
)
830 writeout_li (ctx
, item
?"Yes":"No", "%s", _("Data decryption succeeded"));
834 item
= find_log_item (ctx
, AUDIT_GOT_DATA
, 0);
835 writeout_li (ctx
, item
? "Yes":"No", "%s", _("Data available"));
843 /* Process a verification operation's log. */
845 proc_type_verify (audit_ctx_t ctx
)
847 log_item_t loopitem
, item
;
848 int signo
, count
, idx
;
851 /* If there is at least one signature status we claim that the
852 verifciation succeeded. This does not mean that the data has
854 item
= find_log_item (ctx
, AUDIT_SIG_STATUS
, 0);
855 writeout_li (ctx
, item
?"Yes":"No", "%s", _("Data verification succeeded"));
858 item
= find_log_item (ctx
, AUDIT_GOT_DATA
, AUDIT_NEW_SIG
);
859 writeout_li (ctx
, item
? "Yes":"No", "%s", _("Data available"));
863 item
= find_log_item (ctx
, AUDIT_NEW_SIG
, 0);
864 writeout_li (ctx
, item
? "Yes":"No", "%s", _("Signature available"));
868 item
= find_log_item (ctx
, AUDIT_DATA_HASH_ALGO
, AUDIT_NEW_SIG
);
869 writeout_li (ctx
, item
?"Yes":"No", "%s", _("Parsing signature succeeded"));
872 item
= find_log_item (ctx
, AUDIT_BAD_DATA_HASH_ALGO
, AUDIT_NEW_SIG
);
874 writeout_rem (ctx
, _("Bad hash algorithm: %s"),
875 item
->string
? item
->string
:"?");
880 /* Loop over all signatures. */
881 loopitem
= find_log_item (ctx
, AUDIT_NEW_SIG
, 0);
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
);
893 writeout_rem (ctx
, "%s", item
->string
);
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"));
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
);
915 writeout_li (ctx
, item
->err
?"No":"Yes", "%s",
916 _("Root certificate trustworthy"));
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"); */
932 while ((loopitem
= find_next_log_item (ctx
, loopitem
, AUDIT_NEW_SIG
, 0)));
936 /* Always list the certificates stored in the signature. */
939 while ( ((item
= find_next_log_item (ctx
, item
,
940 AUDIT_SAVE_CERT
, AUDIT_NEW_SIG
))))
942 snprintf (numbuf
, sizeof numbuf
, "%d", count
);
943 writeout_li (ctx
, numbuf
, _("Included certificates"));
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
);
952 for (idx
=0; (name
= get_cert_subject (item
->cert
, idx
)); idx
++)
954 writeout_rem (ctx
, "%s", name
);
965 /* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
967 audit_print_result (audit_ctx_t ctx
, estream_t out
, int use_html
)
980 orig_codeset
= i18n_switchto_utf8 ();
982 /* We use an environment variable to include some debug info in the
984 if ((s
= getenv ("gnupg_debug_audit")))
987 if (!strcmp (s
, "html"))
991 assert (!ctx
->outstream
);
992 ctx
->outstream
= out
;
993 ctx
->use_html
= use_html
;
994 ctx
->indentlevel
= 0;
995 clear_helptags (ctx
);
998 es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx
->outstream
);
1000 if (!ctx
->log
|| !ctx
->logused
)
1002 writeout_para (ctx
, _("No audit log entries."));
1010 for (idx
=0,maxlen
=0; idx
< DIM (eventstr_msgidx
); idx
++)
1012 n
= strlen (eventstr_msgstr
+ eventstr_msgidx
[idx
]);
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
);
1042 es_fputs ("</pre>\n", out
);
1044 es_fputs ("\n", out
);
1050 case AUDIT_TYPE_NONE
:
1051 writeout_li (ctx
, NULL
, _("Unknown operation"));
1053 case AUDIT_TYPE_ENCRYPT
:
1054 proc_type_encrypt (ctx
);
1056 case AUDIT_TYPE_SIGN
:
1057 proc_type_sign (ctx
);
1059 case AUDIT_TYPE_DECRYPT
:
1060 proc_type_decrypt (ctx
);
1062 case AUDIT_TYPE_VERIFY
:
1063 proc_type_verify (ctx
);
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"));
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"));
1082 writeout_rem (ctx
, "%s", gpg_strerror (item
->err
));
1083 add_helptag (ctx
, "gnupg.dirmngr-problem");
1089 /* Show the help from the collected help tags. */
1094 es_fputs ("<hr/>\n", ctx
->outstream
);
1095 if (ctx
->helptags
->next
)
1096 es_fputs ("<ul>\n", ctx
->outstream
);
1099 es_fputs ("\n\n", ctx
->outstream
);
1101 for (helptag
= ctx
->helptags
; helptag
; helptag
= helptag
->next
)
1105 if (use_html
&& ctx
->helptags
->next
)
1106 es_fputs ("<li>\n", ctx
->outstream
);
1108 text
= gnupg_get_help_string (helptag
->name
, 0);
1111 writeout_para (ctx
, "%s", text
);
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
);
1119 es_fputs ("\n", ctx
->outstream
);
1121 if (use_html
&& ctx
->helptags
&& ctx
->helptags
->next
)
1122 es_fputs ("</ul>\n", ctx
->outstream
);
1126 es_fputs ("</div>\n", ctx
->outstream
);
1127 ctx
->outstream
= NULL
;
1129 clear_helptags (ctx
);
1130 i18n_switchback (orig_codeset
);