📄 crypt-gpgme.c
字号:
return NULL; } mutt_need_hard_redraw (); /* Read the output from GPGME, and make sure to change CRLF to LF, otherwise read_mime_header has a hard time parsing the message. */ if (data_object_to_stream (plaintext, fpout)) { gpgme_data_release (plaintext); gpgme_release (ctx); return NULL; } gpgme_data_release (plaintext); a->is_signed_data = 0; if (sig_stat) { int res, idx; int anybad = 0; if (maybe_signed) a->is_signed_data = 1; if(r_is_signed) *r_is_signed = -1; /* A signature exists. */ if ((s->flags & M_DISPLAY)) state_attach_puts (_("[-- Begin signature " "information --]\n"), s); for(idx = 0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) { if (res == 1) anybad = 1; else if (res == 2) anywarn = 1; } if (!anybad && idx && r_is_signed && *r_is_signed) *r_is_signed = anywarn? 2:1; /* Good signature. */ if ((s->flags & M_DISPLAY)) state_attach_puts (_("[-- End signature " "information --]\n\n"), s); } gpgme_release (ctx); ctx = NULL; fflush (fpout); rewind (fpout); tattach = mutt_read_mime_header (fpout, 0); if (tattach) { /* * Need to set the length of this body part. */ fstat (fileno (fpout), &info); tattach->length = info.st_size - tattach->offset; tattach->warnsig = anywarn; /* See if we need to recurse on this MIME part. */ mutt_parse_part (fpout, tattach); } return tattach;}/* Decrypt a PGP/MIME message in FPIN and B and return a new body and the stream in CUR and FPOUT. Returns 0 on success. */int pgp_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur){ char tempfile[_POSIX_PATH_MAX]; STATE s; BODY *first_part = b; int is_signed; first_part->goodsig = 0; first_part->warnsig = 0; if(!mutt_is_multipart_encrypted(b)) return -1; if(!b->parts || !b->parts->next) return -1; b = b->parts->next; memset (&s, 0, sizeof (s)); s.fpin = fpin; mutt_mktemp (tempfile); if (!(*fpout = safe_fopen (tempfile, "w+"))) { mutt_perror (tempfile); return -1; } unlink (tempfile); *cur = decrypt_part (b, &s, *fpout, 0, &is_signed); rewind (*fpout); if (is_signed > 0) first_part->goodsig = 1; return *cur? 0:-1;}/* Decrypt a S/MIME message in FPIN and B and return a new body and the stream in CUR and FPOUT. Returns 0 on success. */int smime_gpgme_decrypt_mime (FILE *fpin, FILE **fpout, BODY *b, BODY **cur){ char tempfile[_POSIX_PATH_MAX]; STATE s; FILE *tmpfp=NULL; int is_signed; LOFF_T saved_b_offset; size_t saved_b_length; int saved_b_type; if (!mutt_is_application_smime (b)) return -1; if (b->parts) return -1; /* Decode the body - we need to pass binary CMS to the backend. The backend allows for Base64 encoded data but it does not allow for QP which I have seen in some messages. So better do it here. */ saved_b_type = b->type; saved_b_offset = b->offset; saved_b_length = b->length; memset (&s, 0, sizeof (s)); s.fpin = fpin; fseeko (s.fpin, b->offset, 0); mutt_mktemp (tempfile); if (!(tmpfp = safe_fopen (tempfile, "w+"))) { mutt_perror (tempfile); return -1; } mutt_unlink (tempfile); s.fpout = tmpfp; mutt_decode_attachment (b, &s); fflush (tmpfp); b->length = ftello (s.fpout); b->offset = 0; rewind (tmpfp); memset (&s, 0, sizeof (s)); s.fpin = tmpfp; s.fpout = 0; mutt_mktemp (tempfile); if (!(*fpout = safe_fopen (tempfile, "w+"))) { mutt_perror (tempfile); return -1; } mutt_unlink (tempfile); *cur = decrypt_part (b, &s, *fpout, 1, &is_signed); if (*cur) (*cur)->goodsig = is_signed > 0; b->type = saved_b_type; b->length = saved_b_length; b->offset = saved_b_offset; fclose (tmpfp); rewind (*fpout); if (*cur && !is_signed && !(*cur)->parts && mutt_is_application_smime (*cur)) { /* Assume that this is a opaque signed s/mime message. This is an ugly way of doing it but we have anyway a problem with arbitrary encoded S/MIME messages: Only the outer part may be encrypted. The entire mime parsing should be revamped, probably by keeping the temportary files so that we don't need to decrypt them all the time. Inner parts of an encrypted part can then pint into this file and tehre won't never be a need to decrypt again. This needs a partial rewrite of the MIME engine. */ BODY *bb = *cur; BODY *tmp_b; saved_b_type = bb->type; saved_b_offset = bb->offset; saved_b_length = bb->length; memset (&s, 0, sizeof (s)); s.fpin = *fpout; fseeko (s.fpin, bb->offset, 0); mutt_mktemp (tempfile); if (!(tmpfp = safe_fopen (tempfile, "w+"))) { mutt_perror (tempfile); return -1; } mutt_unlink (tempfile); s.fpout = tmpfp; mutt_decode_attachment (bb, &s); fflush (tmpfp); bb->length = ftello (s.fpout); bb->offset = 0; rewind (tmpfp); fclose (*fpout); memset (&s, 0, sizeof (s)); s.fpin = tmpfp; s.fpout = 0; mutt_mktemp (tempfile); if (!(*fpout = safe_fopen (tempfile, "w+"))) { mutt_perror (tempfile); return -1; } mutt_unlink (tempfile); tmp_b = decrypt_part (bb, &s, *fpout, 1, &is_signed); if (tmp_b) tmp_b->goodsig = is_signed > 0; bb->type = saved_b_type; bb->length = saved_b_length; bb->offset = saved_b_offset; fclose (tmpfp); rewind (*fpout); mutt_free_body (cur); *cur = tmp_b; } return *cur? 0:-1;}/* * Implementation of `pgp_check_traditional'. */static int pgp_check_traditional_one_body (FILE *fp, BODY *b, int tagged_only){ char tempfile[_POSIX_PATH_MAX]; char buf[HUGE_STRING]; FILE *tfp; short sgn = 0; short enc = 0; if (b->type != TYPETEXT) return 0; if (tagged_only && !b->tagged) return 0; mutt_mktemp (tempfile); if (mutt_decode_save_attachment (fp, b, tempfile, 0, 0) != 0) { unlink (tempfile); return 0; } if ((tfp = fopen (tempfile, "r")) == NULL) { unlink (tempfile); return 0; } while (fgets (buf, sizeof (buf), tfp)) { if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) { if (!mutt_strcmp ("MESSAGE-----\n", buf + 15)) enc = 1; else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15)) sgn = 1; } } safe_fclose (&tfp); unlink (tempfile); if (!enc && !sgn) return 0; /* fix the content type */ mutt_set_parameter ("format", "fixed", &b->parameter); mutt_set_parameter ("x-action", enc ? "pgp-encrypted" : "pgp-signed", &b->parameter); return 1;}int pgp_gpgme_check_traditional (FILE *fp, BODY *b, int tagged_only){ int rv = 0; int r; for (; b; b = b->next) { if (is_multipart (b)) rv = (pgp_gpgme_check_traditional (fp, b->parts, tagged_only) || rv); else if (b->type == TYPETEXT) { if ((r = mutt_is_application_pgp (b))) rv = (rv || r); else rv = (pgp_check_traditional_one_body (fp, b, tagged_only) || rv); } } return rv;}/* * Implementation of `application_handler'. *//* Copy a clearsigned message, and strip the signature and PGP's dash-escaping. XXX - charset handling: We assume that it is safe to do character set decoding first, dash decoding second here, while we do it the other way around in the main handler. (Note that we aren't worse than Outlook & Cie in this, and also note that we can successfully handle anything produced by any existing versions of mutt.) */static void copy_clearsigned (gpgme_data_t data, STATE *s, char *charset){ char buf[HUGE_STRING]; short complete, armor_header; FGETCONV *fc; char *fname; FILE *fp; fname = data_object_to_tempfile (data, &fp); if (!fname) return; unlink (fname); FREE (&fname); fc = fgetconv_open (fp, charset, Charset, M_ICONV_HOOK_FROM); for (complete = 1, armor_header = 1; fgetconvs (buf, sizeof (buf), fc) != NULL; complete = strchr (buf, '\n') != NULL) { if (!complete) { if (!armor_header) state_puts (buf, s); continue; } if (!mutt_strcmp (buf, "-----BEGIN PGP SIGNATURE-----\n")) break; if (armor_header) { if (buf[0] == '\n') armor_header = 0; continue; } if (s->prefix) state_puts (s->prefix, s); if (buf[0] == '-' && buf[1] == ' ') state_puts (buf + 2, s); else state_puts (buf, s); } fgetconv_close (&fc); fclose (fp);}/* Support for classic_application/pgp */int pgp_gpgme_application_handler (BODY *m, STATE *s){ int needpass = -1, pgp_keyblock = 0; int clearsign = 0; long start_pos = 0; long bytes; LOFF_T last_pos, offset; char buf[HUGE_STRING]; FILE *pgpout = NULL; gpgme_error_t err = 0; gpgme_data_t armored_data = NULL; short maybe_goodsig = 1; short have_any_sigs = 0; char body_charset[STRING]; /* Only used for clearsigned messages. */ dprint (2, (debugfile, "Entering pgp_application_pgp handler\n")); /* For clearsigned messages we won't be able to get a character set but we know that this may only be text thus we assume Latin-1 here. */ if (!mutt_get_body_charset (body_charset, sizeof (body_charset), m)) strfcpy (body_charset, "iso-8859-1", sizeof body_charset); fseeko (s->fpin, m->offset, 0); last_pos = m->offset; for (bytes = m->length; bytes > 0;) { if (fgets (buf, sizeof (buf), s->fpin) == NULL) break; offset = ftello (s->fpin); bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */ last_pos = offset; if (!mutt_strncmp ("-----BEGIN PGP ", buf, 15)) { clearsign = 0; start_pos = last_pos; if (!mutt_strcmp ("MESSAGE-----\n", buf + 15)) needpass = 1; else if (!mutt_strcmp ("SIGNED MESSAGE-----\n", buf + 15)) { clearsign = 1; needpass = 0; } else if (!option (OPTDONTHANDLEPGPKEYS) && !mutt_strcmp ("PUBLIC KEY BLOCK-----\n", buf + 15)) { needpass = 0; pgp_keyblock =1; } else { /* XXX - we may wish to recode here */ if (s->prefix) state_puts (s->prefix, s); state_puts (buf, s); continue; } have_any_sigs = (have_any_sigs || (clearsign && (s->flags & M_VERIFY))); /* Copy PGP material to an data container */ armored_data = create_gpgme_data (); gpgme_data_write (armored_data, buf, strlen (buf)); while (bytes > 0 && fgets (buf, sizeof (buf) - 1, s->fpin) != NULL) { offset = ftello (s->fpin); bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf)*/ last_pos = offset; gpgme_data_write (armored_data, buf, strlen (buf)); if ((needpass && !mutt_strcmp ("-----END PGP MESSAGE-----\n", buf)) || (!needpass && (!mutt_strcmp ("-----END PGP SIGNATURE-----\n", buf) || !mutt_strcmp ( "-----END PGP PUBLIC KEY BLOCK-----\n",buf)))) break; } /* Invoke PGP if needed */ if (!clearsign || (s->flags & M_VERIFY)) { unsigned int sig_stat = 0; gpgme_data_t plaintext; gpgme_ctx_t ctx; plaintext = create_gpgme_data (); ctx = create_gpgme_context (0); if (clearsign) err = gpgme_op_verify (ctx, armored_data, NULL, plaintext); else { err = gpgme_op_decrypt_verify (ctx, armored_data, plaintext); if (gpg_err_code (err) == GPG_ERR_NO_DATA) { /* Decrypt verify can't handle signed only messages. */ err = (gpgme_data_seek (armored_data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno (errno) : 0; /* Must release plaintext so that we supply an uninitialized object. */ gpgme_data_release (plaintext); plaintext = create_gpgme_data (); err = gpgme_op_verify (ctx, armored_data, NULL, plaintext); } } if (err) { char errbuf[200]; snprintf (errbuf, sizeof(errbuf)-1, _("Error: decryption/verification failed: %s\n"), gpgme_strerror (err)); state_attach_puts (errbuf, s); } else { /* Decryption/Verification succeeded */ char *tmpfname; { /* Check wether signatures have been verified. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -