Index: b/g10/decrypt-data.c =================================================================== --- b/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -221,7 +221,38 @@ else iobuf_push_filter ( ed->buf, decode_filter, dfx ); - proc_packets (ctrl, procctx, ed->buf ); + if (opt.unwrap_encryption) + { + char *filename; + estream_t fp; + rc = get_output_file ("", 0, ed->buf, &filename, &fp); + if (! rc) + { + iobuf_t output = iobuf_esopen (fp, "w", 0); + armor_filter_context_t *afx = NULL; + + if (opt.armor) + { + afx = new_armor_context (); + push_armor_filter (afx, output); + } + + iobuf_copy (output, ed->buf); + if ((rc = iobuf_error (ed->buf))) + log_error (_("error reading: %s\n"), + filename, gpg_strerror (rc)); + else if ((rc = iobuf_error (output))) + log_error (_("error writing output ('%s'): %s\n"), + filename, gpg_strerror (rc)); + + iobuf_close (output); + if (afx) + release_armor_context (afx); + } + } + else + proc_packets (ctrl, procctx, ed->buf ); + ed->buf = NULL; if (dfx->eof_seen > 1 ) rc = gpg_error (GPG_ERR_INV_PACKET); @@ -249,15 +280,14 @@ gcry_md_final (dfx->mdc_hash); if ( dfx->defer[0] != '\xd3' - || dfx->defer[1] != '\x14' - || datalen != 20 - || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen)) + || dfx->defer[1] != '\x14' + || datalen != 20 + || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen)) rc = gpg_error (GPG_ERR_BAD_SIGNATURE); /* log_printhex("MDC message:", dfx->defer, 22); */ /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */ } - leave: release_dfx_context (dfx); return rc; Index: b/g10/gpg.c =================================================================== --- b/g10/gpg.c +++ b/g10/gpg.c @@ -391,6 +391,7 @@ oTOFUDefaultPolicy, oTOFUDBFormat, oWeakDigest, + oUnwrap, oNoop }; @@ -753,6 +754,7 @@ "personal-compress-preferences", "@"), ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"), ARGPARSE_s_s (oWeakDigest, "weak-digest","@"), + ARGPARSE_s_n (oUnwrap, "unwrap", "@"), /* Aliases. I constantly mistype these, and assume other people do as well. */ @@ -3147,6 +3149,9 @@ case oWeakDigest: additional_weak_digest(pargs.r.ret_str); break; + case oUnwrap: + opt.unwrap_encryption = 1; + break; case oDisplay: set_opt_session_env ("DISPLAY", pargs.r.ret_str); Index: b/g10/options.h =================================================================== --- b/g10/options.h +++ b/g10/options.h @@ -262,6 +262,8 @@ int passphrase_repeat; int pinentry_mode; + + int unwrap_encryption; } opt; /* CTRL is used to keep some global variables we currently can't Index: b/g10/packet.h =================================================================== --- b/g10/packet.h +++ b/g10/packet.h @@ -663,6 +663,8 @@ int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ +gpg_error_t get_output_file (const byte *embedded_name, int embedded_namelen, + iobuf_t data, char **fnamep, estream_t *fpp); int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput, int clearsig ); int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2, Index: b/g10/plaintext.c =================================================================== --- b/g10/plaintext.c +++ b/g10/plaintext.c @@ -40,53 +40,29 @@ #include "i18n.h" -/* Handle a plaintext packet. If MFX is not NULL, update the MDs - * Note: We should have used the filter stuff here, but we have to add - * some easy mimic to set a read limit, so we calculate only the bytes - * from the plaintext. */ -int -handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx, - int nooutput, int clearsig) -{ - char *fname = NULL; - estream_t fp = NULL; - static off_t count = 0; - int err = 0; - int c; - int convert = (pt->mode == 't' || pt->mode == 'u'); -#ifdef __riscos__ - int filetype = 0xfff; -#endif +/* Get the output filename. On success, the actual filename that is + used is set in *FNAMEP and a filepointer is returned in *FP. - /* Let people know what the plaintext info is. This allows the - receiving program to try and do something different based on the - format code (say, recode UTF-8 to local). */ - if (!nooutput && is_status_enabled ()) - { - char status[50]; + EMBEDDED_NAME AND EMBEDDED_NAMELEN are normally stored in a + plaintext packet. EMBEDDED_NAMELEN should not include any NUL + terminator (EMBEDDED_NAME does not need to be NUL terminated). - /* Better make sure that stdout has been flushed in case the - output will be written to it. This is to make sure that no - not-yet-flushed stuff will be written after the plaintext - status message. */ - es_fflush (es_stdout); - - snprintf (status, sizeof status, - "%X %lu ", (byte) pt->mode, (ulong) pt->timestamp); - write_status_text_and_buffer (STATUS_PLAINTEXT, - status, pt->name, pt->namelen, 0); + DATA is the iobuf containing the input data. We just use it to get + the input file's filename. - if (!pt->is_partial) - { - snprintf (status, sizeof status, "%lu", (ulong) pt->len); - write_status_text (STATUS_PLAINTEXT_LENGTH, status); - } - } + On success, the caller is responsible for calling xfree on *FNAMEP + and calling es_close on *FPP. */ +gpg_error_t +get_output_file (const byte *embedded_name, int embedded_namelen, + iobuf_t data, char **fnamep, estream_t *fpp) +{ + gpg_error_t err = 0; + char *fname = NULL; + estream_t fp = NULL; + int nooutput = 0; /* Create the filename as C string. */ - if (nooutput) - ; - else if (opt.outfp) + if (opt.outfp) { fname = xtrystrdup ("[FP]"); if (!fname) @@ -104,16 +80,17 @@ goto leave; } } - else if (pt->namelen == 8 && !memcmp (pt->name, "_CONSOLE", 8)) + else if (embedded_namelen == 8 && !memcmp (embedded_name, "_CONSOLE", 8)) { log_info (_("data not saved; use option \"--output\" to save it\n")); nooutput = 1; } else if (!opt.flags.use_embedded_filename) { - fname = make_outfile_name (iobuf_get_real_fname (pt->buf)); + if (data) + fname = make_outfile_name (iobuf_get_real_fname (data)); if (!fname) - fname = ask_outfile_name (pt->name, pt->namelen); + fname = ask_outfile_name (embedded_name, embedded_namelen); if (!fname) { err = gpg_error (GPG_ERR_GENERAL); /* Can't create file. */ @@ -121,7 +98,7 @@ } } else - fname = utf8_to_native (pt->name, pt->namelen, 0); + fname = utf8_to_native (embedded_name, embedded_namelen, 0); if (nooutput) ; @@ -205,7 +182,8 @@ /* If there's a ,xxx extension in the embedded filename, use that, else check whether the user input (in fname) has a ,xxx appended, then use that in preference */ - if ((c = riscos_get_filetype_from_string (pt->name, pt->namelen)) != -1) + if ((c = riscos_get_filetype_from_string (embedded_name, + embedded_namelen)) != -1) filetype = c; if ((c = riscos_get_filetype_from_string (fname, strlen (fname))) != -1) filetype = c; @@ -213,6 +191,70 @@ } #endif /* __riscos__ */ + leave: + if (err) + { + if (fp && fp != es_stdout && fp != opt.outfp) + es_fclose (fp); + xfree (fname); + return err; + } + + *fnamep = fname; + *fpp = fp; + return 0; +} + +/* Handle a plaintext packet. If MFX is not NULL, update the MDs + * Note: We should have used the filter stuff here, but we have to add + * some easy mimic to set a read limit, so we calculate only the bytes + * from the plaintext. */ +int +handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx, + int nooutput, int clearsig) +{ + char *fname = NULL; + estream_t fp = NULL; + static off_t count = 0; + int err = 0; + int c; + int convert = (pt->mode == 't' || pt->mode == 'u'); +#ifdef __riscos__ + int filetype = 0xfff; +#endif + + /* Let people know what the plaintext info is. This allows the + receiving program to try and do something different based on the + format code (say, recode UTF-8 to local). */ + if (!nooutput && is_status_enabled ()) + { + char status[50]; + + /* Better make sure that stdout has been flushed in case the + output will be written to it. This is to make sure that no + not-yet-flushed stuff will be written after the plaintext + status message. */ + es_fflush (es_stdout); + + snprintf (status, sizeof status, + "%X %lu ", (byte) pt->mode, (ulong) pt->timestamp); + write_status_text_and_buffer (STATUS_PLAINTEXT, + status, pt->name, pt->namelen, 0); + + if (!pt->is_partial) + { + snprintf (status, sizeof status, "%lu", (ulong) pt->len); + write_status_text (STATUS_PLAINTEXT_LENGTH, status); + } + } + + if (! nooutput) + { + err = get_output_file (pt->name, pt->namelen, pt->buf, &fname, &fp); + if (err) + goto leave; + } + if (!pt->is_partial) { /* We have an actual length (which might be zero). */