static gboolean handle_mime_object (MuMsg *msg, GMimeObject *mobj, GMimeObject *parent, MuMsgOptions opts, unsigned *index, gboolean decrypted, MuMsgPartForeachFunc func, gpointer user_data) { if (GMIME_IS_PART (mobj)) return handle_part (msg, GMIME_PART(mobj), parent, opts, index, decrypted, func, user_data); else if (GMIME_IS_MESSAGE_PART (mobj)) return handle_message_part (msg, GMIME_MESSAGE_PART(mobj), parent, opts, index, decrypted, func, user_data); else if ((opts & MU_MSG_OPTION_VERIFY) && GMIME_IS_MULTIPART_SIGNED (mobj)) { check_signature (msg, GMIME_MULTIPART_SIGNED (mobj), opts); return handle_multipart (msg, GMIME_MULTIPART (mobj), mobj, opts, index, decrypted, func, user_data); } else if ((opts & MU_MSG_OPTION_DECRYPT) && GMIME_IS_MULTIPART_ENCRYPTED (mobj)) return handle_encrypted_part (msg, GMIME_MULTIPART_ENCRYPTED (mobj), opts, index, func, user_data); else if (GMIME_IS_MULTIPART (mobj)) return handle_multipart (msg, GMIME_MULTIPART (mobj), parent, opts, index, decrypted, func, user_data); return TRUE; }
static void process_message_callback(GMimeObject *part, gpointer user_data) { struct mime_cbinfo *cbinfo = user_data; cbinfo->count++; /* We strip off the headers before we get here, so should only see GMIME_IS_PART */ if (GMIME_IS_MESSAGE_PART(part)) { ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n"); return; } else if (GMIME_IS_MESSAGE_PARTIAL(part)) { ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n"); return; } else if (GMIME_IS_MULTIPART(part)) { GList *l; ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n"); l = GMIME_MULTIPART(part)->subparts; while (l) { process_message_callback(l->data, cbinfo); l = l->next; } } else if (GMIME_IS_PART(part)) { const char *filename; if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) { ast_debug(1, "Skipping part with no filename\n"); return; } post_raw(GMIME_PART(part), cbinfo->post_dir, filename); } else { ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n"); } }
static void write_part(GMimeObject *part) { GList *l; const GMimeContentType *ct; ct = g_mime_object_get_content_type(GMIME_OBJECT(part)); if (GMIME_IS_MULTIPART(part)) { if (g_mime_content_type_is_type(ct, "multipart", "alternative")) { choose_alternative(part); level += g_list_length(GMIME_MULTIPART(part)->subparts); } else { l = GMIME_MULTIPART(part)->subparts; while (l != NULL) { write_part(l->data); l = l->next; level++; } } } else if (GMIME_IS_MESSAGE_PART(part)) { } else if (GMIME_IS_PART(part)) { display_part(part, ct); } }
static GMimeObject* add_part_to_existing(GMimeObject* mp, GMimeObject* p) { GMimeObject* rv = mp; /* there was a previous part, switch to multipart or just add if we already switched */ /* g_debug("mp=%p (%s), p=%p (%s)", mp, G_OBJECT_TYPE_NAME(mp), p, G_OBJECT_TYPE_NAME(p)); */ if ( GMIME_IS_MULTIPART(mp) ) { g_mime_multipart_add(GMIME_MULTIPART(mp), p); } else { GMimeMultipart* mlp = g_mime_multipart_new(); g_mime_multipart_add(mlp, mp); g_mime_multipart_add(mlp, p); rv = GMIME_OBJECT(mlp); } return rv; }
static gboolean handle_encrypted_part (MuMsg *msg, GMimeMultipartEncrypted *part, MuMsgOptions opts, unsigned *index, MuMsgPartForeachFunc func, gpointer user_data) { GError *err; gboolean rv; GMimeObject *dec; MuMsgPartPasswordFunc pw_func; if (opts & MU_MSG_OPTION_CONSOLE_PASSWORD) pw_func = (MuMsgPartPasswordFunc)get_console_pw; else pw_func = NULL; err = NULL; dec = mu_msg_crypto_decrypt_part (part, opts, pw_func, NULL, &err); if (err) { g_warning ("error decrypting part: %s", err->message); g_clear_error (&err); } if (dec) { rv = handle_mime_object (msg, dec, (GMimeObject *) part, opts, index, TRUE, func, user_data); g_object_unref (dec); } else { /* On failure to decrypt, list the encrypted part as * an attachment */ GMimeObject *encrypted; encrypted = g_mime_multipart_get_part ( GMIME_MULTIPART (part), 1); g_return_val_if_fail (GMIME_IS_PART(encrypted), FALSE); rv = handle_mime_object (msg, encrypted, (GMimeObject *) part, opts, index, FALSE, func, user_data); } return rv; }
static void choose_alternative(GMimeObject *part) { GList *l, *fpart; l = GMIME_MULTIPART(part)->subparts; // Look for a preferred part in this order: // * multipart/relative // * text/html unless text_only // * text/plain if (fpart = g_list_find_custom(l, g_mime_content_type_new("multipart", "related"), (GCompareFunc)find_part_of_type)) { choose_alternative(fpart->data); return; } if ((fpart = g_list_find_custom(l, g_mime_content_type_new("text", "html"), (GCompareFunc)find_part_of_type)) && text_only == 0) { write_part(fpart->data); return; } if (fpart = g_list_find_custom(l, g_mime_content_type_new("text", "plain"), (GCompareFunc)find_part_of_type)) { write_part(fpart->data); return; } }
static void print_body (GMimeMessage *msg) { GMimeObject *body; GMimeDataWrapper *wrapper; GMimeStream *stream; body = g_mime_message_get_body (msg); if (GMIME_IS_MULTIPART(body)) body = g_mime_multipart_get_part (GMIME_MULTIPART(body), 0); if (!GMIME_IS_PART(body)) return; wrapper = g_mime_part_get_content_object (GMIME_PART(body)); if (!GMIME_IS_DATA_WRAPPER(wrapper)) return; stream = g_mime_data_wrapper_get_stream (wrapper); if (!GMIME_IS_STREAM(stream)) return; do { char buf[512]; ssize_t len; len = g_mime_stream_read (stream, buf, sizeof(buf)); if (len == -1) break; if (write (fileno(stdout), buf, len) == -1) break; if (len < (int)sizeof(buf)) break; } while (1); }
static void mime_foreach_callback (GMimeObject * parent, GMimeObject * part, gpointer user_data) { GMimeContentType *type; if (GMIME_IS_MESSAGE_PART (part)) { /* message/rfc822 or message/news */ GMimeMessage *message; /* g_mime_message_foreach_part() won't descend into child message parts, so if we want to count any subparts of this child message, we'll have to call g_mime_message_foreach_part() again here. */ rspamd_printf ("got message part %p: parent: %p\n", part, parent); message = g_mime_message_part_get_message ((GMimeMessagePart *) part); g_mime_message_foreach (message, mime_foreach_callback, part); } else if (GMIME_IS_MULTIPART (part)) { type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT ( part)); rspamd_printf ("got multipart part %p, boundary: %s: parent: %p, type: %s/%s\n", part, g_mime_multipart_get_boundary (GMIME_MULTIPART(part)), parent, g_mime_content_type_get_media_type (type), g_mime_content_type_get_media_subtype (type)); } else { type = (GMimeContentType *) g_mime_object_get_content_type (GMIME_OBJECT ( part)); rspamd_printf ("got normal part %p, parent: %p, type: %s/%s\n", part, parent, g_mime_content_type_get_media_type (type), g_mime_content_type_get_media_subtype (type)); } }
gboolean g_mime_gpgme_mps_sign(GMimeMultipartSigned * mps, GMimeObject * content, const gchar * userid, gpgme_protocol_t protocol, GtkWindow * parent, GError ** err) { GMimeStream *stream; GMimeStream *filtered; GMimeStream *sigstream; GMimeFilter *filter; GMimeContentType *content_type; GMimeDataWrapper *wrapper; GMimeParser *parser; GMimePart *signature; gchar *micalg; const gchar *proto_type; const gchar *sig_subtype; gpgme_hash_algo_t hash_algo; g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), FALSE); g_return_val_if_fail(GMIME_IS_OBJECT(content), FALSE); /* Prepare all the parts for signing... */ sign_prepare(content); /* get the cleartext */ stream = g_mime_stream_mem_new(); filtered = g_mime_stream_filter_new(stream); /* Note: see rfc3156, section 3 - second note */ filter = g_mime_filter_from_new(GMIME_FILTER_FROM_MODE_ARMOR); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); /* Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156) */ filter = g_mime_filter_strip_new(); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); g_mime_object_write_to_stream(content, filtered); g_mime_stream_flush(filtered); g_object_unref(filtered); g_mime_stream_reset(stream); /* Note: see rfc2015 or rfc3156, section 5.1 */ filtered = g_mime_stream_filter_new(stream); filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); /* construct the signature stream */ sigstream = g_mime_stream_mem_new(); /* sign the content stream */ hash_algo = libbalsa_gpgme_sign(userid, filtered, sigstream, protocol, FALSE, parent, err); g_object_unref(filtered); if (hash_algo == GPGME_MD_NONE) { g_object_unref(sigstream); g_object_unref(stream); return FALSE; } g_mime_stream_reset(sigstream); g_mime_stream_reset(stream); /* set the multipart/signed protocol and micalg */ content_type = g_mime_object_get_content_type(GMIME_OBJECT(mps)); if (protocol == GPGME_PROTOCOL_OpenPGP) { micalg = g_strdup_printf("PGP-%s", gpgme_hash_algo_name(hash_algo)); proto_type = "application/pgp-signature"; sig_subtype = "pgp-signature"; } else { micalg = g_strdup(gpgme_hash_algo_name(hash_algo)); proto_type = "application/pkcs7-signature"; sig_subtype = "pkcs7-signature"; } g_mime_content_type_set_parameter(content_type, "micalg", micalg); g_free(micalg); g_mime_content_type_set_parameter(content_type, "protocol", proto_type); g_mime_multipart_set_boundary(GMIME_MULTIPART(mps), NULL); /* construct the content part */ parser = g_mime_parser_new_with_stream(stream); content = g_mime_parser_construct_part(parser); g_object_unref(stream); g_object_unref(parser); /* construct the signature part */ signature = g_mime_part_new_with_type("application", sig_subtype); wrapper = g_mime_data_wrapper_new(); g_mime_data_wrapper_set_stream(wrapper, sigstream); g_mime_part_set_content_object(signature, wrapper); g_object_unref(sigstream); g_object_unref(wrapper); /* FIXME: temporary hack, this info should probably be set in * the CipherContext class - maybe ::sign can take/output a * GMimePart instead. */ if (protocol == GPGME_PROTOCOL_CMS) { g_mime_part_set_content_encoding(signature, GMIME_CONTENT_ENCODING_BASE64); g_mime_part_set_filename(signature, "smime.p7m"); } /* save the content and signature parts */ /* FIXME: make sure there aren't any other parts?? */ g_mime_multipart_add(GMIME_MULTIPART(mps), content); g_mime_multipart_add(GMIME_MULTIPART(mps), (GMimeObject *) signature); g_object_unref(signature); g_object_unref(content); return TRUE; }
GMimeObject * g_mime_gpgme_mpe_decrypt(GMimeMultipartEncrypted * mpe, GMimeGpgmeSigstat ** signature, GtkWindow * parent, GError ** err) { GMimeObject *decrypted, *version, *encrypted; GMimeStream *stream, *ciphertext; GMimeStream *filtered_stream; GMimeContentType *mime_type; GMimeGpgmeSigstat *sigstat; GMimeDataWrapper *wrapper; GMimeFilter *crlf_filter; GMimeParser *parser; const char *protocol; char *content_type; g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), NULL); if (signature && *signature) { g_object_unref(G_OBJECT(*signature)); *signature = NULL; } protocol = g_mime_object_get_content_type_parameter(GMIME_OBJECT(mpe), "protocol"); /* make sure the protocol is present and matches the cipher encrypt protocol */ if (!protocol || g_ascii_strcasecmp("application/pgp-encrypted", protocol) != 0) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, _ ("Cannot decrypt multipart/encrypted part: unsupported encryption protocol “%s”."), protocol ? protocol : _("(none)")); return NULL; } version = g_mime_multipart_get_part(GMIME_MULTIPART(mpe), GMIME_MULTIPART_ENCRYPTED_VERSION); /* make sure the protocol matches the version part's content-type */ content_type = g_mime_content_type_to_string(version->content_type); if (g_ascii_strcasecmp(content_type, protocol) != 0) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: content-type does not match protocol.")); g_free(content_type); return NULL; } g_free(content_type); /* get the encrypted part and check that it is of type application/octet-stream */ encrypted = g_mime_multipart_get_part(GMIME_MULTIPART(mpe), GMIME_MULTIPART_ENCRYPTED_CONTENT); mime_type = g_mime_object_get_content_type(encrypted); if (!g_mime_content_type_is_type (mime_type, "application", "octet-stream")) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: unexpected content type")); return NULL; } /* get the ciphertext stream */ wrapper = g_mime_part_get_content_object(GMIME_PART(encrypted)); ciphertext = g_mime_data_wrapper_get_decoded_stream(wrapper); g_mime_stream_reset(ciphertext); stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); /* get the cleartext */ sigstat = libbalsa_gpgme_decrypt(ciphertext, filtered_stream, GPGME_PROTOCOL_OpenPGP, parent, err); if (!sigstat) { g_object_unref(filtered_stream); g_object_unref(ciphertext); g_object_unref(stream); return NULL; } g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); g_object_unref(ciphertext); g_mime_stream_reset(stream); parser = g_mime_parser_new(); g_mime_parser_init_with_stream(parser, stream); g_object_unref(stream); decrypted = g_mime_parser_construct_part(parser); g_object_unref(parser); if (!decrypted) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: failed to parse decrypted content")); g_object_unref(G_OBJECT(sigstat)); return NULL; } /* cache the decrypted part */ if (signature) { if (sigstat->status != GPG_ERR_NOT_SIGNED) *signature = sigstat; else g_object_unref(G_OBJECT(sigstat)); } return decrypted; }
gboolean g_mime_gpgme_mpe_encrypt(GMimeMultipartEncrypted * mpe, GMimeObject * content, GPtrArray * recipients, gboolean trust_all, GtkWindow * parent, GError ** err) { GMimeStream *filtered_stream; GMimeStream *ciphertext; GMimeStream *stream; GMimePart *version_part; GMimePart *encrypted_part; GMimeDataWrapper *wrapper; GMimeFilter *crlf_filter; g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), FALSE); g_return_val_if_fail(GMIME_IS_OBJECT(content), FALSE); /* get the cleartext */ stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); g_mime_object_write_to_stream(content, filtered_stream); g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); /* reset the content stream */ g_mime_stream_reset(stream); /* encrypt the content stream */ ciphertext = g_mime_stream_mem_new(); if (!libbalsa_gpgme_encrypt (recipients, NULL, stream, ciphertext, GPGME_PROTOCOL_OpenPGP, FALSE, trust_all, parent, err)) { g_object_unref(ciphertext); g_object_unref(stream); return FALSE; } g_object_unref(stream); g_mime_stream_reset(ciphertext); /* construct the version part */ version_part = g_mime_part_new_with_type("application", "pgp-encrypted"); g_mime_part_set_content_encoding(version_part, GMIME_CONTENT_ENCODING_7BIT); stream = g_mime_stream_mem_new_with_buffer("Version: 1\n", strlen("Version: 1\n")); wrapper = g_mime_data_wrapper_new_with_stream(stream, GMIME_CONTENT_ENCODING_7BIT); g_mime_part_set_content_object(version_part, wrapper); g_object_unref(wrapper); g_object_unref(stream); /* construct the encrypted mime part */ encrypted_part = g_mime_part_new_with_type("application", "octet-stream"); g_mime_part_set_content_encoding(encrypted_part, GMIME_CONTENT_ENCODING_7BIT); wrapper = g_mime_data_wrapper_new_with_stream(ciphertext, GMIME_CONTENT_ENCODING_7BIT); g_mime_part_set_content_object(encrypted_part, wrapper); g_object_unref(ciphertext); g_object_unref(wrapper); /* save the version and encrypted parts */ /* FIXME: make sure there aren't any other parts?? */ g_mime_multipart_add(GMIME_MULTIPART(mpe), GMIME_OBJECT(version_part)); g_mime_multipart_add(GMIME_MULTIPART(mpe), GMIME_OBJECT(encrypted_part)); g_object_unref(encrypted_part); g_object_unref(version_part); /* set the content-type params for this multipart/encrypted part */ g_mime_object_set_content_type_parameter(GMIME_OBJECT(mpe), "protocol", "application/pgp-encrypted"); g_mime_multipart_set_boundary(GMIME_MULTIPART(mpe), NULL); return TRUE; }
GMimeGpgmeSigstat * g_mime_gpgme_mps_verify(GMimeMultipartSigned * mps, GError ** error) { const gchar *protocol; gpgme_protocol_t crypto_prot; gchar *content_type; GMimeObject *content; GMimeObject *signature; GMimeStream *stream; GMimeStream *filtered_stream; GMimeFilter *crlf_filter; GMimeDataWrapper *wrapper; GMimeStream *sigstream; GMimeGpgmeSigstat *result; g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), NULL); if (g_mime_multipart_get_count(GMIME_MULTIPART(mps)) < 2) { g_set_error(error, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot verify multipart/signed part due to missing subparts.")); return NULL; } /* grab the protocol so we can configure the GpgME context */ protocol = g_mime_object_get_content_type_parameter(GMIME_OBJECT(mps), "protocol"); if (protocol) { if (g_ascii_strcasecmp("application/pgp-signature", protocol) == 0) crypto_prot = GPGME_PROTOCOL_OpenPGP; else if (g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0 || g_ascii_strcasecmp("application/x-pkcs7-signature", protocol) == 0) crypto_prot = GPGME_PROTOCOL_CMS; else crypto_prot = GPGME_PROTOCOL_UNKNOWN; } else crypto_prot = GPGME_PROTOCOL_UNKNOWN; /* eject on unknown protocols */ if (crypto_prot == GPGME_PROTOCOL_UNKNOWN) { g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_INV_VALUE, _("unsupported protocol “%s”"), protocol); return NULL; } signature = g_mime_multipart_get_part(GMIME_MULTIPART(mps), GMIME_MULTIPART_SIGNED_SIGNATURE); /* make sure the protocol matches the signature content-type */ content_type = g_mime_content_type_to_string(signature->content_type); if (g_ascii_strcasecmp(content_type, protocol) != 0) { g_set_error(error, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot verify multipart/signed part: signature content-type does not match protocol.")); g_free(content_type); return NULL; } g_free(content_type); content = g_mime_multipart_get_part(GMIME_MULTIPART(mps), GMIME_MULTIPART_SIGNED_CONTENT); /* get the content stream */ stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); /* Note: see rfc2015 or rfc3156, section 5.1 */ crlf_filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); g_mime_object_write_to_stream(content, filtered_stream); g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); g_mime_stream_reset(stream); /* get the signature stream */ wrapper = g_mime_part_get_content_object(GMIME_PART(signature)); /* a s/mime signature is always encoded, a pgp signature shouldn't, * but there exist implementations which encode it... */ sigstream = g_mime_stream_mem_new(); g_mime_data_wrapper_write_to_stream(wrapper, sigstream); g_mime_stream_reset(sigstream); /* verify the signature */ result = libbalsa_gpgme_verify(stream, sigstream, crypto_prot, FALSE, error); g_object_unref(stream); g_object_unref(sigstream); return result; }