NeoMutt  2024-12-12-19-ge4b57e
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
application_handler()

Manage the MIME type "application/pgp" or "application/smime". More...

+ Collaboration diagram for application_handler():

Functions

int pgp_gpgme_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 
int smime_gpgme_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 
int pgp_class_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 
int smime_class_application_handler (struct Body *b, struct State *state)
 Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.
 

Detailed Description

Manage the MIME type "application/pgp" or "application/smime".

Parameters
bBody of the email
stateState of text being processed
Return values
0Success
-1Error

Function Documentation

◆ pgp_gpgme_application_handler()

int pgp_gpgme_application_handler ( struct Body b,
struct State state 
)

Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.

Definition at line 2470 of file crypt_gpgme.c.

2471{
2472 int needpass = -1;
2473 bool pgp_keyblock = false;
2474 bool clearsign = false;
2475 long bytes;
2476 LOFF_T last_pos;
2477 LOFF_T block_begin;
2478 LOFF_T block_end;
2479 char buf[8192] = { 0 };
2480 FILE *fp_out = NULL;
2481
2482 gpgme_error_t err = GPG_ERR_NO_ERROR;
2483 gpgme_data_t armored_data = NULL;
2484
2485 bool maybe_goodsig = true;
2486 bool have_any_sigs = false;
2487
2488 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2489 char *gpgcharset = NULL;
2490
2491 mutt_debug(LL_DEBUG2, "Entering handler\n");
2492
2493 /* For clearsigned messages we won't be able to get a character set
2494 * but we know that this may only be text thus we assume Latin-1 here. */
2495 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2496 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2497
2498 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2499 {
2500 return -1;
2501 }
2502 last_pos = b->offset;
2503
2504 for (bytes = b->length; bytes > 0;)
2505 {
2506 // record before the fgets in case it is a BEGIN block
2507 block_begin = last_pos;
2508
2509 if (!fgets(buf, sizeof(buf), state->fp_in))
2510 break;
2511
2512 LOFF_T offset = ftello(state->fp_in);
2513 if (offset < 0)
2514 {
2515 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2516 offset = 0;
2517 }
2518 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2519 last_pos = offset;
2520
2521 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2522 if (plen != 0)
2523 {
2524 needpass = 0;
2525 clearsign = false;
2526 pgp_keyblock = false;
2527
2528 if (MESSAGE(buf + plen))
2529 {
2530 needpass = 1;
2531 }
2532 else if (SIGNED_MESSAGE(buf + plen))
2533 {
2534 clearsign = true;
2535 }
2536 else if (PUBLIC_KEY_BLOCK(buf + plen))
2537 {
2538 pgp_keyblock = true;
2539 }
2540 else
2541 {
2542 /* XXX we may wish to recode here */
2543 if (state->prefix)
2544 state_puts(state, state->prefix);
2545 state_puts(state, buf);
2546 continue;
2547 }
2548
2549 /* Find the end of armored block. */
2550 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2551 {
2552 offset = ftello(state->fp_in);
2553 if (offset < 0)
2554 {
2555 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2556 offset = 0;
2557 }
2558 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2559 last_pos = offset;
2560
2561 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2562 {
2563 break;
2564 }
2565
2566 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2567 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2568 {
2569 break;
2570 }
2571
2572 // remember optional Charset: armor header as defined by rfc4880
2573 if (mutt_strn_equal("Charset: ", buf, 9))
2574 {
2575 size_t l = 0;
2576 FREE(&gpgcharset);
2577 gpgcharset = mutt_str_dup(buf + 9);
2578 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2579 gpgcharset[l - 1] = 0;
2580 if (!mutt_ch_check_charset(gpgcharset, 0))
2581 mutt_str_replace(&gpgcharset, "UTF-8");
2582 }
2583 }
2584 block_end = ftello(state->fp_in);
2585 if (block_end < 0)
2586 {
2587 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2588 block_end = 0;
2589 }
2590
2591 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2592
2593 /* Copy PGP material to an data container */
2594 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2595 fseeko(state->fp_in, block_end, 0);
2596
2597 /* Invoke PGP if needed */
2598 if (pgp_keyblock)
2599 {
2600 pgp_gpgme_extract_keys(armored_data, &fp_out);
2601 }
2602 else if (!clearsign || (state->flags & STATE_VERIFY))
2603 {
2604 gpgme_data_t plaintext = create_gpgme_data();
2605 gpgme_ctx_t ctx = create_gpgme_context(false);
2606
2607 if (clearsign)
2608 {
2609 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2610 }
2611 else
2612 {
2613 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2614 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2615 {
2616 /* Decrypt verify can't handle signed only messages. */
2617 gpgme_data_seek(armored_data, 0, SEEK_SET);
2618 /* Must release plaintext so that we supply an uninitialized object. */
2619 gpgme_data_release(plaintext);
2620 plaintext = create_gpgme_data();
2621 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2622 }
2623 }
2624 redraw_if_needed(ctx);
2625
2626 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
2627 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2628 if (c_devel_security && result && (state->flags & STATE_DISPLAY))
2629 show_encryption_info(state, result);
2630
2631 if (err != GPG_ERR_NO_ERROR)
2632 {
2633 char errbuf[200] = { 0 };
2634
2635 snprintf(errbuf, sizeof(errbuf) - 1,
2636 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2637 state_puts(state, errbuf);
2638 }
2639 else
2640 {
2641 /* Decryption/Verification succeeded */
2642
2643 mutt_message(_("PGP message successfully decrypted"));
2644
2645 bool sig_stat = false;
2646 char *tmpfname = NULL;
2647
2648 /* Check whether signatures have been verified. */
2649 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2650 if (verify_result->signatures)
2651 sig_stat = true;
2652
2653 have_any_sigs = false;
2654 maybe_goodsig = false;
2655 if ((state->flags & STATE_DISPLAY) && sig_stat)
2656 {
2657 int res, idx;
2658 bool anybad = false;
2659
2660 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2661 have_any_sigs = true;
2662 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2663 {
2664 if (res == 1)
2665 anybad = true;
2666 }
2667 if (!anybad && idx)
2668 maybe_goodsig = true;
2669
2670 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2671 }
2672
2673 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2674 if (tmpfname)
2675 {
2676 unlink(tmpfname);
2677 FREE(&tmpfname);
2678 }
2679 else
2680 {
2681 mutt_file_fclose(&fp_out);
2682 state_puts(state, _("Error: copy data failed\n"));
2683 }
2684 }
2685 gpgme_data_release(plaintext);
2686 gpgme_release(ctx);
2687 }
2688
2689 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2690 * outputs utf-8 cleartext. This may not always be true, but it
2691 * seems to be a reasonable guess. */
2692 if (state->flags & STATE_DISPLAY)
2693 {
2694 if (needpass)
2695 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2696 else if (pgp_keyblock)
2697 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2698 else
2699 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2700 }
2701
2702 if (clearsign)
2703 {
2704 copy_clearsigned(armored_data, state, body_charset);
2705 }
2706 else if (fp_out)
2707 {
2708 int c;
2709 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2710 rewind(fp_out);
2711 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2713 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2714 {
2715 state_putc(state, c);
2716 if ((c == '\n') && state->prefix)
2717 state_puts(state, state->prefix);
2718 }
2720 }
2721
2722 if (state->flags & STATE_DISPLAY)
2723 {
2724 state_putc(state, '\n');
2725 if (needpass)
2726 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2727 else if (pgp_keyblock)
2728 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2729 else
2730 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2731 }
2732
2733 // Multiple PGP blocks can exist, so clean these up in each loop
2734 gpgme_data_release(armored_data);
2735 mutt_file_fclose(&fp_out);
2736 }
2737 else
2738 {
2739 /* A traditional PGP part may mix signed and unsigned content */
2740 /* XXX we may wish to recode here */
2741 if (state->prefix)
2742 state_puts(state, state->prefix);
2743 state_puts(state, buf);
2744 }
2745 }
2746 FREE(&gpgcharset);
2747
2748 b->goodsig = (maybe_goodsig && have_any_sigs);
2749
2750 if (needpass == -1)
2751 {
2752 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2753 return 1;
2754 }
2755 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2756
2757 return err;
2758}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
Show encryption information.
Definition: crypt_gpgme.c:1433
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:400
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:361
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:102
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
Definition: crypt_gpgme.c:493
#define PUBLIC_KEY_BLOCK(_y)
Definition: crypt_gpgme.c:103
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:563
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
Definition: crypt_gpgme.c:121
static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
Write PGP keys to a file.
Definition: crypt_gpgme.c:2112
static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
Copy a clearsigned message.
Definition: crypt_gpgme.c:2414
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
Show information about one signature.
Definition: crypt_gpgme.c:1458
#define MESSAGE(_y)
Definition: crypt_gpgme.c:101
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:133
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:55
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition: charset.c:894
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition: charset.c:980
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition: charset.c:933
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:962
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:65
#define _(a)
Definition: message.h:28
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition: state.c:104
#define state_puts(STATE, STR)
Definition: state.h:58
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:33
#define state_putc(STATE, STR)
Definition: state.h:59
#define STATE_VERIFY
Perform signature verification.
Definition: state.h:34
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:425
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:581
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
bool goodsig
Good cryptographic signature.
Definition: body.h:45
Cursor for converting a file's encoding.
Definition: charset.h:43
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:52
FILE * fp_in
File to read from.
Definition: state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition: state.h:51
+ Here is the call graph for this function:

◆ smime_gpgme_application_handler()

int smime_gpgme_application_handler ( struct Body b,
struct State state 
)

Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.

Definition at line 2856 of file crypt_gpgme.c.

2857{
2858 int is_signed = 0;
2859 int rc = 0;
2860
2861 mutt_debug(LL_DEBUG2, "Entering handler\n");
2862
2863 /* clear out any mime headers before the handler, so they can't be spoofed. */
2865 b->warnsig = false;
2866 FILE *fp_out = mutt_file_mkstemp();
2867 if (!fp_out)
2868 {
2869 mutt_perror(_("Can't create temporary file"));
2870 if (state->flags & STATE_DISPLAY)
2871 {
2872 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2873 }
2874 return -1;
2875 }
2876
2877 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2878 if (tattach)
2879 {
2880 tattach->goodsig = is_signed > 0;
2881
2882 if (state->flags & STATE_DISPLAY)
2883 {
2884 state_attach_puts(state, is_signed ?
2885 _("[-- The following data is S/MIME signed --]\n") :
2886 _("[-- The following data is S/MIME encrypted --]\n"));
2887 mutt_protected_headers_handler(tattach, state);
2888 }
2889
2890 /* Store any protected headers in the parent so they can be
2891 * accessed for index updates after the handler recursion is done.
2892 * This is done before the handler to prevent a nested encrypted
2893 * handler from freeing the headers. */
2895 b->mime_headers = tattach->mime_headers;
2896 tattach->mime_headers = NULL;
2897
2898 FILE *fp_save = state->fp_in;
2899 state->fp_in = fp_out;
2900 rc = mutt_body_handler(tattach, state);
2901 state->fp_in = fp_save;
2902
2903 /* Embedded multipart signed protected headers override the
2904 * encrypted headers. We need to do this after the handler so
2905 * they can be printed in the pager. */
2906 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2907 {
2909 b->mime_headers = tattach->parts->mime_headers;
2910 tattach->parts->mime_headers = NULL;
2911 }
2912
2913 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2914 * cache signature verification status. */
2915 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2916 {
2917 b->goodsig = tattach->goodsig;
2918 if (!b->goodsig)
2919 b->warnsig = tattach->warnsig;
2920 }
2921 else if (tattach->goodsig)
2922 {
2923 b->goodsig = true;
2924 b->warnsig = tattach->warnsig;
2925 }
2926
2927 if (state->flags & STATE_DISPLAY)
2928 {
2929 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2930 _("[-- End of S/MIME encrypted data --]\n"));
2931 }
2932
2933 mutt_body_free(&tattach);
2934 }
2935
2936 mutt_file_fclose(&fp_out);
2937 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2938
2939 return rc;
2940}
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:408
static struct Body * decrypt_part(struct Body *b, struct State *state, FILE *fp_out, bool is_smime, int *r_is_signed)
Decrypt a PGP or SMIME message.
Definition: crypt_gpgme.c:1732
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition: crypt.c:1117
#define mutt_perror(...)
Definition: logging2.h:93
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1632
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:73
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:76
struct Body * next
next attachment in the list
Definition: body.h:72
bool warnsig
Maybe good signature.
Definition: body.h:48
#define mutt_file_mkstemp()
Definition: tmp.h:36
+ Here is the call graph for this function:

