/** * crypt_query - Check out the type of encryption used * @param m Body of email * @retval num Flags, see #SecurityFlags * @retval 0 Error (#SEC_NO_FLAGS) * * Set the cached status values if there are any. */ SecurityFlags crypt_query(struct Body *m) { if (!WithCrypto || !m) return SEC_NO_FLAGS; SecurityFlags rc = SEC_NO_FLAGS; if (m->type == TYPE_APPLICATION) { if (WithCrypto & APPLICATION_PGP) rc |= mutt_is_application_pgp(m); if (WithCrypto & APPLICATION_SMIME) { rc |= mutt_is_application_smime(m); if (rc && m->goodsig) rc |= SEC_GOODSIGN; if (rc && m->badsig) rc |= SEC_BADSIGN; } } else if (((WithCrypto & APPLICATION_PGP) != 0) && (m->type == TYPE_TEXT)) { rc |= mutt_is_application_pgp(m); if (rc && m->goodsig) rc |= SEC_GOODSIGN; } if (m->type == TYPE_MULTIPART) { rc |= mutt_is_multipart_encrypted(m); rc |= mutt_is_multipart_signed(m); rc |= mutt_is_malformed_multipart_pgp_encrypted(m); if (rc && m->goodsig) rc |= SEC_GOODSIGN; } if ((m->type == TYPE_MULTIPART) || (m->type == TYPE_MESSAGE)) { SecurityFlags u = m->parts ? SEC_ALL_FLAGS : 0; /* Bits set in all parts */ SecurityFlags w = SEC_NO_FLAGS; /* Bits set in any part */ for (struct Body *b = m->parts; b; b = b->next) { const SecurityFlags v = crypt_query(b); u &= v; w |= v; } rc |= u | (w & ~SEC_GOODSIGN); if ((w & SEC_GOODSIGN) && !(u & SEC_GOODSIGN)) rc |= SEC_PARTSIGN; } return rc; }
int mutt_prepare_template (FILE *fp, CONTEXT *ctx, HEADER *newhdr, HEADER *hdr, short weed) { MESSAGE *msg = NULL; char file[_POSIX_PATH_MAX]; BODY *b; FILE *bfp; int rv = -1; STATE s; memset (&s, 0, sizeof (s)); if (!fp && (msg = mx_open_message (ctx, hdr->msgno)) == NULL) return (-1); if (!fp) fp = msg->fp; bfp = fp; /* parse the message header and MIME structure */ fseeko (fp, hdr->offset, 0); newhdr->offset = hdr->offset; newhdr->env = mutt_read_rfc822_header (fp, newhdr, 1, weed); newhdr->content->length = hdr->content->length; mutt_parse_part (fp, newhdr->content); /* If message_id is set, then we are resending a message and don't want * message_id or mail_followup_to. Otherwise, we are resuming a * postponed message, and want to keep the mail_followup_to. */ if (newhdr->env->message_id != NULL) { FREE (&newhdr->env->message_id); FREE (&newhdr->env->mail_followup_to); } /* decrypt pgp/mime encoded messages */ if ((WithCrypto & (APPLICATION_PGP|APPLICATION_SMIME) & hdr->security) && mutt_is_multipart_encrypted (newhdr->content)) { int ccap = WithCrypto & (APPLICATION_PGP|APPLICATION_SMIME) & hdr->security; newhdr->security |= ENCRYPT | ccap; if (!crypt_valid_passphrase (ccap)) goto err; mutt_message _("Decrypting message..."); if (((ccap & APPLICATION_PGP) && crypt_pgp_decrypt_mime (fp, &bfp, newhdr->content, &b) == -1) || ((ccap & APPLICATION_SMIME) && crypt_smime_decrypt_mime (fp, &bfp, newhdr->content, &b) == -1) || b == NULL) { err: mx_close_message (&msg); mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); mutt_error _("Decryption failed."); return -1; } mutt_free_body (&newhdr->content); newhdr->content = b; mutt_clear_error (); } /* * remove a potential multipart/signed layer - useful when * resending messages */ if (WithCrypto && mutt_is_multipart_signed (newhdr->content)) { newhdr->security |= SIGN; if ((WithCrypto & APPLICATION_PGP) && ascii_strcasecmp (mutt_get_parameter ("protocol", newhdr->content->parameter), "application/pgp-signature") == 0) newhdr->security |= APPLICATION_PGP; else if ((WithCrypto & APPLICATION_SMIME)) newhdr->security |= APPLICATION_SMIME; /* destroy the signature */ mutt_free_body (&newhdr->content->parts->next); newhdr->content = mutt_remove_multipart (newhdr->content); } /* * We don't need no primary multipart. * Note: We _do_ preserve messages! * * XXX - we don't handle multipart/alternative in any * smart way when sending messages. However, one may * consider this a feature. * */ if (newhdr->content->type == TYPEMULTIPART) newhdr->content = mutt_remove_multipart (newhdr->content); s.fpin = bfp; /* create temporary files for all attachments */ for (b = newhdr->content; b; b = b->next) { /* what follows is roughly a receive-mode variant of * mutt_get_tmp_attachment () from muttlib.c */ file[0] = '\0'; if (b->filename) { strfcpy (file, b->filename, sizeof (file)); b->d_filename = safe_strdup (b->filename); } else { /* avoid Content-Disposition: header with temporary filename */ b->use_disp = 0; } /* set up state flags */ s.flags = 0; if (b->type == TYPETEXT) { if (!ascii_strcasecmp ("yes", mutt_get_parameter ("x-mutt-noconv", b->parameter))) b->noconv = 1; else { s.flags |= M_CHARCONV; b->noconv = 0; } mutt_delete_parameter ("x-mutt-noconv", &b->parameter); } mutt_adv_mktemp (file, sizeof(file)); if ((s.fpout = safe_fopen (file, "w")) == NULL) goto bail; if ((WithCrypto & APPLICATION_PGP) && (mutt_is_application_pgp (b) & (ENCRYPT|SIGN))) { mutt_body_handler (b, &s); newhdr->security |= mutt_is_application_pgp (newhdr->content); b->type = TYPETEXT; mutt_str_replace (&b->subtype, "plain"); mutt_delete_parameter ("x-action", &b->parameter); } else mutt_decode_attachment (b, &s); if (safe_fclose (&s.fpout) != 0) goto bail; mutt_str_replace (&b->filename, file); b->unlink = 1; mutt_stamp_attachment (b); mutt_free_body (&b->parts); if (b->hdr) b->hdr->content = NULL; /* avoid dangling pointer */ } /* Fix encryption flags. */ /* No inline if multipart. */ if (WithCrypto && (newhdr->security & INLINE) && newhdr->content->next) newhdr->security &= ~INLINE; /* Do we even support multiple mechanisms? */ newhdr->security &= WithCrypto | ~(APPLICATION_PGP|APPLICATION_SMIME); /* Theoretically, both could be set. Take the one the user wants to set by default. */ if ((newhdr->security & APPLICATION_PGP) && (newhdr->security & APPLICATION_SMIME)) { if (option (OPTSMIMEISDEFAULT)) newhdr->security &= ~APPLICATION_PGP; else newhdr->security &= ~APPLICATION_SMIME; } rv = 0; bail: /* that's it. */ if (bfp != fp) safe_fclose (&bfp); if (msg) mx_close_message (&msg); if (rv == -1) { mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); } return rv; }
/** * mutt_signed_handler - Verify a "multipart/signed" body - Implements ::handler_t */ int mutt_signed_handler(struct Body *a, struct State *s) { bool inconsistent = false; struct Body *b = a; struct Body **signatures = NULL; int sigcnt = 0; int rc = 0; if (!WithCrypto) return -1; a = a->parts; SecurityFlags signed_type = mutt_is_multipart_signed(b); if (signed_type == SEC_NO_FLAGS) { /* A null protocol value is already checked for in mutt_body_handler() */ state_printf(s, _("[-- Error: " "Unknown multipart/signed protocol %s --]\n\n"), mutt_param_get(&b->parameter, "protocol")); return mutt_body_handler(a, s); } if (!(a && a->next)) inconsistent = true; else { switch (signed_type) { case SEC_SIGN: if ((a->next->type != TYPE_MULTIPART) || (mutt_str_strcasecmp(a->next->subtype, "mixed") != 0)) { inconsistent = true; } break; case PGP_SIGN: if ((a->next->type != TYPE_APPLICATION) || (mutt_str_strcasecmp(a->next->subtype, "pgp-signature") != 0)) { inconsistent = true; } break; case SMIME_SIGN: if ((a->next->type != TYPE_APPLICATION) || ((mutt_str_strcasecmp(a->next->subtype, "x-pkcs7-signature") != 0) && (mutt_str_strcasecmp(a->next->subtype, "pkcs7-signature") != 0))) { inconsistent = true; } break; default: inconsistent = true; } } if (inconsistent) { state_attach_puts(_("[-- Error: " "Missing or bad-format multipart/signed signature" " --]\n\n"), s); return mutt_body_handler(a, s); } if (s->flags & MUTT_DISPLAY) { crypt_fetch_signatures(&signatures, a->next, &sigcnt); if (sigcnt) { char tempfile[PATH_MAX]; mutt_mktemp(tempfile, sizeof(tempfile)); bool goodsig = true; if (crypt_write_signed(a, s, tempfile) == 0) { for (int i = 0; i < sigcnt; i++) { if (((WithCrypto & APPLICATION_PGP) != 0) && (signatures[i]->type == TYPE_APPLICATION) && (mutt_str_strcasecmp(signatures[i]->subtype, "pgp-signature") == 0)) { if (crypt_pgp_verify_one(signatures[i], s, tempfile) != 0) goodsig = false; continue; } if (((WithCrypto & APPLICATION_SMIME) != 0) && (signatures[i]->type == TYPE_APPLICATION) && ((mutt_str_strcasecmp(signatures[i]->subtype, "x-pkcs7-signature") == 0) || (mutt_str_strcasecmp(signatures[i]->subtype, "pkcs7-signature") == 0))) { if (crypt_smime_verify_one(signatures[i], s, tempfile) != 0) goodsig = false; continue; } state_printf(s, _("[-- Warning: " "We can't verify %s/%s signatures. --]\n\n"), TYPE(signatures[i]), signatures[i]->subtype); } } mutt_file_unlink(tempfile); b->goodsig = goodsig; b->badsig = !goodsig; /* Now display the signed body */ state_attach_puts(_("[-- The following data is signed --]\n\n"), s); mutt_protected_headers_handler(a, s); FREE(&signatures); } else state_attach_puts(_("[-- Warning: Can't find any signatures. --]\n\n"), s); } rc = mutt_body_handler(a, s); if (s->flags & MUTT_DISPLAY && sigcnt) state_attach_puts(_("\n[-- End of signed data --]\n"), s); return rc; }
int mutt_prepare_template (FILE *fp, CONTEXT *ctx, HEADER *newhdr, HEADER *hdr, short weed) { MESSAGE *msg = NULL; char file[_POSIX_PATH_MAX]; LIST *p, **q; BODY *b; FILE *bfp; if (!fp && (msg = mx_open_message (ctx, hdr->msgno)) == NULL) return (-1); if (!fp) fp = msg->fp; bfp = fp; /* parse the message header and MIME structure */ fseek (fp, hdr->offset, 0); newhdr->offset = hdr->offset; newhdr->env = mutt_read_rfc822_header (fp, newhdr, 1, weed); newhdr->content->length = hdr->content->length; mutt_parse_part (fp, newhdr->content); /* weed user-agent, x-mailer - we don't want them here */ p = newhdr->env->userhdrs; q = &newhdr->env->userhdrs; while (p) { if (!strncasecmp (p->data, "x-mailer:", 9) || !strncasecmp (p->data, "user-agent:", 11)) { *q = p->next; p->next = NULL; mutt_free_list (&p); } else q = &p->next; p = *q; } safe_free ((void **) &newhdr->env->message_id); safe_free ((void **) &newhdr->env->mail_followup_to); #ifdef HAVE_PGP /* decrypt pgp/mime encoded messages */ if ((hdr->pgp & PGPENCRYPT) && mutt_is_multipart_encrypted (newhdr->content)) { newhdr->pgp |= PGPENCRYPT; if (!pgp_valid_passphrase()) goto err; mutt_message _("Invoking PGP..."); if (pgp_decrypt_mime (fp, &bfp, newhdr->content, &b) == -1) { err: mx_close_message (&msg); mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); return -1; } mutt_free_body (&newhdr->content); newhdr->content = b; mutt_clear_error (); } /* * remove a potential multipart/signed layer - useful when * resending messages */ if (mutt_is_multipart_signed (newhdr->content)) { newhdr->pgp |= PGPSIGN; /* destroy the signature */ mutt_free_body (&newhdr->content->parts->next); newhdr->content = mutt_remove_multipart (newhdr->content); } #endif /* * We don't need no primary multipart. * Note: We _do_ preserve messages! * * XXX - we don't handle multipart/alternative in any * smart way when sending messages. However, one may * consider this a feature. * */ if (newhdr->content->type == TYPEMULTIPART) newhdr->content = mutt_remove_multipart (newhdr->content); /* create temporary files for all attachments */ for (b = newhdr->content; b; b = b->next) { /* what follows is roughly a receive-mode variant of * mutt_get_tmp_attachment () from muttlib.c */ file[0] = '\0'; if (b->filename) { strfcpy (file, b->filename, sizeof (file)); b->d_filename = safe_strdup (b->filename); } else /* avoid Content-Disposition: header with temporary filename */ b->use_disp = 0; mutt_adv_mktemp (file, sizeof(file)); if (mutt_save_attachment (bfp, b, file, 0, NULL) == -1) { mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); if (bfp != fp) fclose (bfp); if (msg) mx_close_message (&msg); return -1; } mutt_str_replace (&b->filename, file); b->unlink = 1; if (mutt_is_text_type (b->type, b->subtype)) b->noconv = 1; mutt_stamp_attachment (b); mutt_free_body (&b->parts); if (b->hdr) b->hdr->content = NULL; /* avoid dangling pointer */ } /* that's it. */ if (bfp != fp) fclose (bfp); if (msg) mx_close_message (&msg); return 0; }