/** * 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_is_valid_multipart_pgp_encrypted (BODY *b) { if (! mutt_is_multipart_encrypted (b)) return 0; b = b->parts; if (!b || b->type != TYPEAPPLICATION || !b->subtype || ascii_strcasecmp (b->subtype, "pgp-encrypted")) return 0; b = b->next; if (!b || b->type != TYPEAPPLICATION || !b->subtype || ascii_strcasecmp (b->subtype, "octet-stream")) return 0; return PGPENCRYPT; }
static void set_copy_flags (HEADER *hdr, int decode, int decrypt, int *cmflags, int *chflags) { *cmflags = 0; *chflags = CH_UPDATE_LEN; if (WithCrypto && !decode && decrypt && (hdr->security & ENCRYPT)) { if ((WithCrypto & APPLICATION_PGP) && mutt_is_multipart_encrypted(hdr->content)) { *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME; *cmflags = M_CM_DECODE_PGP; } else if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (hdr->content) & ENCRYPT) decode = 1; else if ((WithCrypto & APPLICATION_SMIME) && mutt_is_application_smime(hdr->content) & ENCRYPT) { *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME; *cmflags = M_CM_DECODE_SMIME; } } if (decode) { *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN; *cmflags = M_CM_DECODE | M_CM_CHARCONV; if (!decrypt) /* If decode doesn't kick in for decrypt, */ { *chflags |= CH_DECODE; /* then decode RFC 2047 headers, */ if (option (OPTWEED)) { *chflags |= CH_WEED; /* and respect $weed. */ *cmflags |= M_CM_WEED; } } } }
/** * mutt_is_valid_multipart_pgp_encrypted - Is this a valid multi-part encrypted message? * @param b Body of email * @retval >0 Message is valid, with encrypted parts, e.g. #PGP_ENCRYPT * @retval 0 Message hasn't got encrypted parts */ int mutt_is_valid_multipart_pgp_encrypted(struct Body *b) { if (mutt_is_multipart_encrypted(b) == SEC_NO_FLAGS) return 0; b = b->parts; if (!b || (b->type != TYPE_APPLICATION) || !b->subtype || (mutt_str_strcasecmp(b->subtype, "pgp-encrypted") != 0)) { return 0; } b = b->next; if (!b || (b->type != TYPE_APPLICATION) || !b->subtype || (mutt_str_strcasecmp(b->subtype, "octet-stream") != 0)) { return 0; } return PGP_ENCRYPT; }
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; }
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; }