1 /*
2  * e-mail-parser-application-xpkcs7mime.c
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17 
18 #include "evolution-config.h"
19 
20 #include <string.h>
21 #include <glib/gi18n-lib.h>
22 
23 #include <e-util/e-util.h>
24 
25 #include "e-mail-formatter-utils.h"
26 #include "e-mail-parser-extension.h"
27 #include "e-mail-part-utils.h"
28 
29 typedef EMailParserExtension EMailParserApplicationSMIME;
30 typedef EMailParserExtensionClass EMailParserApplicationSMIMEClass;
31 
32 GType e_mail_parser_application_smime_get_type (void);
33 
34 G_DEFINE_TYPE (
35 	EMailParserApplicationSMIME,
36 	e_mail_parser_application_smime,
37 	E_TYPE_MAIL_PARSER_EXTENSION)
38 
39 static const gchar *parser_mime_types[] = {
40 	"application/xpkcs7mime",
41 	"application/xpkcs7-mime",
42 	"application/x-pkcs7-mime",
43 	"application/pkcs7-mime",
44 	"application/pkcs7-signature",
45 	"application/xpkcs7signature",
46 	"application/xpkcs7-signature",
47 	"application/x-pkcs7-signature",
48 	NULL
49 };
50 
51 static gboolean
empe_app_smime_parse(EMailParserExtension * extension,EMailParser * parser,CamelMimePart * part,GString * part_id,GCancellable * cancellable,GQueue * out_mail_parts)52 empe_app_smime_parse (EMailParserExtension *extension,
53                       EMailParser *parser,
54                       CamelMimePart *part,
55                       GString *part_id,
56                       GCancellable *cancellable,
57                       GQueue *out_mail_parts)
58 {
59 	CamelCipherContext *context;
60 	CamelMimePart *opart;
61 	CamelCipherValidity *valid;
62 	CamelContentType *ct;
63 	gboolean is_guessed;
64 	GError *local_error = NULL;
65 
66 	ct = camel_mime_part_get_content_type (part);
67 
68 	/* When it's a guessed type, then rather not interpret it as a signed/encrypted message */
69 	is_guessed = g_strcmp0 (camel_content_type_param (ct, E_MAIL_PART_X_EVOLUTION_GUESSED), "1") == 0;
70 
71 	if (is_guessed ||
72 	    camel_content_type_is (ct, "application", "pkcs7-signature") ||
73 	    camel_content_type_is (ct, "application", "xpkcs7signature") ||
74 	    camel_content_type_is (ct, "application", "xpkcs7-signature") ||
75 	    camel_content_type_is (ct, "application", "x-pkcs7-signature")) {
76 		gboolean add_as_attachment = is_guessed;
77 
78 		if (!add_as_attachment) {
79 			EMailPartList *part_list;
80 
81 			part_list = e_mail_parser_ref_part_list_for_operation (parser, cancellable);
82 			if (part_list) {
83 				CamelMimePart *parent_part;
84 
85 				parent_part = e_mail_part_utils_find_parent_part (e_mail_part_list_get_message (part_list), part);
86 				if (parent_part) {
87 					ct = camel_mime_part_get_content_type (parent_part);
88 					add_as_attachment = !camel_content_type_is (ct, "multipart", "signed");
89 				}
90 
91 				g_object_unref (part_list);
92 			}
93 		}
94 
95 		if (add_as_attachment)
96 			e_mail_parser_wrap_as_non_expandable_attachment (parser, part, part_id, out_mail_parts);
97 
98 		return TRUE;
99 	}
100 
101 	context = camel_smime_context_new (e_mail_parser_get_session (parser));
102 
103 	opart = camel_mime_part_new ();
104 	valid = camel_cipher_context_decrypt_sync (
105 		context, part, opart,
106 		cancellable, &local_error);
107 
108 	e_mail_part_preserve_charset_in_content_type (part, opart);
109 
110 	if (local_error != NULL) {
111 		e_mail_parser_error (
112 			parser, out_mail_parts,
113 			_("Could not parse S/MIME message: %s"),
114 			local_error->message);
115 		g_error_free (local_error);
116 
117 	} else {
118 		CamelContentType *ct;
119 		GQueue work_queue = G_QUEUE_INIT;
120 		GList *head, *link;
121 		gint len = part_id->len;
122 
123 		g_string_append (part_id, ".encrypted-smime");
124 
125 		ct = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (opart));
126 
127 		if (!ct || camel_content_type_is (ct, "text", "plain")) {
128 			const gchar *mime_type;
129 
130 			mime_type = e_mail_part_snoop_type (opart);
131 
132 			if (mime_type && g_ascii_strcasecmp (mime_type, "text/plain") != 0)
133 				camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (opart), mime_type);
134 		}
135 
136 		e_mail_parser_parse_part (
137 			parser, opart, part_id, cancellable, &work_queue);
138 
139 		g_string_truncate (part_id, len);
140 
141 		head = g_queue_peek_head_link (&work_queue);
142 
143 		/* Update validity flags of all the involved subp-arts */
144 		for (link = head; link != NULL; link = g_list_next (link)) {
145 			EMailPart *mail_part = link->data;
146 
147 			e_mail_part_update_validity (
148 				mail_part, valid,
149 				E_MAIL_PART_VALIDITY_SMIME);
150 
151 			/* Do not traverse sub-messages */
152 			if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
153 				link = e_mail_formatter_find_rfc822_end_iter (link);
154 		}
155 
156 		e_queue_transfer (&work_queue, out_mail_parts);
157 
158 		/* Add a widget with details about the encryption, but only
159 		 * when the encrypted isn't itself secured, in that case it
160 		 * has created the button itself. */
161 		if (!e_mail_part_is_secured (opart)) {
162 			EMailPart *mail_part;
163 
164 			g_string_append (part_id, ".encrypted-smime.button");
165 
166 			e_mail_parser_parse_part_as (
167 				parser, part, part_id,
168 				"application/vnd.evolution.secure-button",
169 				cancellable, &work_queue);
170 
171 			mail_part = g_queue_peek_head (&work_queue);
172 
173 			if (mail_part != NULL)
174 				e_mail_part_update_validity (
175 					mail_part, valid,
176 					E_MAIL_PART_VALIDITY_SMIME);
177 
178 			e_queue_transfer (&work_queue, out_mail_parts);
179 
180 			g_string_truncate (part_id, len);
181 		}
182 
183 		camel_cipher_validity_free (valid);
184 	}
185 
186 	g_object_unref (opart);
187 	g_object_unref (context);
188 
189 	return TRUE;
190 }
191 
192 static void
e_mail_parser_application_smime_class_init(EMailParserExtensionClass * class)193 e_mail_parser_application_smime_class_init (EMailParserExtensionClass *class)
194 {
195 	class->mime_types = parser_mime_types;
196 	class->priority = G_PRIORITY_LOW;
197 	class->flags = E_MAIL_PARSER_EXTENSION_INLINE;
198 	class->parse = empe_app_smime_parse;
199 }
200 
201 static void
e_mail_parser_application_smime_init(EMailParserExtension * extension)202 e_mail_parser_application_smime_init (EMailParserExtension *extension)
203 {
204 }
205