NeoMutt  2025-12-11-1059-g2f5469
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 2506 of file crypt_gpgme.c.

2507{
2508 int needpass = -1;
2509 bool pgp_keyblock = false;
2510 bool clearsign = false;
2511 long bytes;
2512 LOFF_T last_pos;
2513 LOFF_T block_begin;
2514 LOFF_T block_end;
2515 char buf[8192] = { 0 };
2516 FILE *fp_out = NULL;
2517
2518 gpgme_error_t err = GPG_ERR_NO_ERROR;
2519 gpgme_data_t armored_data = NULL;
2520
2521 bool maybe_goodsig = true;
2522 bool have_any_sigs = false;
2523
2524 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2525 char *gpgcharset = NULL;
2526
2527 mutt_debug(LL_DEBUG2, "Entering handler\n");
2528
2529 /* For clearsigned messages we won't be able to get a character set
2530 * but we know that this may only be text thus we assume Latin-1 here. */
2531 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2532 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2533
2534 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2535 {
2536 return -1;
2537 }
2538 last_pos = b->offset;
2539
2540 for (bytes = b->length; bytes > 0;)
2541 {
2542 // record before the fgets in case it is a BEGIN block
2543 block_begin = last_pos;
2544
2545 if (!fgets(buf, sizeof(buf), state->fp_in))
2546 break;
2547
2548 LOFF_T offset = ftello(state->fp_in);
2549 if (offset < 0)
2550 {
2551 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2552 offset = 0;
2553 }
2554 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2555 last_pos = offset;
2556
2557 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2558 if (plen != 0)
2559 {
2560 needpass = 0;
2561 clearsign = false;
2562 pgp_keyblock = false;
2563
2564 if (MESSAGE(buf + plen))
2565 {
2566 needpass = 1;
2567 }
2568 else if (SIGNED_MESSAGE(buf + plen))
2569 {
2570 clearsign = true;
2571 }
2572 else if (PUBLIC_KEY_BLOCK(buf + plen))
2573 {
2574 pgp_keyblock = true;
2575 }
2576 else
2577 {
2578 /* XXX we may wish to recode here */
2579 if (state->prefix)
2580 state_puts(state, state->prefix);
2581 state_puts(state, buf);
2582 continue;
2583 }
2584
2585 /* Find the end of armored block. */
2586 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2587 {
2588 offset = ftello(state->fp_in);
2589 if (offset < 0)
2590 {
2591 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2592 offset = 0;
2593 }
2594 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2595 last_pos = offset;
2596
2597 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2598 {
2599 break;
2600 }
2601
2602 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2603 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2604 {
2605 break;
2606 }
2607
2608 // remember optional Charset: armor header as defined by rfc4880
2609 if (mutt_strn_equal("Charset: ", buf, 9))
2610 {
2611 size_t l = 0;
2612 FREE(&gpgcharset);
2613 gpgcharset = mutt_str_dup(buf + 9);
2614 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2615 gpgcharset[l - 1] = 0;
2616 if (!mutt_ch_check_charset(gpgcharset, 0))
2617 mutt_str_replace(&gpgcharset, "UTF-8");
2618 }
2619 }
2620 block_end = ftello(state->fp_in);
2621 if (block_end < 0)
2622 {
2623 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2624 block_end = 0;
2625 }
2626
2627 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2628
2629 /* Copy PGP material to an data container */
2630 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2631 fseeko(state->fp_in, block_end, 0);
2632
2633 /* Invoke PGP if needed */
2634 if (pgp_keyblock)
2635 {
2636 pgp_gpgme_extract_keys(armored_data, &fp_out);
2637 }
2638 else if (!clearsign || (state->flags & STATE_VERIFY))
2639 {
2640 gpgme_data_t plaintext = create_gpgme_data();
2641 gpgme_ctx_t ctx = create_gpgme_context(false);
2642
2643 if (clearsign)
2644 {
2645 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2646 }
2647 else
2648 {
2649 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2650 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2651 {
2652 /* Decrypt verify can't handle signed only messages. */
2653 gpgme_data_seek(armored_data, 0, SEEK_SET);
2654 /* Must release plaintext so that we supply an uninitialized object. */
2655 gpgme_data_release(plaintext);
2656 plaintext = create_gpgme_data();
2657 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2658 }
2659 }
2660 redraw_if_needed(ctx);
2661
2662 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2663 if (result && (state->flags & STATE_DISPLAY))
2664 show_encryption_info(state, result);
2665
2666 if (err != GPG_ERR_NO_ERROR)
2667 {
2668 char errbuf[200] = { 0 };
2669
2670 snprintf(errbuf, sizeof(errbuf) - 1,
2671 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2672 state_puts(state, errbuf);
2673 }
2674 else
2675 {
2676 /* Decryption/Verification succeeded */
2677
2678 mutt_message(_("PGP message successfully decrypted"));
2679
2680 bool sig_stat = false;
2681 char *tmpfname = NULL;
2682
2683 /* Check whether signatures have been verified. */
2684 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2685 if (verify_result->signatures)
2686 sig_stat = true;
2687
2688 have_any_sigs = false;
2689 maybe_goodsig = false;
2690 if ((state->flags & STATE_DISPLAY) && sig_stat)
2691 {
2692 int res;
2693 int idx;
2694 bool anybad = false;
2695
2696 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2697 have_any_sigs = true;
2698 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2699 {
2700 if (res == 1)
2701 anybad = true;
2702 }
2703 if (!anybad && idx)
2704 maybe_goodsig = true;
2705
2706 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2707 }
2708
2709 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2710 if (tmpfname)
2711 {
2712 unlink(tmpfname);
2713 FREE(&tmpfname);
2714 }
2715 else
2716 {
2717 mutt_file_fclose(&fp_out);
2718 state_puts(state, _("Error: copy data failed\n"));
2719 }
2720 }
2721 gpgme_data_release(plaintext);
2722 gpgme_release(ctx);
2723 }
2724
2725 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2726 * outputs utf-8 cleartext. This may not always be true, but it
2727 * seems to be a reasonable guess. */
2728 if (state->flags & STATE_DISPLAY)
2729 {
2730 if (needpass)
2731 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2732 else if (pgp_keyblock)
2733 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2734 else
2735 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2736 }
2737
2738 if (clearsign)
2739 {
2740 copy_clearsigned(armored_data, state, body_charset);
2741 }
2742 else if (fp_out)
2743 {
2744 int c;
2745 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2746 fseek(fp_out, 0, SEEK_SET);
2747 clearerr(fp_out);
2748 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2750 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2751 {
2752 state_putc(state, c);
2753 if ((c == '\n') && state->prefix)
2754 state_puts(state, state->prefix);
2755 }
2757 }
2758
2759 if (state->flags & STATE_DISPLAY)
2760 {
2761 state_putc(state, '\n');
2762 if (needpass)
2763 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2764 else if (pgp_keyblock)
2765 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2766 else
2767 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2768 }
2769
2770 // Multiple PGP blocks can exist, so clean these up in each loop
2771 gpgme_data_release(armored_data);
2772 mutt_file_fclose(&fp_out);
2773 }
2774 else
2775 {
2776 /* A traditional PGP part may mix signed and unsigned content */
2777 /* XXX we may wish to recode here */
2778 if (state->prefix)
2779 state_puts(state, state->prefix);
2780 state_puts(state, buf);
2781 }
2782 }
2783 FREE(&gpgcharset);
2784
2785 b->goodsig = (maybe_goodsig && have_any_sigs);
2786
2787 if (needpass == -1)
2788 {
2789 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2790 return 1;
2791 }
2792 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2793
2794 return err;
2795}
const char * cc_charset(void)
Get the cached value of $charset.
static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
Show encryption information.
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
#define SIGNED_MESSAGE(_y)
Definition crypt_gpgme.c:96
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
#define PUBLIC_KEY_BLOCK(_y)
Definition crypt_gpgme.c:97
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
Write PGP keys to a file.
static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
Copy a clearsigned message.
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
Show information about one signature.
#define MESSAGE(_y)
Definition crypt_gpgme.c:95
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition body.c:134
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:92
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition charset.c:882
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition charset.c:968
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:921
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition charset.c:950
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition charset.h:67
#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:64
#define state_putc(STATE, STR)
Definition state.h:65
@ STATE_VERIFY
Perform signature verification.
Definition state.h:38
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
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:429
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
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:587
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
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:45
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_in
File to read from.
Definition state.h:55
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
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 2893 of file crypt_gpgme.c.

2894{
2895 int is_signed = 0;
2896 int rc = 0;
2897
2898 mutt_debug(LL_DEBUG2, "Entering handler\n");
2899
2900 /* clear out any mime headers before the handler, so they can't be spoofed. */
2902 b->warnsig = false;
2903 FILE *fp_out = mutt_file_mkstemp();
2904 if (!fp_out)
2905 {
2906 mutt_perror(_("Can't create temporary file"));
2907 if (state->flags & STATE_DISPLAY)
2908 {
2909 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2910 }
2911 return -1;
2912 }
2913
2914 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2915 if (tattach)
2916 {
2917 tattach->goodsig = is_signed > 0;
2918
2919 if (state->flags & STATE_DISPLAY)
2920 {
2921 state_attach_puts(state, is_signed ?
2922 _("[-- The following data is S/MIME signed --]\n") :
2923 _("[-- The following data is S/MIME encrypted --]\n"));
2924 mutt_protected_headers_handler(tattach, state);
2925 }
2926
2927 /* Store any protected headers in the parent so they can be
2928 * accessed for index updates after the handler recursion is done.
2929 * This is done before the handler to prevent a nested encrypted
2930 * handler from freeing the headers. */
2932 b->mime_headers = tattach->mime_headers;
2933 tattach->mime_headers = NULL;
2934
2935 FILE *fp_save = state->fp_in;
2936 state->fp_in = fp_out;
2937 rc = mutt_body_handler(tattach, state);
2938 state->fp_in = fp_save;
2939
2940 /* Embedded multipart signed protected headers override the
2941 * encrypted headers. We need to do this after the handler so
2942 * they can be printed in the pager. */
2943 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2944 {
2946 b->mime_headers = tattach->parts->mime_headers;
2947 tattach->parts->mime_headers = NULL;
2948 }
2949
2950 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2951 * cache signature verification status. */
2952 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2953 {
2954 b->goodsig = tattach->goodsig;
2955 if (!b->goodsig)
2956 b->warnsig = tattach->warnsig;
2957 }
2958 else if (tattach->goodsig)
2959 {
2960 b->goodsig = true;
2961 b->warnsig = tattach->warnsig;
2962 }
2963
2964 if (state->flags & STATE_DISPLAY)
2965 {
2966 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2967 _("[-- End of S/MIME encrypted data --]\n"));
2968 }
2969
2970 mutt_body_free(&tattach);
2971 }
2972
2973 mutt_file_fclose(&fp_out);
2974 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2975
2976 return rc;
2977}
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:409
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.
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:125
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1124
#define mutt_perror(...)
Definition logging2.h:95
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1675
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 471 of file pgp.c.

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

2045{
2046 int rc = -1;
2047
2048 /* clear out any mime headers before the handler, so they can't be spoofed. */
2050
2051 struct Body *tattach = smime_handle_entity(b, state, NULL);
2052 if (tattach)
2053 {
2054 rc = 0;
2055 mutt_body_free(&tattach);
2056 }
2057 return rc;
2058}
static struct Body * smime_handle_entity(struct Body *b, struct State *state, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition smime.c:1724
Here is the call graph for this function: