diff --git a/NEWS b/NEWS index 6c33c258..9c641100 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ Noteworthy changes in version 1.11.2 (unreleased) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_decrypt_result_t EXTENDED: New field legacy_cipher_nomdc. gpgme_set_ctx_flag EXTENDED: New flag 'ignore-mdc-error'. + GPGME_AUDITLOG_DEFAULT NEW. + GPGME_AUDITLOG_DIAG NEW. cpp: DecryptionResult::sessionKey NEW. cpp: DecryptionResult::symkeyAlgo NEW. cpp: DecryptionResult::isLegacyCipherNoMDC New. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index e3445a0e..3dac60d0 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2426,6 +2426,7 @@ started. In fact, these references are accessed through the * Progress Meter Callback:: Being informed about the progress. * Status Message Callback:: Status messages received from gpg. * Locale:: Setting the locale of a context. +* Additional Logs:: Additional logs of a context. @end menu @@ -3155,6 +3156,70 @@ The function returns an error if not enough memory is available. @end deftypefun +@node Additional Logs +@subsection Additional Logs +@cindex auditlog, of the engine +@cindex auditlog + +Additional logs can be associated with a context. These logs are +engine specific and can be be obtained with @code{gpgme_op_getauditlog}. + +@deftypefun gpgme_error_t gpgme_op_getauditlog @ + (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{output}}, @ + @w{unsigned int @var{flags}}) +@since{1.1.1} + +The function @code{gpgme_op_getauditlog} is used to obtain additional +logs as specified by @var{flags} into the @var{output} data. If + +The function returns the error code @code{GPG_ERR_NO_ERROR} if a +log could be queried from the engine, and @code{GPG_ERR_NOT_IMPLEMENTED} +if the log specified in @var{flags} is not available for this engine. +If no log is available @code{GPG_ERR_NO_DATA} is returned. + +The value in @var{flags} is a bitwise-or combination of one or +multiple of the following bit values: + +@table @code +@item GPGME_AUDITLOG_DIAG +@since{1.11.2} + +Obtain diagnostic output which would be written to @code{stderr} in +interactive use of the engine. This can be used to provide additional +diagnostic information in case of errors in other operations. + +Note: If log-file has been set in the configuration the log will +be empty and @code{GPG_ERR_NO_DATA} will be returned. + +Implemented for: @code{GPGME_PROTOCOL_OpenPGP} + +@item GPGME_AUDITLOG_DEFAULT +@since{1.11.2} + +This flag has the value 0 for compatibility reasons. Obtains additional +information from the engine by issuing the @code{GETAUDITLOG} command. +For @code{GPGME_PROTOCOL_CMS} this provides additional information about +the X509 certificate chain. + +Implemented for: @code{GPGME_PROTOCOL_CMS} + +@item GPGME_AUDITLOG_HTML +@since{1.1.1} + +Same as @code{GPGME_AUDITLOG_DEFAULT} but in HTML. + +Implemented for: @code{GPGME_PROTOCOL_CMS} +@end table +@end deftypefun + +@deftypefun gpgme_error_t gpgme_op_getauditlog_start @ + (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{output}}, @ + @w{unsigned int @var{flags}}) +@since{1.1.1} + +This is the asynchronous variant of @code{gpgme_op_getauditlog}. +@end deftypefun + @node Key Management @section Key Management @cindex key management diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 802af08d..f096bcbf 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -149,6 +149,9 @@ struct engine_gpg /* NULL or the data object fed to --override_session_key-fd. */ gpgme_data_t override_session_key; + + /* Memory data containing diagnostics (--logger-fd) of gpg */ + gpgme_data_t diagnostics; }; typedef struct engine_gpg *engine_gpg_t; @@ -452,6 +455,7 @@ gpg_release (void *engine) free (gpg->cmd.keyword); gpgme_data_release (gpg->override_session_key); + gpgme_data_release (gpg->diagnostics); free (gpg); } @@ -620,6 +624,16 @@ gpg_new (void **engine, const char *file_name, const char *home_dir, } } + rc = gpgme_data_new (&gpg->diagnostics); + if (rc) + goto leave; + + rc = add_arg (gpg, "--logger-fd"); + if (rc) + goto leave; + + rc = add_data (gpg, gpg->diagnostics, -2, 1); + leave: if (rc) gpg_release (gpg); @@ -3243,6 +3257,52 @@ gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode) } +static gpgme_error_t +gpg_getauditlog (void *engine, gpgme_data_t output, unsigned int flags) +{ + engine_gpg_t gpg = engine; +#define MYBUFLEN 4096 + char buf[MYBUFLEN]; + int nread; + int any_written = 0; + + if (!(flags & GPGME_AUDITLOG_DIAG)) + { + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + } + + if (!gpg || !output) + { + return gpg_error (GPG_ERR_INV_VALUE); + } + + if (!gpg->diagnostics) + { + return gpg_error (GPG_ERR_GENERAL); + } + + gpgme_data_rewind (gpg->diagnostics); + + while ((nread = gpgme_data_read (gpg->diagnostics, buf, MYBUFLEN)) > 0) + { + any_written = 1; + if (gpgme_data_write (output, buf, nread) == -1) + return gpg_error_from_syserror (); + } + if (!any_written) + { + return gpg_error (GPG_ERR_NO_DATA); + } + + if (nread == -1) + return gpg_error_from_syserror (); + + gpgme_data_rewind (output); + return 0; +#undef MYBUFLEN +} + + struct engine_ops _gpgme_engine_ops_gpg = { @@ -3280,7 +3340,7 @@ struct engine_ops _gpgme_engine_ops_gpg = gpg_sign, gpg_trustlist, gpg_verify, - NULL, /* getauditlog */ + gpg_getauditlog, NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 84a9315d..3266e360 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -2064,6 +2064,9 @@ gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags) if (!gpgsm || !output) return gpg_error (GPG_ERR_INV_VALUE); + if ((flags & GPGME_AUDITLOG_DIAG)) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + #if USE_DESCRIPTOR_PASSING gpgsm->output_cb.data = output; err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0); diff --git a/src/getauditlog.c b/src/getauditlog.c index dbaf260e..d70e66fd 100644 --- a/src/getauditlog.c +++ b/src/getauditlog.c @@ -47,9 +47,12 @@ getauditlog_start (gpgme_ctx_t ctx, int synchronous, if (!output) return gpg_error (GPG_ERR_INV_VALUE); - err = _gpgme_op_reset (ctx, ((synchronous&255) | 256) ); - if (err) - return err; + if (!(flags & GPGME_AUDITLOG_DIAG)) + { + err = _gpgme_op_reset (ctx, ((synchronous&255) | 256) ); + if (err) + return err; + } _gpgme_engine_set_status_handler (ctx->engine, getauditlog_status_handler, ctx); diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 5279f6a2..421199a9 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -404,7 +404,9 @@ typedef unsigned int gpgme_export_mode_t; /* Flags for the audit log functions. */ +#define GPGME_AUDITLOG_DEFAULT 0 #define GPGME_AUDITLOG_HTML 1 +#define GPGME_AUDITLOG_DIAG 2 #define GPGME_AUDITLOG_WITH_HELP 128 diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index 99a15c7e..c9d9e72d 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -88,6 +88,7 @@ show_usage (int ex) " --no-symkey-cache disable the use of that cache\n" " --ignore-mdc-error allow decryption of legacy data\n" " --unwrap remove only the encryption layer\n" + " --diagnostics print diagnostics\n" , stderr); exit (ex); } @@ -112,6 +113,7 @@ main (int argc, char **argv) int no_symkey_cache = 0; int ignore_mdc_error = 0; int raw_output = 0; + int diagnostics = 0; if (argc) { argc--; argv++; } @@ -177,6 +179,11 @@ main (int argc, char **argv) ignore_mdc_error = 1; argc--; argv++; } + else if (!strcmp (*argv, "--diagnostics")) + { + diagnostics = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--unwrap")) { flags |= GPGME_DECRYPT_UNWRAP; @@ -283,6 +290,28 @@ main (int argc, char **argv) err = gpgme_op_decrypt_ext (ctx, flags, in, out); result = gpgme_op_decrypt_result (ctx); + + if (diagnostics) + { + gpgme_data_t diag; + gpgme_error_t diag_err; + + gpgme_data_new (&diag); + diag_err = gpgme_op_getauditlog (ctx, diag, GPGME_AUDITLOG_DIAG); + if (diag_err) + { + fprintf (stderr, PGM ": getting diagnostics failed: %s\n", + gpgme_strerror (diag_err)); + } + else + { + fputs ("Begin Diagnostics:\n", stdout); + print_data (diag); + fputs ("End Diagnostics.\n", stdout); + } + gpgme_data_release (diag); + } + if (err) { fprintf (stderr, PGM ": decrypt failed: %s\n", gpgme_strerror (err));