Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 2E2736DE091F for ; Fri, 8 Jul 2016 03:15:53 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: 0.108 X-Spam-Level: X-Spam-Status: No, score=0.108 tagged_above=-999 required=5 tests=[AWL=0.108] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lcP0jSlf_7qU for ; Fri, 8 Jul 2016 03:15:45 -0700 (PDT) Received: from che.mayfirst.org (che.mayfirst.org [162.247.75.118]) by arlo.cworth.org (Postfix) with ESMTP id 8C5226DE0931 for ; Fri, 8 Jul 2016 03:13:25 -0700 (PDT) Received: from fifthhorseman.net (unknown [88.128.80.54]) by che.mayfirst.org (Postfix) with ESMTPSA id 49617F993 for ; Fri, 8 Jul 2016 06:13:24 -0400 (EDT) Received: by fifthhorseman.net (Postfix, from userid 1000) id AF49D213E0; Fri, 8 Jul 2016 11:27:34 +0200 (CEST) From: Daniel Kahn Gillmor To: Notmuch Mail Subject: [PATCH v4 09/16] index encrypted parts when asked. Date: Fri, 8 Jul 2016 11:27:20 +0200 Message-Id: <1467970047-8013-10-git-send-email-dkg@fifthhorseman.net> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net> References: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net> X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 08 Jul 2016 10:15:53 -0000 If we see index options that ask us to decrypt when indexing a message, and we encounter an encrypted part, we'll try to descend into it. If we can decrypt, we add the property index-decryption=success. If we can't decrypt (or recognize the encrypted type of mail), we add the property index-decryption=failure. Note that a single message may have both values of the "index-decryption" property: "success" and "failure". For example, consider a message that includes multiple layers of encryption. If we manage to decrypt the outer layer ("index-decryption=success"), but fail on the inner layer ("index-decryption=failure"). --- lib/database.cc | 3 ++- lib/index.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++++--- lib/notmuch-private.h | 1 + 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index 9d6b6f2..4e01f12 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -2426,6 +2426,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS, ret2; notmuch_private_status_t private_status; notmuch_bool_t is_ghost = false; + notmuch_indexopts_t *indexopts = NULL; const char *date, *header; const char *from, *to, *subject; @@ -2538,7 +2539,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch, date = _notmuch_message_file_get_header (message_file, "date"); _notmuch_message_set_header_values (message, date, from, subject); - ret = _notmuch_message_index_file (message, message_file); + ret = _notmuch_message_index_file (message, indexopts, message_file); if (ret) goto DONE; } else { diff --git a/lib/index.cc b/lib/index.cc index 1c030a6..a579c42 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -300,9 +300,14 @@ _index_address_list (notmuch_message_t *message, } } +static void +_index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, + GMimeContentType *content_type, GMimeMultipartEncrypted *part); + /* Callback to generate terms for each mime part of a message. */ static void _index_mime_part (notmuch_message_t *message, + notmuch_indexopts_t *indexopts, GMimeObject *part) { GMimeStream *stream, *filter; @@ -340,17 +345,19 @@ _index_mime_part (notmuch_message_t *message, /* FIXME: is it always just the first part that is signed in all multipart/signed messages?*/ _index_mime_part (message, + indexopts, g_mime_multipart_get_part (multipart, 0)); if (g_mime_multipart_get_count (multipart) > 2) _notmuch_database_log (_notmuch_message_database (message), "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n"); } else if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) { - /* Don't index encrypted parts */ _notmuch_message_add_term (message, "tag", "encrypted"); + _index_encrypted_mime_part(message, indexopts, content_type, GMIME_MULTIPART_ENCRYPTED (part)); } else { for (i = 0; i < g_mime_multipart_get_count (multipart); i++) { _index_mime_part (message, + indexopts, g_mime_multipart_get_part (multipart, i)); } } @@ -362,7 +369,7 @@ _index_mime_part (notmuch_message_t *message, mime_message = g_mime_message_part_get_message (GMIME_MESSAGE_PART (part)); - _index_mime_part (message, g_mime_message_get_mime_part (mime_message)); + _index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message)); return; } @@ -432,8 +439,69 @@ _index_mime_part (notmuch_message_t *message, } } +/* descend (if desired) into the cleartext part of an encrypted MIME + * part while indexing. */ +static void +_index_encrypted_mime_part (notmuch_message_t *message, + notmuch_indexopts_t *indexopts, + GMimeContentType *content_type, + GMimeMultipartEncrypted *encrypted_data) +{ + notmuch_status_t status; + GMimeCryptoContext* crypto_ctx = NULL; + const char *protocol = NULL; + GError *err = NULL; + notmuch_database_t * notmuch = NULL; + GMimeObject *clear = NULL; + + if (!indexopts || !notmuch_indexopts_get_try_decrypt (indexopts)) + return; + + protocol = g_mime_content_type_get_parameter (content_type, "protocol"); + notmuch = _notmuch_message_database (message); + + status = _notmuch_crypto_get_gmime_ctx_for_protocol (&(indexopts->crypto), + protocol, &crypto_ctx); + if (status) { + _notmuch_database_log (notmuch, "Warning: setup failed for decrypting " + "during indexing. (%d)\n", status); + status = notmuch_message_add_property (message, "index-decryption", "failure"); + if (status) + _notmuch_database_log (notmuch, "failed to add index-decryption " + "property (%d)\n", status); + return; + } + + /* we don't need the GMimeDecryptResult, because we're not looking + * at validating signatures, and we don't care about indexing who + * the message was ostensibly encrypted to. + */ + clear = g_mime_multipart_encrypted_decrypt(encrypted_data, crypto_ctx, + NULL, &err); + if (err) { + _notmuch_database_log (notmuch, "Failed to decrypt during indexing. (%d:%d) [%s]\n", + err->domain, err->code, err->message); + g_error_free(err); + /* Indicate that we failed to decrypt during indexing */ + status = notmuch_message_add_property (message, "index-decryption", "failure"); + if (status) + _notmuch_database_log (notmuch, "failed to add index-decryption " + "property (%d)\n", status); + return; + } + _index_mime_part (message, indexopts, clear); + g_object_unref (clear); + + status = notmuch_message_add_property (message, "index-decryption", "success"); + if (status) + _notmuch_database_log (notmuch, "failed to add index-decryption " + "property (%d)\n", status); + +} + notmuch_status_t _notmuch_message_index_file (notmuch_message_t *message, + notmuch_indexopts_t *indexopts, notmuch_message_file_t *message_file) { GMimeMessage *mime_message; @@ -463,7 +531,7 @@ _notmuch_message_index_file (notmuch_message_t *message, subject = g_mime_message_get_subject (mime_message); _notmuch_message_gen_terms (message, "subject", subject); - _index_mime_part (message, g_mime_message_get_mime_part (mime_message)); + _index_mime_part (message, indexopts, g_mime_message_get_mime_part (mime_message)); return NOTMUCH_STATUS_SUCCESS; } diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 8b2aede..01b65ba 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -431,6 +431,7 @@ _notmuch_message_file_get_header (notmuch_message_file_t *message, notmuch_status_t _notmuch_message_index_file (notmuch_message_t *message, + notmuch_indexopts_t *indexopts, notmuch_message_file_t *message_file); /* messages.c */ -- 2.8.1