◆ pgp_class_application_handler()

int pgp_class_application_handler ( struct Body b,
struct State state 
)

Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.

Definition at line 472 of file pgp.c.

473{
474 bool could_not_decrypt = false;
475 int decrypt_okay_rc = 0;
476 int needpass = -1;
477 bool pgp_keyblock = false;
478 bool clearsign = false;
479 int rc = -1;
480 int c = 1;
481 long bytes;
482 LOFF_T last_pos, offset;
483 char buf[8192] = { 0 };
484 FILE *fp_pgp_out = NULL, *fp_pgp_in = NULL, *fp_pgp_err = NULL;
485 FILE *fp_tmp = NULL;
486 pid_t pid;
487 struct Buffer *tempfile = buf_pool_get();
488
489 bool maybe_goodsig = true;
490 bool have_any_sigs = false;
491
492 char *gpgcharset = NULL;
493 char body_charset[256] = { 0 };
494 mutt_body_get_charset(b, body_charset, sizeof(body_charset));
495
496 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
497 {
498 return -1;
499 }
500 last_pos = b->offset;
501
502 for (bytes = b->length; bytes > 0;)
503 {
504 if (!fgets(buf, sizeof(buf), state->fp_in))
505 break;
506
507 offset = ftello(state->fp_in);
508 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
509 last_pos = offset;
510
511 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
512 if (plen != 0)
513 {
514 needpass = false;
515 clearsign = false;
516 could_not_decrypt = false;
517 decrypt_okay_rc = 0;
518
519 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
520 {
521 needpass = 1;
522 }
523 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
524 {
525 clearsign = true;
526 }
527 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
528 {
529 pgp_keyblock = true;
530 }
531 else
532 {
533 /* XXX we may wish to recode here */
534 if (state->prefix)
535 state_puts(state, state->prefix);
536 state_puts(state, buf);
537 continue;
538 }
539
540 have_any_sigs = have_any_sigs || (clearsign && (state->flags & STATE_VERIFY));
541
542 /* Copy PGP material to temporary file */
543 buf_mktemp(tempfile);
544 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
545 if (!fp_tmp)
546 {
547 mutt_perror("%s", buf_string(tempfile));
548 FREE(&gpgcharset);
549 goto out;
550 }
551
552 fputs(buf, fp_tmp);
553 while ((bytes > 0) && fgets(buf, sizeof(buf) - 1, state->fp_in))
554 {
555 offset = ftello(state->fp_in);
556 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
557 last_pos = offset;
558
559 fputs(buf, fp_tmp);
560
561 if ((needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf)) ||
562 (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
563 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf))))
564 {
565 break;
566 }
567 /* remember optional Charset: armor header as defined by RFC4880 */
568 if (mutt_str_startswith(buf, "Charset: "))
569 {
570 size_t l = 0;
571 FREE(&gpgcharset);
572 gpgcharset = mutt_str_dup(buf + 9);
573 l = mutt_str_len(gpgcharset);
574 if ((l > 0) && (gpgcharset[l - 1] == '\n'))
575 gpgcharset[l - 1] = 0;
576 if (!mutt_ch_check_charset(gpgcharset, false))
577 mutt_str_replace(&gpgcharset, "UTF-8");
578 }
579 }
580
581 /* leave fp_tmp open in case we still need it - but flush it! */
582 fflush(fp_tmp);
583
584 /* Invoke PGP if needed */
585 if (!clearsign || (state->flags & STATE_VERIFY))
586 {
587 fp_pgp_out = mutt_file_mkstemp();
588 if (!fp_pgp_out)
589 {
590 mutt_perror(_("Can't create temporary file"));
591 goto out;
592 }
593
594 fp_pgp_err = mutt_file_mkstemp();
595 if (!fp_pgp_err)
596 {
597 mutt_perror(_("Can't create temporary file"));
598 goto out;
599 }
600
601 pid = pgp_invoke_decode(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
602 fileno(fp_pgp_err), buf_string(tempfile),
603 (needpass != 0));
604 if (pid == -1)
605 {
606 mutt_file_fclose(&fp_pgp_out);
607 maybe_goodsig = false;
608 fp_pgp_in = NULL;
609 state_attach_puts(state, _("[-- Error: unable to create PGP subprocess --]\n"));
610 }
611 else /* PGP started successfully */
612 {
613 if (needpass)
614 {
617 if (pgp_use_gpg_agent())
618 *PgpPass = '\0';
619 fprintf(fp_pgp_in, "%s\n", PgpPass);
620 }
621
622 mutt_file_fclose(&fp_pgp_in);
623
624 int wait_filter_rc = filter_wait(pid);
625
626 fflush(fp_pgp_err);
627 /* If we are expecting an encrypted message, verify status fd output.
628 * Note that BEGIN PGP MESSAGE does not guarantee the content is encrypted,
629 * so we need to be more selective about the value of decrypt_okay_rc.
630 *
631 * -3 indicates we actively found a DECRYPTION_FAILED.
632 * -2 and -1 indicate part or all of the content was plaintext. */
633 if (needpass)
634 {
635 rewind(fp_pgp_err);
636 decrypt_okay_rc = pgp_check_decryption_okay(fp_pgp_err);
637 if (decrypt_okay_rc <= -3)
638 mutt_file_fclose(&fp_pgp_out);
639 }
640
641 if (state->flags & STATE_DISPLAY)
642 {
643 rewind(fp_pgp_err);
644 crypt_current_time(state, "PGP");
645 int checksig_rc = pgp_copy_checksig(fp_pgp_err, state->fp_out);
646
647 if (checksig_rc == 0)
648 have_any_sigs = true;
649 /* Sig is bad if
650 * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
651 * Sig _is_ correct if
652 * gpg_good_sign="" && pgp_decode_command returned 0 */
653 if (checksig_rc == -1 || (wait_filter_rc != 0))
654 maybe_goodsig = false;
655
656 state_attach_puts(state, _("[-- End of PGP output --]\n\n"));
657 }
658 if (pgp_use_gpg_agent())
659 {
661 }
662 }
663
664 /* treat empty result as sign of failure */
665 /* TODO: maybe on failure neomutt should include the original undecoded text. */
666 if (fp_pgp_out)
667 {
668 rewind(fp_pgp_out);
669 c = fgetc(fp_pgp_out);
670 ungetc(c, fp_pgp_out);
671 }
672 if (!clearsign && (!fp_pgp_out || (c == EOF)))
673 {
674 could_not_decrypt = true;
676 }
677
678 if ((could_not_decrypt || (decrypt_okay_rc <= -3)) && !(state->flags & STATE_DISPLAY))
679 {
680 mutt_error(_("Could not decrypt PGP message"));
681 goto out;
682 }
683 }
684
685 /* Now, copy cleartext to the screen. */
686 if (state->flags & STATE_DISPLAY)
687 {
688 if (needpass)
689 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
690 else if (pgp_keyblock)
691 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
692 else
693 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
694 }
695
696 if (clearsign)
697 {
698 rewind(fp_tmp);
699 pgp_copy_clearsigned(fp_tmp, state, body_charset);
700 }
701 else if (fp_pgp_out)
702 {
703 struct FgetConv *fc = NULL;
704 int ch;
705 char *expected_charset = (gpgcharset && *gpgcharset) ? gpgcharset : "utf-8";
706
707 mutt_debug(LL_DEBUG3, "pgp: recoding inline from [%s] to [%s]\n",
708 expected_charset, cc_charset());
709
710 rewind(fp_pgp_out);
711 state_set_prefix(state);
712 fc = mutt_ch_fgetconv_open(fp_pgp_out, expected_charset, cc_charset(),
714 while ((ch = mutt_ch_fgetconv(fc)) != EOF)
715 state_prefix_putc(state, ch);
717 }
718
719 /* Multiple PGP blocks can exist, so these need to be closed and
720 * unlinked inside the loop. */
721 mutt_file_fclose(&fp_tmp);
722 mutt_file_unlink(buf_string(tempfile));
723 mutt_file_fclose(&fp_pgp_out);
724 mutt_file_fclose(&fp_pgp_err);
725
726 if (state->flags & STATE_DISPLAY)
727 {
728 state_putc(state, '\n');
729 if (needpass)
730 {
731 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
732 if (could_not_decrypt || (decrypt_okay_rc <= -3))
733 {
734 mutt_error(_("Could not decrypt PGP message"));
735 }
736 else if (decrypt_okay_rc < 0)
737 {
738 /* L10N: You will see this error message if (1) you are decrypting
739 (not encrypting) something and (2) it is a plaintext. So the
740 message does not mean "You failed to encrypt the message." */
741 mutt_error(_("PGP message is not encrypted"));
742 }
743 else
744 {
745 mutt_message(_("PGP message successfully decrypted"));
746 }
747 }
748 else if (pgp_keyblock)
749 {
750 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
751 }
752 else
753 {
754 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
755 }
756 }
757 }
758 else
759 {
760 /* A traditional PGP part may mix signed and unsigned content */
761 /* XXX we may wish to recode here */
762 if (state->prefix)
763 state_puts(state, state->prefix);
764 state_puts(state, buf);
765 }
766 }
767
768 rc = 0;
769
770out:
771 b->goodsig = (maybe_goodsig && have_any_sigs);
772
773 if (fp_tmp)
774 {
775 mutt_file_fclose(&fp_tmp);
776 mutt_file_unlink(buf_string(tempfile));
777 }
778 mutt_file_fclose(&fp_pgp_out);
779 mutt_file_fclose(&fp_pgp_err);
780
781 buf_pool_release(&tempfile);
782
783 FREE(&gpgcharset);
784
785 if (needpass == -1)
786 {
787 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
788 return -1;
789 }
790
791 return rc;
792}
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition: crypt.c:65
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:100
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:221
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
bool pgp_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition: pgp.c:85
void pgp_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition: pgp.c:76
#define mutt_error(...)
Definition: logging2.h:92
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
void state_prefix_putc(struct State *state, char c)
Write a prefixed character to the state.
Definition: state.c:165
#define state_set_prefix(state)
Definition: state.h:56
static char PgpPass[1024]
Cached PGP Passphrase.
Definition: pgp.c:69
static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
Copy PGP output and look for signs of a good signature.
Definition: pgp.c:251
static void pgp_copy_clearsigned(FILE *fp_in, struct State *state, char *charset)
Copy a clearsigned message, stripping the signature.
Definition: pgp.c:424
bool pgp_use_gpg_agent(void)
Does the user want to use the gpg agent?
Definition: pgp.c:127
static int pgp_check_decryption_okay(FILE *fp_in)
Check GPG output for status codes.
Definition: pgp.c:357
pid_t pgp_invoke_decode(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *fname, bool need_passphrase)
Use PGP to decode a message.
Definition: pgpinvoke.c:133
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
String manipulation buffer.
Definition: buffer.h:36
FILE * fp_out
File to write to.
Definition: state.h:50
#define buf_mktemp(buf)
Definition: tmp.h:33
+ Here is the call graph for this function:

◆ smime_class_application_handler()

int smime_class_application_handler ( struct Body b,
struct State state 
)

Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::application_handler() -.

Definition at line 1980 of file smime.c.

1981{
1982 int rc = -1;
1983
1984 /* clear out any mime headers before the handler, so they can't be spoofed. */
1986
1987 struct Body *tattach = smime_handle_entity(b, state, NULL);
1988 if (tattach)
1989 {
1990 rc = 0;
1991 mutt_body_free(&tattach);
1992 }
1993 return rc;
1994}
static struct Body * smime_handle_entity(struct Body *b, struct State *state, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition: smime.c:1679
+ Here is the call graph for this function: