From 5efd3486a9fa9f4b0f383aca2f2f01412e73237c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Tue, 19 Dec 2023 11:26:15 +0100 Subject: [PATCH] core: Support writing the decrypt/verify output directly to a file * src/engine-gpg.c (gpg_decrypt): Pass output file name to gpg if output has file name set. (gpg_verify): Ditto. * tests/run-decrypt.c (show_usage): New option --output. (main): Parse new option. Set file name on output if --output is given. Do not print output if --output is given. * tests/run-verify.c (show_usage): New option --output. (main): Parse new option. Set file name on output if --output is given. -- This change makes it possible to tell gpg to write the output (i.e. the decrypted/verified data) directly to a file with given file name instead of piping the output back to gpgme. GnuPG-bug-id: 6550 --- NEWS | 3 +++ doc/gpgme.texi | 8 ++++++-- src/engine-gpg.c | 21 +++++++++++++++------ tests/run-decrypt.c | 33 ++++++++++++++++++++++++++++----- tests/run-verify.c | 27 +++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index e9e2ed28..b265f3f4 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Noteworthy changes in version 1.23.3 (unrelease) ------------------------------------------------- + * Extended gpgme_op_decrypt* and gpgme_op_verify* to allow writing the + output directly to a file. [T6550] + * Extended gpgme_op_encrypt*, gpgme_op_encrypt_sign*, and gpgme_op_sign* to allow reading the input data directly from a file. [T6550] diff --git a/doc/gpgme.texi b/doc/gpgme.texi index e7a568a3..32bca164 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -5630,7 +5630,9 @@ An error code describing the reason why the key was found invalid. The function @code{gpgme_op_decrypt} decrypts the ciphertext in the data object @var{cipher} or, if a file name is set on the data object, the ciphertext stored in the corresponding file. The decrypted -ciphertext is stored into the data object @var{plain}. +ciphertext is stored into the data object @var{plain} or written to +the file set with @code{gpgme_data_set_file_name} for the data object +@var{plain}. The function returns the error code @code{GPG_ERR_NO_ERROR} if the ciphertext could be decrypted successfully, @code{GPG_ERR_INV_VALUE} @@ -5846,7 +5848,9 @@ writable data object that will contain the plaintext after successful verification. If a file name is set on the data object @var{sig} (or on the data object @var{signed_text}), then the data of the signature (resp. the data of the signed text) is not read from the data object -but from the file with the given file name. +but from the file with the given file name. If a file name is set on +the data object @var{plain} then the plaintext is not stored in the +data object but it is written to a file with the given file name. The results of the individual signature verifications can be retrieved with @code{gpgme_op_verify_result}. diff --git a/src/engine-gpg.c b/src/engine-gpg.c index cc249e7b..6954b596 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1899,12 +1899,18 @@ gpg_decrypt (void *engine, } else { + const char *output = gpgme_data_get_file_name (plain); if (!err) err = add_arg (gpg, "--output"); - if (!err) - err = add_arg (gpg, "-"); - if (!err) - err = add_data (gpg, plain, 1, 1); + if (!err && output) + err = add_arg (gpg, output); + else + { + if (!err) + err = add_arg (gpg, "-"); + if (!err) + err = add_data (gpg, plain, 1, 1); + } if (!err) err = add_input_size_hint (gpg, ciph); if (!err) @@ -3768,9 +3774,12 @@ gpg_verify (void *engine, gpgme_verify_flags_t flags, gpgme_data_t sig, else if (plaintext) { /* Normal or cleartext signature. */ + const char *output = gpgme_data_get_file_name (plaintext); err = add_arg (gpg, "--output"); - if (!err) - err = add_data (gpg, plaintext, -1, 1); + if (!err && output) + err = add_arg (gpg, output); + else if (!err) + err = add_data (gpg, plaintext, -1, 1); if (!err) err = add_input_size_hint (gpg, sig); if (!err) diff --git a/tests/run-decrypt.c b/tests/run-decrypt.c index de082d6f..0e38e0d3 100644 --- a/tests/run-decrypt.c +++ b/tests/run-decrypt.c @@ -91,6 +91,7 @@ show_usage (int ex) " --unwrap remove only the encryption layer\n" " --large-buffers use large I/O buffer\n" " --sensitive mark data objects as sensitive\n" + " --output FILE write output to FILE instead of stdout\n" " --archive extract files from an encrypted archive\n" " --directory DIR extract the files into the directory DIR\n" " --diagnostics print diagnostics\n" @@ -116,6 +117,7 @@ main (int argc, char **argv) int export_session_key = 0; const char *override_session_key = NULL; const char *request_origin = NULL; + const char *output = NULL; const char *directory = NULL; int no_symkey_cache = 0; int ignore_mdc_error = 0; @@ -210,6 +212,14 @@ main (int argc, char **argv) raw_output = 1; argc--; argv++; } + else if (!strcmp (*argv, "--output")) + { + argc--; argv++; + if (!argc) + show_usage (1); + output = *argv; + argc--; argv++; + } else if (!strcmp (*argv, "--archive")) { flags |= GPGME_DECRYPT_ARCHIVE; @@ -341,6 +351,16 @@ main (int argc, char **argv) gpgme_strerror (err)); exit (1); } + if (output && !(flags & GPGME_DECRYPT_ARCHIVE)) + { + err = gpgme_data_set_file_name (out, output); + if (err) + { + fprintf (stderr, PGM ": error setting file name (out): %s\n", + gpgme_strerror (err)); + exit (1); + } + } if (directory && (flags & GPGME_DECRYPT_ARCHIVE)) { err = gpgme_data_set_file_name (out, directory); @@ -407,11 +427,14 @@ main (int argc, char **argv) { if (!raw_output) print_result (result); - if (!raw_output) - fputs ("Begin Output:\n", stdout); - print_data (out); - if (!raw_output) - fputs ("End Output.\n", stdout); + if (!output) + { + if (!raw_output) + fputs ("Begin Output:\n", stdout); + print_data (out); + if (!raw_output) + fputs ("End Output.\n", stdout); + } } gpgme_data_release (out); diff --git a/tests/run-verify.c b/tests/run-verify.c index dba45557..9f32fce9 100644 --- a/tests/run-verify.c +++ b/tests/run-verify.c @@ -236,6 +236,7 @@ show_usage (int ex) " --repeat N repeat the operation N times\n" " --auto-key-retrieve\n" " --auto-key-import\n" + " --output FILE write output to FILE instead of stdout\n" " --archive extract files from a signed archive FILE\n" " --directory DIR extract the files into the directory DIR\n" " --diagnostics print diagnostics\n" @@ -254,6 +255,7 @@ main (int argc, char **argv) gpgme_verify_flags_t flags = 0; int print_status = 0; const char *sender = NULL; + const char *output = NULL; const char *directory = NULL; int auto_key_retrieve = 0; int auto_key_import = 0; @@ -327,6 +329,14 @@ main (int argc, char **argv) auto_key_import = 1; argc--; argv++; } + else if (!strcmp (*argv, "--output")) + { + argc--; argv++; + if (!argc) + show_usage (1); + output = *argv; + argc--; argv++; + } else if (!strcmp (*argv, "--archive")) { flags |= GPGME_VERIFY_ARCHIVE; @@ -484,6 +494,23 @@ main (int argc, char **argv) } } + if (output && !(flags & GPGME_VERIFY_ARCHIVE)) + { + err = gpgme_data_new (&out); + if (err) + { + fprintf (stderr, PGM ": error allocating data object: %s\n", + gpgme_strerror (err)); + exit (1); + } + err = gpgme_data_set_file_name (out, output); + if (err) + { + fprintf (stderr, PGM ": error setting file name (out): %s\n", + gpgme_strerror (err)); + exit (1); + } + } if (directory && (flags & GPGME_VERIFY_ARCHIVE)) { err = gpgme_data_new (&out);