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
int idx = eventstr_msgidxof (event);
120
return "Unknown event";
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. */
134
ctx = xtrycalloc (1, sizeof *ctx);
140
/* Release an audit context. Passing NULL for CTX is allowed and does
143
audit_release (audit_ctx_t ctx)
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);
159
clear_helptags (ctx);
164
/* Set the type for the audit operation. If CTX is NULL, this is a
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";
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
185
create_log_item (audit_ctx_t ctx)
187
log_item_t item, table;
193
table = xtrymalloc (size * sizeof *table);
196
ctx->failure = "Out of memory in create_log_item";
204
else if (ctx->logused >= ctx->logsize)
206
size = ctx->logsize + 10;
207
table = xtryrealloc (ctx->log, size * sizeof *table);
210
ctx->failure = "Out of memory while reallocating in create_log_item";
215
item = ctx->log + ctx->logused++;
218
item = ctx->log + ctx->logused++;
220
item->event = AUDIT_NULL_EVENT;
224
item->have_intvalue = 0;
232
/* Add a new event to the audit log. If CTX is NULL, this function
235
audit_log (audit_ctx_t ctx, audit_event_t event)
239
if (!ctx || ctx->failure)
240
return; /* Audit not enabled or an internal error has occurred. */
243
ctx->failure = "Invalid event passed to audit_log";
246
if (!(item = create_log_item (ctx)))
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
255
audit_log_ok (audit_ctx_t ctx, audit_event_t event, gpg_error_t err)
259
if (!ctx || ctx->failure)
260
return; /* Audit not enabled or an internal error has occurred. */
263
ctx->failure = "Invalid event passed to audit_log_ok";
266
if (!(item = create_log_item (ctx)))
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. */
277
audit_log_i (audit_ctx_t ctx, audit_event_t event, int value)
281
if (!ctx || ctx->failure)
282
return; /* Audit not enabled or an internal error has occurred. */
285
ctx->failure = "Invalid event passed to audit_log_i";
288
if (!(item = create_log_item (ctx)))
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. */
299
audit_log_s (audit_ctx_t ctx, audit_event_t event, const char *value)
304
if (!ctx || ctx->failure)
305
return; /* Audit not enabled or an internal error has occurred. */
308
ctx->failure = "Invalid event passed to audit_log_s";
311
tmp = xtrystrdup (value? value : "");
314
ctx->failure = "Out of memory in audit_event";
317
if (!(item = create_log_item (ctx)))
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. */
330
audit_log_cert (audit_ctx_t ctx, audit_event_t event,
331
ksba_cert_t cert, gpg_error_t err)
335
if (!ctx || ctx->failure)
336
return; /* Audit not enabled or an internal error has occurred. */
339
ctx->failure = "Invalid event passed to audit_log_cert";
342
if (!(item = create_log_item (ctx)))
349
ksba_cert_ref (cert);
355
/* Write TEXT to the outstream. */
357
writeout (audit_ctx_t ctx, const char *text)
361
for (; *text; text++)
364
es_fputs ("<", ctx->outstream);
365
else if (*text == '&')
366
es_fputs ("&", ctx->outstream);
368
es_putc (*text, ctx->outstream);
372
es_fputs (text, ctx->outstream);
376
/* Write TEXT to the outstream using a variable argument list. */
378
writeout_v (audit_ctx_t ctx, const char *format, va_list arg_ptr)
382
estream_vasprintf (&buf, format, arg_ptr);
389
writeout (ctx, "[!!Out of core!!]");
393
/* Write TEXT as a paragraph. */
395
writeout_para (audit_ctx_t ctx, const char *format, ...)
400
es_fputs ("<p>", ctx->outstream);
401
va_start (arg_ptr, format) ;
402
writeout_v (ctx, format, arg_ptr);
405
es_fputs ("</p>\n", ctx->outstream);
407
es_fputc ('\n', ctx->outstream);
412
enter_li (audit_ctx_t ctx)
416
if (!ctx->indentlevel)
418
es_fputs ("<table border=\"0\">\n"
420
" <col width=\"80%\" />\n"
421
" <col width=\"20%\" />\n"
431
leave_li (audit_ctx_t ctx)
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
445
writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...)
448
const char *color = NULL;
450
if (ctx->use_html && format && oktext)
452
if (!strcmp (oktext, "Yes"))
454
else if (!strcmp (oktext, "No"))
462
es_fputs (" <tr><td><table><tr><td>", ctx->outstream);
464
es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
466
es_fputs ("*", ctx->outstream);
467
for (i=1; i < ctx->indentlevel; i++)
468
es_fputs (" ", ctx->outstream);
469
es_fputs ("</td><td>", ctx->outstream);
472
es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
475
va_start (arg_ptr, format) ;
476
writeout_v (ctx, format, arg_ptr);
480
es_fputs ("</td></tr></table>", ctx->outstream);
481
if (format && oktext)
485
es_fputs ("</td><td>", ctx->outstream);
487
es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
490
writeout (ctx, ": ");
491
writeout (ctx, oktext);
493
es_fputs ("</font>", ctx->outstream);
497
es_fputs ("</td></tr>\n", ctx->outstream);
499
es_fputc ('\n', ctx->outstream);
503
/* Write a remark line. */
505
writeout_rem (audit_ctx_t ctx, const char *format, ...)
513
es_fputs (" <tr><td><table><tr><td>*", ctx->outstream);
514
for (i=1; i < ctx->indentlevel; i++)
515
es_fputs (" ", ctx->outstream);
516
es_fputs (" </td><td> (", ctx->outstream);
520
es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
523
va_start (arg_ptr, format) ;
524
writeout_v (ctx, format, arg_ptr);
528
es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
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. */
538
find_next_log_item (audit_ctx_t ctx, log_item_t startitem,
539
audit_event_t event, audit_event_t stopevent)
543
for (idx=0; idx < ctx->logused; idx++)
547
if (ctx->log + idx == startitem)
550
else if (stopevent && ctx->log[idx].event == stopevent)
552
else if (ctx->log[idx].event == event)
553
return ctx->log + idx;
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. */
568
format_serial (ksba_const_sexp_t sn)
570
const char *p = (const char *)sn;
577
BUG (); /* Not a valid S-expression. */
578
n = strtoul (p+1, &endp, 10);
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. */
589
get_cert_name (ksba_cert_t cert)
596
return xtrystrdup ("[no certificate]");
598
issuer = ksba_cert_get_issuer (cert, 0);
599
sn = ksba_cert_get_serial (cert);
602
p = format_serial (sn);
604
result = xtrystrdup ("[invalid S/N]");
607
result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
611
strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
617
result = xtrystrdup ("[missing S/N or issuer]");
623
/* Return a malloced string with the serial number and the issuer DN
624
of the certificate. */
626
get_cert_subject (ksba_cert_t cert, int idx)
632
return xtrystrdup ("[no certificate]");
634
subject = ksba_cert_get_subject (cert, idx);
637
result = xtrymalloc (strlen (subject) + 1 + 1);
641
strcpy (result+1, subject);
651
/* List the given certificiate. If CERT is NULL, this is a NOP. */
653
list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj)
658
name = get_cert_name (cert);
659
writeout_rem (ctx, "%s", name);
664
for (idx=0; (name = get_cert_subject (cert, idx)); idx++)
666
writeout_rem (ctx, "%s", name);
674
/* List the chain of certificates from STARTITEM up to STOPEVENT. The
675
certifcates are written out as comments. */
677
list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
681
startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
682
writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available"));
686
item = find_next_log_item (ctx, startitem,
687
AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
689
writeout_rem (ctx, "%s", _("root certificate missing"));
692
list_cert (ctx, item->cert, 0);
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. */
706
proc_type_encrypt (audit_ctx_t ctx)
708
log_item_t loopitem, item;
714
item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0);
715
writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption succeeded"));
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"));
726
algo = gcry_cipher_map_name (item->string);
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);
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. */
745
while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0)))
748
writeout_li (ctx, NULL, _("Recipient %d"), recp_no);
751
name = get_cert_name (loopitem->cert);
752
writeout_rem (ctx, "%s", name);
755
for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++)
757
writeout_rem (ctx, "%s", name);
769
/* Process a sign operation's log. */
771
proc_type_sign (audit_ctx_t ctx)
776
writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded"));
780
item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
781
writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
789
/* Process a decrypt operation's log. */
791
proc_type_decrypt (audit_ctx_t ctx)
796
writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded"));
800
item = find_log_item (ctx, AUDIT_GOT_DATA, 0);
801
writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
809
/* Process a verification operation's log. */
811
proc_type_verify (audit_ctx_t ctx)
813
log_item_t loopitem, item;
814
int signo, count, idx;
817
/* If there is at least one signature status we claim that the
818
verifciation succeeded. This does not mean that the data has
820
item = find_log_item (ctx, AUDIT_SIG_STATUS, 0);
821
writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded"));
824
item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
825
writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
829
item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
830
writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
834
item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
835
writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded"));
838
item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG);
840
writeout_rem (ctx, _("Bad hash algorithm: %s"),
841
item->string? item->string:"?");
846
/* Loop over all signatures. */
847
loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
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);
859
writeout_rem (ctx, "%s", item->string);
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"));
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);
881
writeout_li (ctx, item->err?"No":"Yes", "%s",
882
_("Root certificate trustworthy"));
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"); */
898
while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
902
/* Always list the certificates stored in the signature. */
905
while ( ((item = find_next_log_item (ctx, item,
906
AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
908
snprintf (numbuf, sizeof numbuf, "%d", count);
909
writeout_li (ctx, numbuf, _("Included certificates"));
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);
918
for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
920
writeout_rem (ctx, "%s", name);
931
/* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
933
audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
946
orig_codeset = i18n_switchto_utf8 ();
948
/* We use an environment variable to include some debug info in the
950
if ((s = getenv ("gnupg_debug_audit")))
953
if (!strcmp (s, "html"))
957
assert (!ctx->outstream);
958
ctx->outstream = out;
959
ctx->use_html = use_html;
960
ctx->indentlevel = 0;
961
clear_helptags (ctx);
964
es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
966
if (!ctx->log || !ctx->logused)
968
writeout_para (ctx, _("No audit log entries."));
976
for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++)
978
n = strlen (eventstr_msgstr + eventstr_msgidx[idx]);
984
es_fputs ("<pre>\n", out);
985
for (idx=0; idx < ctx->logused; idx++)
987
es_fprintf (out, "log: %-*s",
988
maxlen, event2str (ctx->log[idx].event));
989
if (ctx->log[idx].have_intvalue)
990
es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
991
if (ctx->log[idx].string)
993
es_fputs (" s=`", out);
994
writeout (ctx, ctx->log[idx].string);
997
if (ctx->log[idx].cert)
998
es_fprintf (out, " has_cert");
999
if (ctx->log[idx].have_err)
1001
es_fputs (" err=`", out);
1002
writeout (ctx, gpg_strerror (ctx->log[idx].err));
1003
es_fputs ("'", out);
1005
es_fputs ("\n", out);
1008
es_fputs ("</pre>\n", out);
1010
es_fputs ("\n", out);
1016
case AUDIT_TYPE_NONE:
1017
writeout_li (ctx, NULL, _("Unknown operation"));
1019
case AUDIT_TYPE_ENCRYPT:
1020
proc_type_encrypt (ctx);
1022
case AUDIT_TYPE_SIGN:
1023
proc_type_sign (ctx);
1025
case AUDIT_TYPE_DECRYPT:
1026
proc_type_decrypt (ctx);
1028
case AUDIT_TYPE_VERIFY:
1029
proc_type_verify (ctx);
1032
item = find_log_item (ctx, AUDIT_AGENT_READY, 0);
1033
if (item && item->have_err)
1035
writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable"));
1038
writeout_rem (ctx, "%s", gpg_strerror (item->err));
1039
add_helptag (ctx, "gnupg.agent-problem");
1042
item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0);
1043
if (item && item->have_err)
1045
writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable"));
1048
writeout_rem (ctx, "%s", gpg_strerror (item->err));
1049
add_helptag (ctx, "gnupg.dirmngr-problem");
1055
/* Show the help from the collected help tags. */
1060
es_fputs ("<hr/>\n", ctx->outstream);
1061
if (ctx->helptags->next)
1062
es_fputs ("<ul>\n", ctx->outstream);
1065
es_fputs ("\n\n", ctx->outstream);
1067
for (helptag = ctx->helptags; helptag; helptag = helptag->next)
1071
if (use_html && ctx->helptags->next)
1072
es_fputs ("<li>\n", ctx->outstream);
1074
text = gnupg_get_help_string (helptag->name, 0);
1077
writeout_para (ctx, "%s", text);
1081
writeout_para (ctx, _("No help available for `%s'."), helptag->name);
1082
if (use_html && ctx->helptags->next)
1083
es_fputs ("</li>\n", ctx->outstream);
1085
es_fputs ("\n", ctx->outstream);
1087
if (use_html && ctx->helptags && ctx->helptags->next)
1088
es_fputs ("</ul>\n", ctx->outstream);
1092
es_fputs ("</div>\n", ctx->outstream);
1093
ctx->outstream = NULL;
1095
clear_helptags (ctx);
1096
i18n_switchback (orig_codeset);