author | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
commit | 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (unidiff) | |
tree | 2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/engine/mailprivacy_gnupg.c | |
parent | 9319998f20f03dcc217fbb39656755dc65226276 (diff) | |
download | kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2 |
Initial revision
Diffstat (limited to 'libetpan/src/engine/mailprivacy_gnupg.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libetpan/src/engine/mailprivacy_gnupg.c | 2614 |
1 files changed, 2614 insertions, 0 deletions
diff --git a/libetpan/src/engine/mailprivacy_gnupg.c b/libetpan/src/engine/mailprivacy_gnupg.c new file mode 100644 index 0000000..01dcc80 --- a/dev/null +++ b/libetpan/src/engine/mailprivacy_gnupg.c | |||
@@ -0,0 +1,2614 @@ | |||
1 | /* | ||
2 | * libEtPan! -- a mail library | ||
3 | * | ||
4 | * Copyright (C) 2001, 2005 - DINH Viet Hoa | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * 3. Neither the name of the libEtPan! project nor the names of its | ||
16 | * contributors may be used to endorse or promote products derived | ||
17 | * from this software without specific prior written permission. | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE | ||
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
29 | * SUCH DAMAGE. | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * $Id$ | ||
34 | */ | ||
35 | |||
36 | #include "mailprivacy_gnupg.h" | ||
37 | |||
38 | #include "mailprivacy.h" | ||
39 | #include <sys/types.h> | ||
40 | #include <sys/stat.h> | ||
41 | #include <fcntl.h> | ||
42 | #include <unistd.h> | ||
43 | #include <sys/mman.h> | ||
44 | #include <string.h> | ||
45 | #include <sys/wait.h> | ||
46 | #include <stdlib.h> | ||
47 | #include "mailprivacy_tools.h" | ||
48 | #include <libetpan/mailmime.h> | ||
49 | #include <libetpan/libetpan-config.h> | ||
50 | |||
51 | static int pgp_is_encrypted(struct mailmime * mime) | ||
52 | { | ||
53 | if (mime->mm_content_type != NULL) { | ||
54 | clistiter * cur; | ||
55 | |||
56 | if (strcasecmp(mime->mm_content_type->ct_subtype, "encrypted") != 0) | ||
57 | return 0; | ||
58 | |||
59 | for(cur = clist_begin(mime->mm_content_type->ct_parameters) ; cur != NULL ; | ||
60 | cur = clist_next(cur)) { | ||
61 | struct mailmime_parameter * param; | ||
62 | |||
63 | param = clist_content(cur); | ||
64 | |||
65 | if ((strcasecmp(param->pa_name, "protocol") == 0) && | ||
66 | (strcasecmp(param->pa_value, "application/pgp-encrypted") == 0)) | ||
67 | return 1; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int pgp_is_signed(struct mailmime * mime) | ||
75 | { | ||
76 | if (mime->mm_content_type != NULL) { | ||
77 | clistiter * cur; | ||
78 | |||
79 | if (strcasecmp(mime->mm_content_type->ct_subtype, "signed") != 0) | ||
80 | return 0; | ||
81 | |||
82 | for(cur = clist_begin(mime->mm_content_type->ct_parameters) ; | ||
83 | cur != NULL ; cur = clist_next(cur)) { | ||
84 | struct mailmime_parameter * param; | ||
85 | |||
86 | param = clist_content(cur); | ||
87 | |||
88 | if ((strcasecmp(param->pa_name, "protocol") == 0) && | ||
89 | (strcasecmp(param->pa_value, "application/pgp-signature") == 0)) | ||
90 | return 1; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | #define PGP_SIGNED "-----BEGIN PGP SIGNED MESSAGE-----" | ||
98 | |||
99 | int pgp_is_clearsigned(char * data, size_t len) | ||
100 | { | ||
101 | if (len >= strlen(PGP_SIGNED)) | ||
102 | if (strncmp(data, PGP_SIGNED, sizeof(PGP_SIGNED) - 1) == 0) | ||
103 | return 1; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | #define PGP_CRYPTED "-----BEGIN PGP MESSAGE-----" | ||
109 | |||
110 | int pgp_is_crypted_armor(char * data, size_t len) | ||
111 | { | ||
112 | if (len >= strlen(PGP_CRYPTED)) | ||
113 | if (strncmp(data, PGP_CRYPTED, sizeof(PGP_CRYPTED) - 1) == 0) | ||
114 | return 1; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | |||
120 | #define BUF_SIZE 1024 | ||
121 | |||
122 | enum { | ||
123 | NO_ERROR_PGP = 0, | ||
124 | ERROR_PGP_CHECK, | ||
125 | ERROR_PGP_COMMAND, | ||
126 | ERROR_PGP_FILE, | ||
127 | }; | ||
128 | |||
129 | /* write output to a file */ | ||
130 | |||
131 | static int get_pgp_output(FILE * dest_f, char * command) | ||
132 | { | ||
133 | FILE * p; | ||
134 | char buf[BUF_SIZE]; | ||
135 | size_t size; | ||
136 | int res; | ||
137 | int status; | ||
138 | char command_redirected[PATH_MAX]; | ||
139 | |||
140 | snprintf(command_redirected, sizeof(command_redirected), "%s 2>&1", command); | ||
141 | |||
142 | /* | ||
143 | flush buffer so that it is not flushed more than once when forking | ||
144 | */ | ||
145 | fflush(dest_f); | ||
146 | |||
147 | p = popen(command_redirected, "r"); | ||
148 | if (p == NULL) { | ||
149 | res = ERROR_PGP_COMMAND; | ||
150 | goto err; | ||
151 | } | ||
152 | |||
153 | while ((size = fread(buf, 1, sizeof(buf), p)) != 0) { | ||
154 | size_t written; | ||
155 | |||
156 | written = fwrite(buf, 1, size, dest_f); | ||
157 | if (written != size) { | ||
158 | res = ERROR_PGP_FILE; | ||
159 | goto close; | ||
160 | } | ||
161 | } | ||
162 | status = pclose(p); | ||
163 | |||
164 | if (WEXITSTATUS(status) != 0) | ||
165 | return ERROR_PGP_CHECK; | ||
166 | else | ||
167 | return NO_ERROR_PGP; | ||
168 | |||
169 | close: | ||
170 | pclose(p); | ||
171 | err: | ||
172 | return res; | ||
173 | } | ||
174 | |||
175 | #define PGP_DECRYPT_DESCRIPTION "PGP encrypted part\r\n" | ||
176 | #define PGP_DECRYPT_FAILED "PGP decryption FAILED\r\n" | ||
177 | #define PGP_DECRYPT_SUCCESS "PGP decryption success\r\n" | ||
178 | |||
179 | /* extracted from mailprivacy_smime.c -- begin */ | ||
180 | |||
181 | static char * get_first_from_addr(struct mailmime * mime) | ||
182 | { | ||
183 | clistiter * cur; | ||
184 | struct mailimf_single_fields single_fields; | ||
185 | struct mailimf_fields * fields; | ||
186 | struct mailimf_mailbox * mb; | ||
187 | |||
188 | if (mime->mm_type != MAILMIME_MESSAGE) | ||
189 | return NULL; | ||
190 | |||
191 | fields = mime->mm_data.mm_message.mm_fields; | ||
192 | if (fields == NULL) | ||
193 | return NULL; | ||
194 | |||
195 | mailimf_single_fields_init(&single_fields, fields); | ||
196 | |||
197 | if (single_fields.fld_from == NULL) | ||
198 | return NULL; | ||
199 | |||
200 | cur = clist_begin(single_fields.fld_from->frm_mb_list->mb_list); | ||
201 | if (cur == NULL) | ||
202 | return NULL; | ||
203 | |||
204 | mb = clist_content(cur); | ||
205 | |||
206 | return mb->mb_addr_spec; | ||
207 | } | ||
208 | |||
209 | /* extracted from mailprivacy_smime.c -- end */ | ||
210 | |||
211 | static int pgp_decrypt(struct mailprivacy * privacy, | ||
212 | mailmessage * msg, | ||
213 | struct mailmime * mime, struct mailmime ** result) | ||
214 | { | ||
215 | char default_key[PATH_MAX]; | ||
216 | struct mailmime * version_mime; | ||
217 | struct mailmime * encrypted_mime; | ||
218 | clistiter * cur; | ||
219 | char encrypted_filename[PATH_MAX]; | ||
220 | char description_filename[PATH_MAX]; | ||
221 | FILE * description_f; | ||
222 | char decrypted_filename[PATH_MAX]; | ||
223 | FILE * decrypted_f; | ||
224 | char command[PATH_MAX]; | ||
225 | struct mailmime * description_mime; | ||
226 | struct mailmime * decrypted_mime; | ||
227 | int r; | ||
228 | int res; | ||
229 | int decrypt_ok; | ||
230 | char quoted_decrypted_filename[PATH_MAX]; | ||
231 | char quoted_encrypted_filename[PATH_MAX]; | ||
232 | struct mailmime * multipart; | ||
233 | char * email; | ||
234 | |||
235 | /* get the two parts of the PGP message */ | ||
236 | |||
237 | cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list); | ||
238 | if (cur == NULL) { | ||
239 | res = MAIL_ERROR_INVAL; | ||
240 | goto err; | ||
241 | } | ||
242 | |||
243 | version_mime = clist_content(cur); | ||
244 | cur = clist_next(cur); | ||
245 | if (cur == NULL) { | ||
246 | res = MAIL_ERROR_INVAL; | ||
247 | goto err; | ||
248 | } | ||
249 | |||
250 | encrypted_mime = clist_content(cur); | ||
251 | |||
252 | /* fetch the second section, that's the useful one */ | ||
253 | |||
254 | r = mailprivacy_fetch_decoded_to_file(privacy, | ||
255 | encrypted_filename, sizeof(encrypted_filename), | ||
256 | msg, encrypted_mime); | ||
257 | if (r != MAIL_NO_ERROR) { | ||
258 | res = r; | ||
259 | goto err; | ||
260 | } | ||
261 | |||
262 | /* we are in a safe directory */ | ||
263 | |||
264 | decrypted_f = mailprivacy_get_tmp_file(privacy, | ||
265 | decrypted_filename, | ||
266 | sizeof(decrypted_filename)); | ||
267 | if (decrypted_f == NULL) { | ||
268 | res = MAIL_ERROR_FILE; | ||
269 | goto unlink_encrypted; | ||
270 | } | ||
271 | fclose(decrypted_f); | ||
272 | |||
273 | /* description */ | ||
274 | |||
275 | description_f = mailprivacy_get_tmp_file(privacy, | ||
276 | description_filename, | ||
277 | sizeof(description_filename)); | ||
278 | if (description_f == NULL) { | ||
279 | res = MAIL_ERROR_FILE; | ||
280 | goto unlink_decrypted; | ||
281 | } | ||
282 | |||
283 | fprintf(description_f, PGP_DECRYPT_DESCRIPTION); | ||
284 | |||
285 | /* get encryption key */ | ||
286 | |||
287 | * default_key = '\0'; | ||
288 | email = get_first_from_addr(mime); | ||
289 | if (email != NULL) | ||
290 | snprintf(default_key, sizeof(default_key), | ||
291 | "--default-key %s", email); | ||
292 | |||
293 | /* run the command */ | ||
294 | |||
295 | r = mail_quote_filename(quoted_encrypted_filename, | ||
296 | sizeof(quoted_encrypted_filename), encrypted_filename); | ||
297 | if (r < 0) { | ||
298 | fclose(description_f); | ||
299 | res = MAIL_ERROR_MEMORY; | ||
300 | goto unlink_description; | ||
301 | } | ||
302 | |||
303 | r = mail_quote_filename(quoted_decrypted_filename, | ||
304 | sizeof(quoted_decrypted_filename), decrypted_filename); | ||
305 | if (r < 0) { | ||
306 | fclose(description_f); | ||
307 | res = MAIL_ERROR_MEMORY; | ||
308 | goto unlink_description; | ||
309 | } | ||
310 | |||
311 | decrypt_ok = 0; | ||
312 | snprintf(command, sizeof(command), | ||
313 | "gpg -q --batch --yes --out %s %s --decrypt %s", | ||
314 | quoted_decrypted_filename, default_key, quoted_encrypted_filename); | ||
315 | |||
316 | r = get_pgp_output(description_f, command); | ||
317 | switch (r) { | ||
318 | case NO_ERROR_PGP: | ||
319 | decrypt_ok = 1; | ||
320 | break; | ||
321 | case ERROR_PGP_CHECK: | ||
322 | decrypt_ok = 0; | ||
323 | break; | ||
324 | case ERROR_PGP_COMMAND: | ||
325 | fclose(description_f); | ||
326 | res = MAIL_ERROR_COMMAND; | ||
327 | goto unlink_description; | ||
328 | case ERROR_PGP_FILE: | ||
329 | fclose(description_f); | ||
330 | res = MAIL_ERROR_FILE; | ||
331 | goto unlink_description; | ||
332 | } | ||
333 | if (decrypt_ok) | ||
334 | fprintf(description_f, PGP_DECRYPT_SUCCESS); | ||
335 | else | ||
336 | fprintf(description_f, PGP_DECRYPT_FAILED); | ||
337 | fclose(description_f); | ||
338 | |||
339 | /* building multipart */ | ||
340 | |||
341 | r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart); | ||
342 | if (r != MAILIMF_NO_ERROR) { | ||
343 | res = MAIL_ERROR_MEMORY; | ||
344 | goto unlink_description; | ||
345 | } | ||
346 | |||
347 | /* building the description part */ | ||
348 | |||
349 | description_mime = mailprivacy_new_file_part(privacy, | ||
350 | description_filename, | ||
351 | "text/plain", MAILMIME_MECHANISM_8BIT); | ||
352 | if (description_mime == NULL) { | ||
353 | mailprivacy_mime_clear(multipart); | ||
354 | mailmime_free(multipart); | ||
355 | res = MAIL_ERROR_MEMORY; | ||
356 | goto unlink_description; | ||
357 | } | ||
358 | |||
359 | /* adds the description part */ | ||
360 | |||
361 | r = mailmime_smart_add_part(multipart, description_mime); | ||
362 | if (r != MAIL_NO_ERROR) { | ||
363 | mailprivacy_mime_clear(description_mime); | ||
364 | mailmime_free(description_mime); | ||
365 | mailprivacy_mime_clear(multipart); | ||
366 | mailmime_free(multipart); | ||
367 | res = MAIL_ERROR_MEMORY; | ||
368 | goto unlink_description; | ||
369 | } | ||
370 | |||
371 | /* building the decrypted part */ | ||
372 | |||
373 | r = mailprivacy_get_part_from_file(privacy, 1, | ||
374 | decrypted_filename, &decrypted_mime); | ||
375 | if (r == MAIL_NO_ERROR) { | ||
376 | /* adds the decrypted part */ | ||
377 | |||
378 | r = mailmime_smart_add_part(multipart, decrypted_mime); | ||
379 | if (r != MAIL_NO_ERROR) { | ||
380 | mailprivacy_mime_clear(decrypted_mime); | ||
381 | mailmime_free(decrypted_mime); | ||
382 | mailprivacy_mime_clear(multipart); | ||
383 | mailmime_free(multipart); | ||
384 | res = MAIL_ERROR_MEMORY; | ||
385 | goto unlink_description; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | unlink(description_filename); | ||
390 | unlink(decrypted_filename); | ||
391 | unlink(encrypted_filename); | ||
392 | |||
393 | * result = multipart; | ||
394 | |||
395 | return MAIL_NO_ERROR; | ||
396 | |||
397 | unlink_description: | ||
398 | unlink(description_filename); | ||
399 | unlink_decrypted: | ||
400 | unlink(decrypted_filename); | ||
401 | unlink_encrypted: | ||
402 | unlink(encrypted_filename); | ||
403 | err: | ||
404 | return res; | ||
405 | } | ||
406 | |||
407 | #define PGP_VERIFY_DESCRIPTION "PGP verify signed message\r\n" | ||
408 | #define PGP_VERIFY_FAILED "PGP verification FAILED\r\n" | ||
409 | #define PGP_VERIFY_SUCCESS "PGP verification success\r\n" | ||
410 | |||
411 | static int | ||
412 | pgp_verify(struct mailprivacy * privacy, | ||
413 | mailmessage * msg, | ||
414 | struct mailmime * mime, struct mailmime ** result) | ||
415 | { | ||
416 | struct mailmime * signed_mime; | ||
417 | struct mailmime * signature_mime; | ||
418 | char signed_filename[PATH_MAX]; | ||
419 | char signature_filename[PATH_MAX]; | ||
420 | int res; | ||
421 | int r; | ||
422 | clistiter * cur; | ||
423 | char command[PATH_MAX]; | ||
424 | int sign_ok; | ||
425 | struct mailmime * description_mime; | ||
426 | FILE * description_f; | ||
427 | char description_filename[PATH_MAX]; | ||
428 | char quoted_signed_filename[PATH_MAX]; | ||
429 | char quoted_signature_filename[PATH_MAX]; | ||
430 | struct mailmime * multipart; | ||
431 | struct mailmime * signed_msg_mime; | ||
432 | |||
433 | /* get the two parts of the PGP message */ | ||
434 | |||
435 | cur = clist_begin(mime->mm_data.mm_multipart.mm_mp_list); | ||
436 | if (cur == NULL) { | ||
437 | res = MAIL_ERROR_INVAL; | ||
438 | goto err; | ||
439 | } | ||
440 | |||
441 | signed_mime = clist_content(cur); | ||
442 | cur = clist_next(cur); | ||
443 | if (cur == NULL) { | ||
444 | res = MAIL_ERROR_INVAL; | ||
445 | goto err; | ||
446 | } | ||
447 | |||
448 | signature_mime = clist_content(cur); | ||
449 | |||
450 | /* fetch signed part and write it to a file */ | ||
451 | |||
452 | r = mailprivacy_fetch_mime_body_to_file(privacy, | ||
453 | signed_filename, sizeof(signed_filename), | ||
454 | msg, signed_mime); | ||
455 | if (r != MAIL_NO_ERROR) { | ||
456 | res = r; | ||
457 | goto err; | ||
458 | } | ||
459 | |||
460 | /* fetch signed part and write it to a file */ | ||
461 | |||
462 | r = mailprivacy_fetch_decoded_to_file(privacy, | ||
463 | signature_filename, sizeof(signature_filename), | ||
464 | msg, signature_mime); | ||
465 | if (r != MAIL_NO_ERROR) { | ||
466 | res = r; | ||
467 | goto unlink_signed; | ||
468 | } | ||
469 | |||
470 | /* description */ | ||
471 | |||
472 | description_f = mailprivacy_get_tmp_file(privacy, | ||
473 | description_filename, | ||
474 | sizeof(description_filename)); | ||
475 | if (description_f == NULL) { | ||
476 | res = MAIL_ERROR_FILE; | ||
477 | goto unlink_signature; | ||
478 | } | ||
479 | |||
480 | fprintf(description_f, PGP_VERIFY_DESCRIPTION); | ||
481 | |||
482 | /* run the command */ | ||
483 | |||
484 | r = mail_quote_filename(quoted_signature_filename, | ||
485 | sizeof(quoted_signature_filename), signature_filename); | ||
486 | if (r < 0) { | ||
487 | fclose(description_f); | ||
488 | res = MAIL_ERROR_MEMORY; | ||
489 | goto unlink_description; | ||
490 | } | ||
491 | |||
492 | r = mail_quote_filename(quoted_signed_filename, | ||
493 | sizeof(quoted_signed_filename), signed_filename); | ||
494 | if (r < 0) { | ||
495 | fclose(description_f); | ||
496 | res = MAIL_ERROR_MEMORY; | ||
497 | goto unlink_description; | ||
498 | } | ||
499 | |||
500 | sign_ok = 0; | ||
501 | snprintf(command, sizeof(command), "gpg -q --batch --yes --verify %s %s", | ||
502 | quoted_signature_filename, quoted_signed_filename); | ||
503 | |||
504 | r = get_pgp_output(description_f, command); | ||
505 | switch (r) { | ||
506 | case NO_ERROR_PGP: | ||
507 | sign_ok = 1; | ||
508 | break; | ||
509 | case ERROR_PGP_CHECK: | ||
510 | sign_ok = 0; | ||
511 | break; | ||
512 | case ERROR_PGP_COMMAND: | ||
513 | fclose(description_f); | ||
514 | res = MAIL_ERROR_COMMAND; | ||
515 | goto unlink_description; | ||
516 | case ERROR_PGP_FILE: | ||
517 | fclose(description_f); | ||
518 | res = MAIL_ERROR_FILE; | ||
519 | goto unlink_description; | ||
520 | } | ||
521 | |||
522 | if (sign_ok) | ||
523 | fprintf(description_f, PGP_VERIFY_SUCCESS); | ||
524 | else | ||
525 | fprintf(description_f, PGP_VERIFY_FAILED); | ||
526 | fclose(description_f); | ||
527 | |||
528 | /* building multipart */ | ||
529 | |||
530 | r = mailmime_new_with_content("multipart/x-verified", NULL, &multipart); | ||
531 | if (r != MAILIMF_NO_ERROR) { | ||
532 | res = MAIL_ERROR_MEMORY; | ||
533 | goto unlink_description; | ||
534 | } | ||
535 | |||
536 | /* building the description part */ | ||
537 | |||
538 | description_mime = mailprivacy_new_file_part(privacy, | ||
539 | description_filename, | ||
540 | "text/plain", MAILMIME_MECHANISM_8BIT); | ||
541 | if (description_mime == NULL) { | ||
542 | mailprivacy_mime_clear(multipart); | ||
543 | mailmime_free(multipart); | ||
544 | res = MAIL_ERROR_MEMORY; | ||
545 | goto unlink_description; | ||
546 | } | ||
547 | |||
548 | /* adds the description part */ | ||
549 | |||
550 | r = mailmime_smart_add_part(multipart, description_mime); | ||
551 | if (r != MAIL_NO_ERROR) { | ||
552 | mailprivacy_mime_clear(description_mime); | ||
553 | mailmime_free(description_mime); | ||
554 | mailprivacy_mime_clear(multipart); | ||
555 | mailmime_free(multipart); | ||
556 | res = MAIL_ERROR_MEMORY; | ||
557 | goto unlink_description; | ||
558 | } | ||
559 | |||
560 | r = mailprivacy_get_part_from_file(privacy, 1, | ||
561 | signed_filename, &signed_msg_mime); | ||
562 | if (r != MAIL_NO_ERROR) { | ||
563 | mailprivacy_mime_clear(multipart); | ||
564 | mailmime_free(multipart); | ||
565 | res = MAIL_ERROR_MEMORY; | ||
566 | goto unlink_description; | ||
567 | } | ||
568 | |||
569 | r = mailmime_smart_add_part(multipart, signed_msg_mime); | ||
570 | if (r != MAIL_NO_ERROR) { | ||
571 | mailprivacy_mime_clear(signed_msg_mime); | ||
572 | mailmime_free(signed_msg_mime); | ||
573 | mailprivacy_mime_clear(multipart); | ||
574 | mailmime_free(multipart); | ||
575 | res = MAIL_ERROR_MEMORY; | ||
576 | goto unlink_description; | ||
577 | } | ||
578 | |||
579 | unlink(description_filename); | ||
580 | unlink(signature_filename); | ||
581 | unlink(signed_filename); | ||
582 | |||
583 | * result = multipart; | ||
584 | |||
585 | return MAIL_NO_ERROR; | ||
586 | |||
587 | unlink_description: | ||
588 | unlink(description_filename); | ||
589 | unlink_signature: | ||
590 | unlink(signature_filename); | ||
591 | unlink_signed: | ||
592 | unlink(signed_filename); | ||
593 | err: | ||
594 | return res; | ||
595 | } | ||
596 | |||
597 | |||
598 | #define PGP_CLEAR_VERIFY_DESCRIPTION "PGP verify clear signed message\r\n" | ||
599 | #define PGP_CLEAR_VERIFY_FAILED "PGP verification FAILED\r\n" | ||
600 | #define PGP_CLEAR_VERIFY_SUCCESS "PGP verification success\r\n" | ||
601 | |||
602 | static int pgp_verify_clearsigned(struct mailprivacy * privacy, | ||
603 | mailmessage * msg, | ||
604 | struct mailmime * mime, | ||
605 | char * content, size_t content_len, struct mailmime ** result) | ||
606 | { | ||
607 | int r; | ||
608 | char command[PATH_MAX]; | ||
609 | int res; | ||
610 | int sign_ok; | ||
611 | size_t written; | ||
612 | char signed_filename[PATH_MAX]; | ||
613 | FILE * signed_f; | ||
614 | char stripped_filename[PATH_MAX]; | ||
615 | FILE * stripped_f; | ||
616 | char description_filename[PATH_MAX]; | ||
617 | FILE * description_f; | ||
618 | char quoted_signed_filename[PATH_MAX]; | ||
619 | char quoted_stripped_filename[PATH_MAX]; | ||
620 | struct mailmime * stripped_mime; | ||
621 | struct mailmime * description_mime; | ||
622 | struct mailmime * multipart; | ||
623 | struct mailmime_content * content_type; | ||
624 | |||
625 | if (mime->mm_parent == NULL) { | ||
626 | res = MAIL_ERROR_INVAL; | ||
627 | goto err; | ||
628 | } | ||
629 | |||
630 | if (mime->mm_parent->mm_type == MAILMIME_SINGLE) { | ||
631 | res = MAIL_ERROR_INVAL; | ||
632 | goto err; | ||
633 | } | ||
634 | |||
635 | signed_f = mailprivacy_get_tmp_file(privacy, | ||
636 | signed_filename, sizeof(signed_filename)); | ||
637 | if (signed_f == NULL) { | ||
638 | res = MAIL_ERROR_FILE; | ||
639 | goto err; | ||
640 | } | ||
641 | |||
642 | written = fwrite(content, 1, content_len, signed_f); | ||
643 | if (written != content_len) { | ||
644 | fclose(signed_f); | ||
645 | unlink(signed_filename); | ||
646 | res = MAIL_ERROR_FILE; | ||
647 | goto err; | ||
648 | } | ||
649 | fclose(signed_f); | ||
650 | |||
651 | /* XXX - prepare file for PGP, remove trailing WS */ | ||
652 | |||
653 | stripped_f = mailprivacy_get_tmp_file(privacy, | ||
654 | stripped_filename, sizeof(stripped_filename)); | ||
655 | if (stripped_f == NULL) { | ||
656 | res = MAIL_ERROR_FILE; | ||
657 | goto unlink_signed; | ||
658 | } | ||
659 | fclose(stripped_f); | ||
660 | |||
661 | /* description */ | ||
662 | |||
663 | description_f = mailprivacy_get_tmp_file(privacy, | ||
664 | description_filename, | ||
665 | sizeof(description_filename)); | ||
666 | if (description_f == NULL) { | ||
667 | res = MAIL_ERROR_FILE; | ||
668 | goto unlink_stripped; | ||
669 | } | ||
670 | |||
671 | fprintf(description_f, PGP_CLEAR_VERIFY_DESCRIPTION); | ||
672 | |||
673 | r = mail_quote_filename(quoted_stripped_filename, | ||
674 | sizeof(quoted_stripped_filename), stripped_filename); | ||
675 | if (r < 0) { | ||
676 | fclose(description_f); | ||
677 | res = MAIL_ERROR_MEMORY; | ||
678 | goto unlink_description; | ||
679 | } | ||
680 | |||
681 | r = mail_quote_filename(quoted_signed_filename, | ||
682 | sizeof(quoted_signed_filename), signed_filename); | ||
683 | if (r < 0) { | ||
684 | fclose(description_f); | ||
685 | res = MAIL_ERROR_MEMORY; | ||
686 | goto unlink_description; | ||
687 | } | ||
688 | |||
689 | snprintf(command, sizeof(command), | ||
690 | "gpg -q --batch --yes --out %s --decrypt %s", | ||
691 | quoted_stripped_filename, quoted_signed_filename); | ||
692 | |||
693 | sign_ok = 0; | ||
694 | r = get_pgp_output(description_f, command); | ||
695 | switch (r) { | ||
696 | case NO_ERROR_PGP: | ||
697 | sign_ok = 1; | ||
698 | break; | ||
699 | case ERROR_PGP_CHECK: | ||
700 | sign_ok = 0; | ||
701 | break; | ||
702 | case ERROR_PGP_COMMAND: | ||
703 | res = MAIL_ERROR_COMMAND; | ||
704 | fclose(description_f); | ||
705 | goto unlink_description; | ||
706 | case ERROR_PGP_FILE: | ||
707 | res = MAIL_ERROR_FILE; | ||
708 | fclose(description_f); | ||
709 | goto unlink_description; | ||
710 | } | ||
711 | if (sign_ok) | ||
712 | fprintf(description_f, PGP_CLEAR_VERIFY_SUCCESS); | ||
713 | else | ||
714 | fprintf(description_f, PGP_CLEAR_VERIFY_FAILED); | ||
715 | fclose(description_f); | ||
716 | |||
717 | /* building multipart */ | ||
718 | |||
719 | r = mailmime_new_with_content("multipart/x-verified", NULL, &multipart); | ||
720 | if (r != MAILIMF_NO_ERROR) { | ||
721 | res = MAIL_ERROR_MEMORY; | ||
722 | goto unlink_description; | ||
723 | } | ||
724 | |||
725 | /* building the description part */ | ||
726 | |||
727 | description_mime = mailprivacy_new_file_part(privacy, | ||
728 | description_filename, | ||
729 | "text/plain", MAILMIME_MECHANISM_8BIT); | ||
730 | if (description_mime == NULL) { | ||
731 | mailprivacy_mime_clear(multipart); | ||
732 | mailmime_free(multipart); | ||
733 | res = MAIL_ERROR_MEMORY; | ||
734 | goto unlink_description; | ||
735 | } | ||
736 | |||
737 | /* adds the description part */ | ||
738 | |||
739 | r = mailmime_smart_add_part(multipart, description_mime); | ||
740 | if (r != MAIL_NO_ERROR) { | ||
741 | mailprivacy_mime_clear(description_mime); | ||
742 | mailmime_free(description_mime); | ||
743 | mailprivacy_mime_clear(multipart); | ||
744 | mailmime_free(multipart); | ||
745 | res = MAIL_ERROR_MEMORY; | ||
746 | goto unlink_description; | ||
747 | } | ||
748 | |||
749 | /* building the signature stripped part */ | ||
750 | |||
751 | stripped_mime = mailprivacy_new_file_part(privacy, | ||
752 | stripped_filename, | ||
753 | "application/octet-stream", | ||
754 | MAILMIME_MECHANISM_8BIT); | ||
755 | if (stripped_mime == NULL) { | ||
756 | mailprivacy_mime_clear(multipart); | ||
757 | mailmime_free(multipart); | ||
758 | res = MAIL_ERROR_MEMORY; | ||
759 | goto unlink_description; | ||
760 | } | ||
761 | |||
762 | /* place original content type */ | ||
763 | |||
764 | content_type = mailmime_content_dup(mime->mm_content_type); | ||
765 | if (content_type == NULL) { | ||
766 | mailprivacy_mime_clear(stripped_mime); | ||
767 | mailmime_free(stripped_mime); | ||
768 | mailprivacy_mime_clear(multipart); | ||
769 | mailmime_free(multipart); | ||
770 | res = MAIL_ERROR_MEMORY; | ||
771 | goto unlink_description; | ||
772 | } | ||
773 | |||
774 | mailmime_content_free(stripped_mime->mm_content_type); | ||
775 | stripped_mime->mm_content_type = content_type; | ||
776 | |||
777 | /* place original MIME fields */ | ||
778 | |||
779 | if (mime->mm_mime_fields != NULL) { | ||
780 | struct mailmime_fields * mime_fields; | ||
781 | clistiter * cur; | ||
782 | |||
783 | mime_fields = mailprivacy_mime_fields_dup(privacy, mime->mm_mime_fields); | ||
784 | if (mime_fields == NULL) { | ||
785 | mailprivacy_mime_clear(stripped_mime); | ||
786 | mailmime_free(stripped_mime); | ||
787 | mailprivacy_mime_clear(multipart); | ||
788 | mailmime_free(multipart); | ||
789 | res = MAIL_ERROR_MEMORY; | ||
790 | goto unlink_description; | ||
791 | } | ||
792 | for(cur = clist_begin(mime_fields->fld_list) ; | ||
793 | cur != NULL ; cur = clist_next(cur)) { | ||
794 | struct mailmime_field * field; | ||
795 | |||
796 | field = clist_content(cur); | ||
797 | if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) { | ||
798 | mailmime_field_free(field); | ||
799 | clist_delete(mime_fields->fld_list, cur); | ||
800 | break; | ||
801 | } | ||
802 | } | ||
803 | clist_concat(stripped_mime->mm_mime_fields->fld_list, | ||
804 | mime_fields->fld_list); | ||
805 | mailmime_fields_free(mime_fields); | ||
806 | } | ||
807 | |||
808 | /* adds the stripped part */ | ||
809 | |||
810 | r = mailmime_smart_add_part(multipart, stripped_mime); | ||
811 | if (r != MAIL_NO_ERROR) { | ||
812 | mailprivacy_mime_clear(stripped_mime); | ||
813 | mailmime_free(stripped_mime); | ||
814 | mailprivacy_mime_clear(multipart); | ||
815 | mailmime_free(multipart); | ||
816 | res = MAIL_ERROR_MEMORY; | ||
817 | goto unlink_description; | ||
818 | } | ||
819 | |||
820 | unlink(description_filename); | ||
821 | unlink(stripped_filename); | ||
822 | unlink(signed_filename); | ||
823 | |||
824 | * result = multipart; | ||
825 | |||
826 | return MAIL_NO_ERROR; | ||
827 | |||
828 | unlink_description: | ||
829 | unlink(description_filename); | ||
830 | unlink_stripped: | ||
831 | unlink(stripped_filename); | ||
832 | unlink_signed: | ||
833 | unlink(signed_filename); | ||
834 | err: | ||
835 | return res; | ||
836 | } | ||
837 | |||
838 | |||
839 | #define PGP_DECRYPT_ARMOR_DESCRIPTION "PGP ASCII armor encrypted part\r\n" | ||
840 | #define PGP_DECRYPT_ARMOR_FAILED "PGP ASCII armor decryption FAILED\r\n" | ||
841 | #define PGP_DECRYPT_ARMOR_SUCCESS "PGP ASCII armor decryption success\r\n" | ||
842 | |||
843 | static int pgp_decrypt_armor(struct mailprivacy * privacy, | ||
844 | mailmessage * msg, | ||
845 | struct mailmime * mime, | ||
846 | char * content, size_t content_len, struct mailmime ** result) | ||
847 | { | ||
848 | char default_key[PATH_MAX]; | ||
849 | FILE * encrypted_f; | ||
850 | char encrypted_filename[PATH_MAX]; | ||
851 | char description_filename[PATH_MAX]; | ||
852 | FILE * description_f; | ||
853 | char decrypted_filename[PATH_MAX]; | ||
854 | FILE * decrypted_f; | ||
855 | size_t written; | ||
856 | char command[PATH_MAX]; | ||
857 | struct mailmime * description_mime; | ||
858 | struct mailmime * decrypted_mime; | ||
859 | struct mailmime * multipart; | ||
860 | int r; | ||
861 | int res; | ||
862 | int sign_ok; | ||
863 | char quoted_decrypted_filename[PATH_MAX]; | ||
864 | char quoted_encrypted_filename[PATH_MAX]; | ||
865 | char * email; | ||
866 | |||
867 | if (mime->mm_parent == NULL) { | ||
868 | res = MAIL_ERROR_INVAL; | ||
869 | goto err; | ||
870 | } | ||
871 | |||
872 | if (mime->mm_parent->mm_type == MAILMIME_SINGLE) { | ||
873 | res = MAIL_ERROR_INVAL; | ||
874 | goto err; | ||
875 | } | ||
876 | |||
877 | encrypted_f = mailprivacy_get_tmp_file(privacy, | ||
878 | encrypted_filename, | ||
879 | sizeof(encrypted_filename)); | ||
880 | if (encrypted_f == NULL) { | ||
881 | res = MAIL_ERROR_FILE; | ||
882 | goto err; | ||
883 | } | ||
884 | |||
885 | written = fwrite(content, 1, content_len, encrypted_f); | ||
886 | if (written != content_len) { | ||
887 | fclose(encrypted_f); | ||
888 | unlink(encrypted_filename); | ||
889 | res = MAIL_ERROR_FILE; | ||
890 | goto err; | ||
891 | } | ||
892 | |||
893 | fclose(encrypted_f); | ||
894 | |||
895 | /* we are in a safe directory */ | ||
896 | |||
897 | decrypted_f = mailprivacy_get_tmp_file(privacy, | ||
898 | decrypted_filename, | ||
899 | sizeof(decrypted_filename)); | ||
900 | if (decrypted_f == NULL) { | ||
901 | res = MAIL_ERROR_FILE; | ||
902 | goto unlink_encrypted; | ||
903 | } | ||
904 | fclose(decrypted_f); | ||
905 | |||
906 | /* description */ | ||
907 | |||
908 | description_f = mailprivacy_get_tmp_file(privacy, | ||
909 | description_filename, | ||
910 | sizeof(description_filename)); | ||
911 | if (description_f == NULL) { | ||
912 | res = MAIL_ERROR_FILE; | ||
913 | goto unlink_decrypted; | ||
914 | } | ||
915 | |||
916 | fprintf(description_f, PGP_DECRYPT_ARMOR_DESCRIPTION); | ||
917 | |||
918 | /* get encryption key */ | ||
919 | |||
920 | * default_key = '\0'; | ||
921 | email = get_first_from_addr(mime); | ||
922 | if (email != NULL) | ||
923 | snprintf(default_key, sizeof(default_key), | ||
924 | "--default-key %s", email); | ||
925 | |||
926 | /* run the command */ | ||
927 | |||
928 | r = mail_quote_filename(quoted_encrypted_filename, | ||
929 | sizeof(quoted_encrypted_filename), encrypted_filename); | ||
930 | if (r < 0) { | ||
931 | fclose(description_f); | ||
932 | res = MAIL_ERROR_MEMORY; | ||
933 | goto unlink_description; | ||
934 | } | ||
935 | |||
936 | r = mail_quote_filename(quoted_decrypted_filename, | ||
937 | sizeof(quoted_decrypted_filename), decrypted_filename); | ||
938 | if (r < 0) { | ||
939 | fclose(description_f); | ||
940 | res = MAIL_ERROR_MEMORY; | ||
941 | goto unlink_description; | ||
942 | } | ||
943 | |||
944 | sign_ok = 0; | ||
945 | snprintf(command, sizeof(command), | ||
946 | "gpg -q --batch --yes --out %s %s --decrypt %s", | ||
947 | quoted_decrypted_filename, default_key, quoted_encrypted_filename); | ||
948 | |||
949 | r = get_pgp_output(description_f, command); | ||
950 | switch (r) { | ||
951 | case NO_ERROR_PGP: | ||
952 | sign_ok = 1; | ||
953 | break; | ||
954 | case ERROR_PGP_CHECK: | ||
955 | sign_ok = 0; | ||
956 | break; | ||
957 | case ERROR_PGP_COMMAND: | ||
958 | fclose(description_f); | ||
959 | res = MAIL_ERROR_COMMAND; | ||
960 | goto unlink_description; | ||
961 | case ERROR_PGP_FILE: | ||
962 | fclose(description_f); | ||
963 | res = MAIL_ERROR_FILE; | ||
964 | goto unlink_description; | ||
965 | } | ||
966 | if (sign_ok) | ||
967 | fprintf(description_f, PGP_DECRYPT_ARMOR_SUCCESS); | ||
968 | else | ||
969 | fprintf(description_f, PGP_DECRYPT_ARMOR_FAILED); | ||
970 | fclose(description_f); | ||
971 | |||
972 | /* building multipart */ | ||
973 | |||
974 | r = mailmime_new_with_content("multipart/x-decrypted", NULL, &multipart); | ||
975 | if (r != MAILIMF_NO_ERROR) { | ||
976 | res = MAIL_ERROR_MEMORY; | ||
977 | goto unlink_description; | ||
978 | } | ||
979 | |||
980 | /* building the description part */ | ||
981 | |||
982 | description_mime = mailprivacy_new_file_part(privacy, | ||
983 | description_filename, | ||
984 | "text/plain", MAILMIME_MECHANISM_8BIT); | ||
985 | if (description_mime == NULL) { | ||
986 | mailprivacy_mime_clear(multipart); | ||
987 | mailmime_free(multipart); | ||
988 | res = MAIL_ERROR_MEMORY; | ||
989 | goto unlink_description; | ||
990 | } | ||
991 | |||
992 | /* adds the description part */ | ||
993 | |||
994 | r = mailmime_smart_add_part(multipart, description_mime); | ||
995 | if (r != MAIL_NO_ERROR) { | ||
996 | mailprivacy_mime_clear(description_mime); | ||
997 | mailmime_free(description_mime); | ||
998 | mailprivacy_mime_clear(multipart); | ||
999 | mailmime_free(multipart); | ||
1000 | res = MAIL_ERROR_MEMORY; | ||
1001 | goto unlink_description; | ||
1002 | } | ||
1003 | |||
1004 | /* building the decrypted part */ | ||
1005 | |||
1006 | r = mailprivacy_get_part_from_file(privacy, 1, | ||
1007 | decrypted_filename, &decrypted_mime); | ||
1008 | if (r != MAIL_NO_ERROR) { | ||
1009 | mailprivacy_mime_clear(multipart); | ||
1010 | mailmime_free(multipart); | ||
1011 | res = r; | ||
1012 | goto unlink_description; | ||
1013 | } | ||
1014 | |||
1015 | /* adds the decrypted part */ | ||
1016 | |||
1017 | r = mailmime_smart_add_part(multipart, decrypted_mime); | ||
1018 | if (r != MAIL_NO_ERROR) { | ||
1019 | mailprivacy_mime_clear(decrypted_mime); | ||
1020 | mailmime_free(decrypted_mime); | ||
1021 | mailprivacy_mime_clear(multipart); | ||
1022 | mailmime_free(multipart); | ||
1023 | res = MAIL_ERROR_MEMORY; | ||
1024 | goto unlink_description; | ||
1025 | } | ||
1026 | |||
1027 | unlink(description_filename); | ||
1028 | unlink(decrypted_filename); | ||
1029 | unlink(encrypted_filename); | ||
1030 | |||
1031 | * result = multipart; | ||
1032 | |||
1033 | return MAIL_NO_ERROR; | ||
1034 | |||
1035 | unlink_description: | ||
1036 | unlink(description_filename); | ||
1037 | unlink_decrypted: | ||
1038 | unlink(decrypted_filename); | ||
1039 | unlink_encrypted: | ||
1040 | unlink(encrypted_filename); | ||
1041 | err: | ||
1042 | return res; | ||
1043 | } | ||
1044 | |||
1045 | |||
1046 | static int mime_is_text(struct mailmime * build_info) | ||
1047 | { | ||
1048 | if (build_info->mm_type == MAILMIME_SINGLE) { | ||
1049 | if (build_info->mm_content_type != NULL) { | ||
1050 | if (build_info->mm_content_type->ct_type->tp_type == | ||
1051 | MAILMIME_TYPE_DISCRETE_TYPE) { | ||
1052 | if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type == | ||
1053 | MAILMIME_DISCRETE_TYPE_TEXT) | ||
1054 | return 1; | ||
1055 | } | ||
1056 | } | ||
1057 | else | ||
1058 | return 1; | ||
1059 | } | ||
1060 | |||
1061 | return 0; | ||
1062 | } | ||
1063 | |||
1064 | |||
1065 | static int pgp_test_encrypted(struct mailprivacy * privacy, | ||
1066 | mailmessage * msg, struct mailmime * mime) | ||
1067 | { | ||
1068 | int r; | ||
1069 | int res; | ||
1070 | |||
1071 | switch (mime->mm_type) { | ||
1072 | case MAILMIME_MULTIPLE: | ||
1073 | return (pgp_is_encrypted(mime) || pgp_is_signed(mime)); | ||
1074 | |||
1075 | case MAILMIME_SINGLE: | ||
1076 | /* clear sign or ASCII armor encryption */ | ||
1077 | if (mime_is_text(mime)) { | ||
1078 | char * content; | ||
1079 | size_t content_len; | ||
1080 | char * parsed_content; | ||
1081 | size_t parsed_content_len; | ||
1082 | size_t cur_token; | ||
1083 | int encoding; | ||
1084 | struct mailmime_single_fields single_fields; | ||
1085 | |||
1086 | r = mailprivacy_msg_fetch_section(privacy, msg, mime, | ||
1087 | &content, &content_len); | ||
1088 | if (r != MAIL_NO_ERROR) | ||
1089 | return 0; | ||
1090 | |||
1091 | mailmime_single_fields_init(&single_fields, mime->mm_mime_fields, | ||
1092 | mime->mm_content_type); | ||
1093 | if (single_fields.fld_encoding != NULL) | ||
1094 | encoding = single_fields.fld_encoding->enc_type; | ||
1095 | else | ||
1096 | encoding = MAILMIME_MECHANISM_8BIT; | ||
1097 | |||
1098 | cur_token = 0; | ||
1099 | r = mailmime_part_parse(content, content_len, &cur_token, | ||
1100 | encoding, &parsed_content, &parsed_content_len); | ||
1101 | mailprivacy_msg_fetch_result_free(privacy, msg, content); | ||
1102 | |||
1103 | if (r != MAILIMF_NO_ERROR) | ||
1104 | return 0; | ||
1105 | |||
1106 | res = 0; | ||
1107 | |||
1108 | if (pgp_is_clearsigned(parsed_content, parsed_content_len)) | ||
1109 | res = 1; | ||
1110 | else if (pgp_is_crypted_armor(parsed_content, parsed_content_len)) | ||
1111 | res = 1; | ||
1112 | |||
1113 | mmap_string_unref(parsed_content); | ||
1114 | |||
1115 | return res; | ||
1116 | } | ||
1117 | break; | ||
1118 | } | ||
1119 | |||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static int pgp_handler(struct mailprivacy * privacy, | ||
1124 | mailmessage * msg, | ||
1125 | struct mailmime * mime, struct mailmime ** result) | ||
1126 | { | ||
1127 | int r; | ||
1128 | struct mailmime * alternative_mime; | ||
1129 | |||
1130 | alternative_mime = NULL; | ||
1131 | switch (mime->mm_type) { | ||
1132 | case MAILMIME_MULTIPLE: | ||
1133 | r = MAIL_ERROR_INVAL; | ||
1134 | if (pgp_is_encrypted(mime)) { | ||
1135 | r = pgp_decrypt(privacy, msg, mime, &alternative_mime); | ||
1136 | } | ||
1137 | else if (pgp_is_signed(mime)) { | ||
1138 | r = pgp_verify(privacy, msg, mime, &alternative_mime); | ||
1139 | } | ||
1140 | |||
1141 | if (r != MAIL_NO_ERROR) | ||
1142 | return r; | ||
1143 | |||
1144 | * result = alternative_mime; | ||
1145 | |||
1146 | return MAIL_NO_ERROR; | ||
1147 | |||
1148 | case MAILMIME_SINGLE: | ||
1149 | /* clear sign or ASCII armor encryption */ | ||
1150 | if (mime_is_text(mime)) { | ||
1151 | char * content; | ||
1152 | size_t content_len; | ||
1153 | char * parsed_content; | ||
1154 | size_t parsed_content_len; | ||
1155 | size_t cur_token; | ||
1156 | int encoding; | ||
1157 | struct mailmime_single_fields single_fields; | ||
1158 | |||
1159 | r = mailprivacy_msg_fetch_section(privacy, msg, mime, | ||
1160 | &content, &content_len); | ||
1161 | if (r != MAIL_NO_ERROR) | ||
1162 | return MAIL_ERROR_FETCH; | ||
1163 | |||
1164 | mailmime_single_fields_init(&single_fields, mime->mm_mime_fields, | ||
1165 | mime->mm_content_type); | ||
1166 | if (single_fields.fld_encoding != NULL) | ||
1167 | encoding = single_fields.fld_encoding->enc_type; | ||
1168 | else | ||
1169 | encoding = MAILMIME_MECHANISM_8BIT; | ||
1170 | |||
1171 | cur_token = 0; | ||
1172 | r = mailmime_part_parse(content, content_len, &cur_token, | ||
1173 | encoding, &parsed_content, &parsed_content_len); | ||
1174 | mailprivacy_msg_fetch_result_free(privacy, msg, content); | ||
1175 | |||
1176 | if (r != MAILIMF_NO_ERROR) | ||
1177 | return MAIL_ERROR_PARSE; | ||
1178 | |||
1179 | r = MAIL_ERROR_INVAL; | ||
1180 | if (pgp_is_clearsigned(parsed_content, | ||
1181 | parsed_content_len)) { | ||
1182 | r = pgp_verify_clearsigned(privacy, | ||
1183 | msg, mime, parsed_content, parsed_content_len, &alternative_mime); | ||
1184 | } | ||
1185 | else if (pgp_is_crypted_armor(parsed_content, | ||
1186 | parsed_content_len)) { | ||
1187 | r = pgp_decrypt_armor(privacy, | ||
1188 | msg, mime, parsed_content, parsed_content_len, &alternative_mime); | ||
1189 | } | ||
1190 | |||
1191 | mmap_string_unref(parsed_content); | ||
1192 | |||
1193 | if (r != MAIL_NO_ERROR) | ||
1194 | return r; | ||
1195 | |||
1196 | * result = alternative_mime; | ||
1197 | |||
1198 | return MAIL_NO_ERROR; | ||
1199 | } | ||
1200 | break; | ||
1201 | } | ||
1202 | |||
1203 | return MAIL_ERROR_INVAL; | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | #if 0 | ||
1208 | static void prepare_mime_single(struct mailmime * mime) | ||
1209 | { | ||
1210 | struct mailmime_single_fields single_fields; | ||
1211 | int encoding; | ||
1212 | int r; | ||
1213 | |||
1214 | if (mime->mime_fields != NULL) { | ||
1215 | mailmime_single_fields_init(&single_fields, mime->mime_fields, | ||
1216 | mime->content_type); | ||
1217 | if (single_fields.encoding != NULL) { | ||
1218 | encoding = single_fields.encoding->type; | ||
1219 | switch (encoding) { | ||
1220 | case MAILMIME_MECHANISM_8BIT: | ||
1221 | case MAILMIME_MECHANISM_7BIT: | ||
1222 | case MAILMIME_MECHANISM_BINARY: | ||
1223 | single_fields.encoding->type = MAILMIME_MECHANISM_QUOTED_PRINTABLE; | ||
1224 | break; | ||
1225 | } | ||
1226 | } | ||
1227 | else { | ||
1228 | struct mailmime_mechanism * mechanism; | ||
1229 | struct mailmime_field * field; | ||
1230 | |||
1231 | mechanism = | ||
1232 | mailmime_mechanism_new(MAILMIME_MECHANISM_QUOTED_PRINTABLE, NULL); | ||
1233 | if (mechanism == NULL) | ||
1234 | return; | ||
1235 | |||
1236 | field = mailmime_field_new(MAILMIME_FIELD_TRANSFER_ENCODING, | ||
1237 | NULL, mechanism, NULL, NULL, 0, NULL, NULL); | ||
1238 | if (field == NULL) { | ||
1239 | mailmime_mechanism_free(mechanism); | ||
1240 | return; | ||
1241 | } | ||
1242 | |||
1243 | r = clist_append(mime->mime_fields->list, field); | ||
1244 | if (r < 0) { | ||
1245 | mailmime_field_free(field); | ||
1246 | return; | ||
1247 | } | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | switch (mime->body->encoding) { | ||
1252 | case MAILMIME_MECHANISM_8BIT: | ||
1253 | case MAILMIME_MECHANISM_7BIT: | ||
1254 | case MAILMIME_MECHANISM_BINARY: | ||
1255 | mime->body->encoding = MAILMIME_MECHANISM_QUOTED_PRINTABLE; | ||
1256 | mime->body->encoded = 0; | ||
1257 | break; | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | /* | ||
1262 | prepare_mime() | ||
1263 | |||
1264 | we assume we built ourself the message. | ||
1265 | */ | ||
1266 | |||
1267 | static void prepare_mime(struct mailmime * mime) | ||
1268 | { | ||
1269 | clistiter * cur; | ||
1270 | |||
1271 | switch (mime->type) { | ||
1272 | case MAILMIME_SINGLE: | ||
1273 | if (mime->body != NULL) { | ||
1274 | prepare_mime_single(mime); | ||
1275 | } | ||
1276 | break; | ||
1277 | |||
1278 | case MAILMIME_MULTIPLE: | ||
1279 | for(cur = clist_begin(mime->list) ; cur != NULL ; cur = clist_next(cur)) { | ||
1280 | struct mailmime * child; | ||
1281 | |||
1282 | child = cur->data; | ||
1283 | |||
1284 | prepare_mime(child); | ||
1285 | } | ||
1286 | break; | ||
1287 | |||
1288 | case MAILMIME_MESSAGE: | ||
1289 | if (mime->msg_mime) { | ||
1290 | prepare_mime(mime->msg_mime); | ||
1291 | } | ||
1292 | break; | ||
1293 | } | ||
1294 | } | ||
1295 | #endif | ||
1296 | |||
1297 | static int pgp_sign_mime(struct mailprivacy * privacy, | ||
1298 | struct mailmime * mime, struct mailmime ** result) | ||
1299 | { | ||
1300 | char signed_filename[PATH_MAX]; | ||
1301 | FILE * signed_f; | ||
1302 | int res; | ||
1303 | int r; | ||
1304 | int col; | ||
1305 | char signature_filename[PATH_MAX]; | ||
1306 | FILE * signature_f; | ||
1307 | char command[PATH_MAX]; | ||
1308 | char quoted_signature_filename[PATH_MAX]; | ||
1309 | char quoted_signed_filename[PATH_MAX]; | ||
1310 | char default_key[PATH_MAX]; | ||
1311 | struct mailmime * signature_mime; | ||
1312 | struct mailmime * multipart; | ||
1313 | struct mailmime_content * content; | ||
1314 | struct mailmime_parameter * param; | ||
1315 | struct mailmime * signed_msg_mime; | ||
1316 | char * dup_signature_filename; | ||
1317 | char * email; | ||
1318 | |||
1319 | /* get signing key */ | ||
1320 | |||
1321 | * default_key = '\0'; | ||
1322 | email = get_first_from_addr(mime); | ||
1323 | if (email != NULL) | ||
1324 | snprintf(default_key, sizeof(default_key), | ||
1325 | "--default-key %s", email); | ||
1326 | |||
1327 | /* part to sign */ | ||
1328 | |||
1329 | /* encode quoted printable all text parts */ | ||
1330 | |||
1331 | mailprivacy_prepare_mime(mime); | ||
1332 | |||
1333 | signed_f = mailprivacy_get_tmp_file(privacy, | ||
1334 | signed_filename, sizeof(signed_filename)); | ||
1335 | if (signed_f == NULL) { | ||
1336 | res = MAIL_ERROR_FILE; | ||
1337 | goto err; | ||
1338 | } | ||
1339 | |||
1340 | col = 0; | ||
1341 | r = mailmime_write(signed_f, &col, mime); | ||
1342 | if (r != MAILIMF_NO_ERROR) { | ||
1343 | fclose(signed_f); | ||
1344 | res = MAIL_ERROR_FILE; | ||
1345 | goto unlink_signed; | ||
1346 | } | ||
1347 | |||
1348 | fclose(signed_f); | ||
1349 | |||
1350 | /* prepare destination file for signature */ | ||
1351 | |||
1352 | signature_f = mailprivacy_get_tmp_file(privacy, | ||
1353 | signature_filename, | ||
1354 | sizeof(signature_filename)); | ||
1355 | if (signature_f == NULL) { | ||
1356 | res = MAIL_ERROR_FILE; | ||
1357 | goto unlink_signed; | ||
1358 | } | ||
1359 | fclose(signature_f); | ||
1360 | |||
1361 | r = mail_quote_filename(quoted_signed_filename, | ||
1362 | sizeof(quoted_signed_filename), signed_filename); | ||
1363 | if (r < 0) { | ||
1364 | res = MAIL_ERROR_MEMORY; | ||
1365 | goto unlink_signature; | ||
1366 | } | ||
1367 | |||
1368 | r = mail_quote_filename(quoted_signature_filename, | ||
1369 | sizeof(quoted_signature_filename), signature_filename); | ||
1370 | if (r < 0) { | ||
1371 | res = MAIL_ERROR_MEMORY; | ||
1372 | goto unlink_signature; | ||
1373 | } | ||
1374 | |||
1375 | snprintf(command, sizeof(command), | ||
1376 | "gpg -q -a --batch --yes --digest-algo sha1 --out %s %s -b %s 2>/dev/null", | ||
1377 | quoted_signature_filename, default_key, quoted_signed_filename); | ||
1378 | |||
1379 | r = system(command); | ||
1380 | if (WEXITSTATUS(r) != 0) { | ||
1381 | res = MAIL_ERROR_COMMAND; | ||
1382 | goto unlink_signature; | ||
1383 | } | ||
1384 | |||
1385 | /* multipart */ | ||
1386 | |||
1387 | multipart = mailprivacy_new_file_part(privacy, NULL, | ||
1388 | "multipart/signed", -1); | ||
1389 | |||
1390 | content = multipart->mm_content_type; | ||
1391 | |||
1392 | param = mailmime_param_new_with_data("micalg", "pgp-sha1"); | ||
1393 | if (param == NULL) { | ||
1394 | mailmime_free(multipart); | ||
1395 | res = MAIL_ERROR_MEMORY; | ||
1396 | goto unlink_signature; | ||
1397 | } | ||
1398 | |||
1399 | r = clist_append(content->ct_parameters, param); | ||
1400 | if (r < 0) { | ||
1401 | mailmime_parameter_free(param); | ||
1402 | mailmime_free(multipart); | ||
1403 | res = MAIL_ERROR_MEMORY; | ||
1404 | goto unlink_signature; | ||
1405 | } | ||
1406 | |||
1407 | param = mailmime_param_new_with_data("protocol", | ||
1408 | "application/pgp-signature"); | ||
1409 | if (param == NULL) { | ||
1410 | mailmime_free(multipart); | ||
1411 | res = MAIL_ERROR_MEMORY; | ||
1412 | goto unlink_signature; | ||
1413 | } | ||
1414 | |||
1415 | r = clist_append(content->ct_parameters, param); | ||
1416 | if (r < 0) { | ||
1417 | mailmime_parameter_free(param); | ||
1418 | mailmime_free(multipart); | ||
1419 | res = MAIL_ERROR_MEMORY; | ||
1420 | goto unlink_signature; | ||
1421 | } | ||
1422 | |||
1423 | /* signed part */ | ||
1424 | |||
1425 | r = mailprivacy_get_part_from_file(privacy, 1, | ||
1426 | signed_filename, &signed_msg_mime); | ||
1427 | if (r != MAIL_NO_ERROR) { | ||
1428 | mailprivacy_mime_clear(multipart); | ||
1429 | mailmime_free(multipart); | ||
1430 | res = r; | ||
1431 | goto unlink_signature; | ||
1432 | } | ||
1433 | |||
1434 | mailprivacy_prepare_mime(signed_msg_mime); | ||
1435 | |||
1436 | r = mailmime_smart_add_part(multipart, signed_msg_mime); | ||
1437 | if (r != MAIL_NO_ERROR) { | ||
1438 | mailprivacy_mime_clear(signed_msg_mime); | ||
1439 | mailmime_free(signed_msg_mime); | ||
1440 | mailprivacy_mime_clear(multipart); | ||
1441 | mailmime_free(multipart); | ||
1442 | res = MAIL_ERROR_MEMORY; | ||
1443 | goto unlink_signature; | ||
1444 | } | ||
1445 | |||
1446 | /* signature part */ | ||
1447 | |||
1448 | /* reencode the signature file with CRLF */ | ||
1449 | dup_signature_filename = mailprivacy_dup_imf_file(privacy, | ||
1450 | signature_filename); | ||
1451 | if (dup_signature_filename == NULL) { | ||
1452 | mailprivacy_mime_clear(multipart); | ||
1453 | mailmime_free(multipart); | ||
1454 | res = MAIL_ERROR_FILE; | ||
1455 | goto unlink_signature; | ||
1456 | } | ||
1457 | |||
1458 | /* replace the signature file */ | ||
1459 | unlink(signature_filename); | ||
1460 | strncpy(signature_filename, | ||
1461 | dup_signature_filename, sizeof(signature_filename)); | ||
1462 | signature_filename[sizeof(signature_filename) - 1] = '\0'; | ||
1463 | |||
1464 | signature_mime = mailprivacy_new_file_part(privacy, | ||
1465 | signature_filename, | ||
1466 | "application/pgp-signature", | ||
1467 | MAILMIME_MECHANISM_8BIT); | ||
1468 | if (signature_mime == NULL) { | ||
1469 | mailprivacy_mime_clear(multipart); | ||
1470 | mailmime_free(multipart); | ||
1471 | res = MAIL_ERROR_MEMORY; | ||
1472 | goto unlink_signature; | ||
1473 | } | ||
1474 | |||
1475 | r = mailmime_smart_add_part(multipart, signature_mime); | ||
1476 | if (r != MAIL_NO_ERROR) { | ||
1477 | mailprivacy_mime_clear(signature_mime); | ||
1478 | mailmime_free(signature_mime); | ||
1479 | mailprivacy_mime_clear(multipart); | ||
1480 | mailmime_free(multipart); | ||
1481 | res = MAIL_ERROR_MEMORY; | ||
1482 | goto unlink_signature; | ||
1483 | } | ||
1484 | |||
1485 | unlink(signature_filename); | ||
1486 | unlink(signed_filename); | ||
1487 | |||
1488 | * result = multipart; | ||
1489 | |||
1490 | return MAIL_NO_ERROR; | ||
1491 | |||
1492 | unlink_signature: | ||
1493 | unlink(signature_filename); | ||
1494 | unlink_signed: | ||
1495 | unlink(signed_filename); | ||
1496 | err: | ||
1497 | return res; | ||
1498 | } | ||
1499 | |||
1500 | |||
1501 | /* ********************************************************************* */ | ||
1502 | /* find GPG recipient */ | ||
1503 | |||
1504 | static int recipient_add_mb(char * recipient, size_t * len, | ||
1505 | struct mailimf_mailbox * mb) | ||
1506 | { | ||
1507 | char buffer[PATH_MAX]; | ||
1508 | size_t buflen; | ||
1509 | |||
1510 | if (mb->mb_addr_spec != NULL) { | ||
1511 | snprintf(buffer, sizeof(buffer), "-r %s ", mb->mb_addr_spec); | ||
1512 | buflen = strlen(buffer); | ||
1513 | if (buflen >= * len) | ||
1514 | return MAIL_ERROR_MEMORY; | ||
1515 | |||
1516 | strncat(recipient, buffer, * len); | ||
1517 | (* len) -= buflen; | ||
1518 | } | ||
1519 | |||
1520 | return MAIL_NO_ERROR; | ||
1521 | } | ||
1522 | |||
1523 | static int recipient_add_mb_list(char * recipient, size_t * len, | ||
1524 | struct mailimf_mailbox_list * mb_list) | ||
1525 | { | ||
1526 | clistiter * cur; | ||
1527 | int r; | ||
1528 | |||
1529 | for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ; | ||
1530 | cur = clist_next(cur)) { | ||
1531 | struct mailimf_mailbox * mb; | ||
1532 | |||
1533 | mb = clist_content(cur); | ||
1534 | |||
1535 | r = recipient_add_mb(recipient, len, mb); | ||
1536 | if (r != MAIL_NO_ERROR) | ||
1537 | return r; | ||
1538 | } | ||
1539 | |||
1540 | return MAIL_NO_ERROR; | ||
1541 | } | ||
1542 | |||
1543 | static int recipient_add_group(char * recipient, size_t * len, | ||
1544 | struct mailimf_group * group) | ||
1545 | { | ||
1546 | return recipient_add_mb_list(recipient, len, group->grp_mb_list); | ||
1547 | } | ||
1548 | |||
1549 | static int recipient_add_addr(char * recipient, size_t * len, | ||
1550 | struct mailimf_address * addr) | ||
1551 | { | ||
1552 | int r; | ||
1553 | |||
1554 | switch (addr->ad_type) { | ||
1555 | case MAILIMF_ADDRESS_MAILBOX: | ||
1556 | r = recipient_add_mb(recipient, len, addr->ad_data.ad_mailbox); | ||
1557 | break; | ||
1558 | case MAILIMF_ADDRESS_GROUP: | ||
1559 | r = recipient_add_group(recipient, len, addr->ad_data.ad_group); | ||
1560 | break; | ||
1561 | default: | ||
1562 | r = MAIL_ERROR_INVAL; | ||
1563 | } | ||
1564 | |||
1565 | return r; | ||
1566 | } | ||
1567 | |||
1568 | static int recipient_add_addr_list(char * recipient, size_t * len, | ||
1569 | struct mailimf_address_list * addr_list) | ||
1570 | { | ||
1571 | clistiter * cur; | ||
1572 | int r; | ||
1573 | |||
1574 | for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ; | ||
1575 | cur = clist_next(cur)) { | ||
1576 | struct mailimf_address * addr; | ||
1577 | |||
1578 | addr = clist_content(cur); | ||
1579 | |||
1580 | r = recipient_add_addr(recipient, len, addr); | ||
1581 | if (r != MAIL_NO_ERROR) | ||
1582 | return r; | ||
1583 | } | ||
1584 | |||
1585 | return MAIL_NO_ERROR; | ||
1586 | } | ||
1587 | |||
1588 | |||
1589 | static int collect_recipient(char * recipient, size_t size, | ||
1590 | struct mailimf_fields * fields) | ||
1591 | { | ||
1592 | struct mailimf_single_fields single_fields; | ||
1593 | int r; | ||
1594 | size_t remaining; | ||
1595 | int res; | ||
1596 | |||
1597 | * recipient = '\0'; | ||
1598 | remaining = size; | ||
1599 | |||
1600 | if (fields != NULL) | ||
1601 | mailimf_single_fields_init(&single_fields, fields); | ||
1602 | |||
1603 | if (single_fields.fld_to != NULL) { | ||
1604 | r = recipient_add_addr_list(recipient, &remaining, | ||
1605 | single_fields.fld_to->to_addr_list); | ||
1606 | if (r != MAIL_NO_ERROR) { | ||
1607 | res = r; | ||
1608 | goto err; | ||
1609 | } | ||
1610 | } | ||
1611 | |||
1612 | if (single_fields.fld_cc != NULL) { | ||
1613 | r = recipient_add_addr_list(recipient, &remaining, | ||
1614 | single_fields.fld_cc->cc_addr_list); | ||
1615 | if (r != MAIL_NO_ERROR) { | ||
1616 | res = r; | ||
1617 | goto err; | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | if (single_fields.fld_bcc != NULL) { | ||
1622 | if (single_fields.fld_bcc->bcc_addr_list != NULL) { | ||
1623 | r = recipient_add_addr_list(recipient, &remaining, | ||
1624 | single_fields.fld_bcc->bcc_addr_list); | ||
1625 | if (r != MAIL_NO_ERROR) { | ||
1626 | res = r; | ||
1627 | goto err; | ||
1628 | } | ||
1629 | } | ||
1630 | } | ||
1631 | |||
1632 | return MAIL_NO_ERROR; | ||
1633 | |||
1634 | err: | ||
1635 | return res; | ||
1636 | } | ||
1637 | |||
1638 | |||
1639 | #define PGP_VERSION "Version: 1\r\n" | ||
1640 | |||
1641 | static int pgp_sign_encrypt_mime(struct mailprivacy * privacy, | ||
1642 | struct mailmime * mime, struct mailmime ** result) | ||
1643 | { | ||
1644 | char original_filename[PATH_MAX]; | ||
1645 | FILE * original_f; | ||
1646 | int res; | ||
1647 | int r; | ||
1648 | int col; | ||
1649 | char encrypted_filename[PATH_MAX]; | ||
1650 | FILE * encrypted_f; | ||
1651 | char version_filename[PATH_MAX]; | ||
1652 | FILE * version_f; | ||
1653 | char command[PATH_MAX]; | ||
1654 | char quoted_original_filename[PATH_MAX]; | ||
1655 | char quoted_encrypted_filename[PATH_MAX]; | ||
1656 | char default_key[PATH_MAX]; | ||
1657 | struct mailmime * version_mime; | ||
1658 | struct mailmime * multipart; | ||
1659 | struct mailmime_content * content; | ||
1660 | struct mailmime_parameter * param; | ||
1661 | struct mailmime * encrypted_mime; | ||
1662 | char recipient[PATH_MAX]; | ||
1663 | struct mailimf_fields * fields; | ||
1664 | struct mailmime * root; | ||
1665 | size_t written; | ||
1666 | char * email; | ||
1667 | |||
1668 | root = mime; | ||
1669 | while (root->mm_parent != NULL) | ||
1670 | root = root->mm_parent; | ||
1671 | |||
1672 | fields = NULL; | ||
1673 | if (root->mm_type == MAILMIME_MESSAGE) | ||
1674 | fields = root->mm_data.mm_message.mm_fields; | ||
1675 | |||
1676 | /* recipient */ | ||
1677 | |||
1678 | collect_recipient(recipient, sizeof(recipient), fields); | ||
1679 | |||
1680 | /* get signing key */ | ||
1681 | |||
1682 | * default_key = '\0'; | ||
1683 | email = get_first_from_addr(mime); | ||
1684 | if (email != NULL) | ||
1685 | snprintf(default_key, sizeof(default_key), | ||
1686 | "--default-key %s", email); | ||
1687 | |||
1688 | /* part to encrypt */ | ||
1689 | |||
1690 | /* encode quoted printable all text parts */ | ||
1691 | |||
1692 | mailprivacy_prepare_mime(mime); | ||
1693 | |||
1694 | original_f = mailprivacy_get_tmp_file(privacy, original_filename, | ||
1695 | sizeof(original_filename)); | ||
1696 | if (original_f == NULL) { | ||
1697 | res = MAIL_ERROR_FILE; | ||
1698 | goto err; | ||
1699 | } | ||
1700 | |||
1701 | col = 0; | ||
1702 | r = mailmime_write(original_f, &col, mime); | ||
1703 | if (r != MAILIMF_NO_ERROR) { | ||
1704 | fclose(original_f); | ||
1705 | res = MAIL_ERROR_FILE; | ||
1706 | goto unlink_original; | ||
1707 | } | ||
1708 | |||
1709 | fclose(original_f); | ||
1710 | |||
1711 | /* prepare destination file for encryption */ | ||
1712 | |||
1713 | encrypted_f = mailprivacy_get_tmp_file(privacy, | ||
1714 | encrypted_filename, | ||
1715 | sizeof(encrypted_filename)); | ||
1716 | if (encrypted_f == NULL) { | ||
1717 | res = MAIL_ERROR_FILE; | ||
1718 | goto unlink_original; | ||
1719 | } | ||
1720 | fclose(encrypted_f); | ||
1721 | |||
1722 | r = mail_quote_filename(quoted_original_filename, | ||
1723 | sizeof(quoted_original_filename), original_filename); | ||
1724 | if (r < 0) { | ||
1725 | res = MAIL_ERROR_MEMORY; | ||
1726 | goto unlink_encrypted; | ||
1727 | } | ||
1728 | |||
1729 | r = mail_quote_filename(quoted_encrypted_filename, | ||
1730 | sizeof(quoted_encrypted_filename), encrypted_filename); | ||
1731 | if (r < 0) { | ||
1732 | res = MAIL_ERROR_MEMORY; | ||
1733 | goto unlink_encrypted; | ||
1734 | } | ||
1735 | |||
1736 | snprintf(command, sizeof(command), | ||
1737 | "gpg -q %s -a --batch --yes --digest-algo sha1 --out %s -s %s -e %s 2>/dev/null", | ||
1738 | recipient, quoted_encrypted_filename, default_key, | ||
1739 | quoted_original_filename); | ||
1740 | |||
1741 | r = system(command); | ||
1742 | if (WEXITSTATUS(r) != 0) { | ||
1743 | res = MAIL_ERROR_COMMAND; | ||
1744 | goto unlink_encrypted; | ||
1745 | } | ||
1746 | |||
1747 | /* multipart */ | ||
1748 | |||
1749 | multipart = mailprivacy_new_file_part(privacy, NULL, | ||
1750 | "multipart/encrypted", -1); | ||
1751 | |||
1752 | content = multipart->mm_content_type; | ||
1753 | |||
1754 | param = mailmime_param_new_with_data("protocol", | ||
1755 | "application/pgp-encrypted"); | ||
1756 | if (param == NULL) { | ||
1757 | mailmime_free(multipart); | ||
1758 | res = MAIL_ERROR_MEMORY; | ||
1759 | goto unlink_encrypted; | ||
1760 | } | ||
1761 | |||
1762 | r = clist_append(content->ct_parameters, param); | ||
1763 | if (r < 0) { | ||
1764 | mailmime_parameter_free(param); | ||
1765 | mailmime_free(multipart); | ||
1766 | res = MAIL_ERROR_MEMORY; | ||
1767 | goto unlink_encrypted; | ||
1768 | } | ||
1769 | |||
1770 | /* version part */ | ||
1771 | |||
1772 | version_f = mailprivacy_get_tmp_file(privacy, | ||
1773 | version_filename, | ||
1774 | sizeof(version_filename)); | ||
1775 | if (version_f == NULL) { | ||
1776 | mailprivacy_mime_clear(multipart); | ||
1777 | mailmime_free(multipart); | ||
1778 | res = MAIL_ERROR_FILE; | ||
1779 | goto unlink_encrypted; | ||
1780 | } | ||
1781 | written = fwrite(PGP_VERSION, 1, sizeof(PGP_VERSION) - 1, version_f); | ||
1782 | if (written != sizeof(PGP_VERSION) - 1) { | ||
1783 | fclose(version_f); | ||
1784 | mailprivacy_mime_clear(multipart); | ||
1785 | mailmime_free(multipart); | ||
1786 | res = MAIL_ERROR_FILE; | ||
1787 | goto unlink_encrypted; | ||
1788 | } | ||
1789 | fclose(version_f); | ||
1790 | |||
1791 | version_mime = mailprivacy_new_file_part(privacy, | ||
1792 | version_filename, | ||
1793 | "application/pgp-encrypted", | ||
1794 | MAILMIME_MECHANISM_8BIT); | ||
1795 | if (r != MAIL_NO_ERROR) { | ||
1796 | mailprivacy_mime_clear(multipart); | ||
1797 | mailmime_free(multipart); | ||
1798 | res = r; | ||
1799 | goto unlink_version; | ||
1800 | } | ||
1801 | |||
1802 | r = mailmime_smart_add_part(multipart, version_mime); | ||
1803 | if (r != MAIL_NO_ERROR) { | ||
1804 | mailprivacy_mime_clear(version_mime); | ||
1805 | mailmime_free(version_mime); | ||
1806 | mailprivacy_mime_clear(multipart); | ||
1807 | mailmime_free(multipart); | ||
1808 | res = MAIL_ERROR_MEMORY; | ||
1809 | goto unlink_version; | ||
1810 | } | ||
1811 | |||
1812 | /* encrypted part */ | ||
1813 | |||
1814 | encrypted_mime = mailprivacy_new_file_part(privacy, | ||
1815 | encrypted_filename, | ||
1816 | "application/octet-stream", | ||
1817 | MAILMIME_MECHANISM_8BIT); | ||
1818 | if (r != MAIL_NO_ERROR) { | ||
1819 | mailprivacy_mime_clear(multipart); | ||
1820 | mailmime_free(multipart); | ||
1821 | res = r; | ||
1822 | goto unlink_version; | ||
1823 | } | ||
1824 | |||
1825 | r = mailmime_smart_add_part(multipart, encrypted_mime); | ||
1826 | if (r != MAIL_NO_ERROR) { | ||
1827 | mailprivacy_mime_clear(encrypted_mime); | ||
1828 | mailmime_free(encrypted_mime); | ||
1829 | mailprivacy_mime_clear(multipart); | ||
1830 | mailmime_free(multipart); | ||
1831 | res = MAIL_ERROR_MEMORY; | ||
1832 | goto unlink_version; | ||
1833 | } | ||
1834 | |||
1835 | unlink(version_filename); | ||
1836 | unlink(encrypted_filename); | ||
1837 | unlink(original_filename); | ||
1838 | |||
1839 | * result = multipart; | ||
1840 | |||
1841 | return MAIL_NO_ERROR; | ||
1842 | |||
1843 | unlink_version: | ||
1844 | unlink(version_filename); | ||
1845 | unlink_encrypted: | ||
1846 | unlink(encrypted_filename); | ||
1847 | unlink_original: | ||
1848 | unlink(original_filename); | ||
1849 | err: | ||
1850 | return res; | ||
1851 | } | ||
1852 | |||
1853 | |||
1854 | static int pgp_encrypt_mime(struct mailprivacy * privacy, | ||
1855 | struct mailmime * mime, struct mailmime ** result) | ||
1856 | { | ||
1857 | char original_filename[PATH_MAX]; | ||
1858 | FILE * original_f; | ||
1859 | int res; | ||
1860 | int r; | ||
1861 | int col; | ||
1862 | char encrypted_filename[PATH_MAX]; | ||
1863 | FILE * encrypted_f; | ||
1864 | char version_filename[PATH_MAX]; | ||
1865 | FILE * version_f; | ||
1866 | char command[PATH_MAX]; | ||
1867 | char quoted_original_filename[PATH_MAX]; | ||
1868 | char quoted_encrypted_filename[PATH_MAX]; | ||
1869 | struct mailmime * version_mime; | ||
1870 | struct mailmime * multipart; | ||
1871 | struct mailmime_content * content; | ||
1872 | struct mailmime_parameter * param; | ||
1873 | struct mailmime * encrypted_mime; | ||
1874 | char recipient[PATH_MAX]; | ||
1875 | struct mailimf_fields * fields; | ||
1876 | struct mailmime * root; | ||
1877 | size_t written; | ||
1878 | |||
1879 | root = mime; | ||
1880 | while (root->mm_parent != NULL) | ||
1881 | root = root->mm_parent; | ||
1882 | |||
1883 | fields = NULL; | ||
1884 | if (root->mm_type == MAILMIME_MESSAGE) | ||
1885 | fields = root->mm_data.mm_message.mm_fields; | ||
1886 | |||
1887 | /* recipient */ | ||
1888 | |||
1889 | collect_recipient(recipient, sizeof(recipient), fields); | ||
1890 | |||
1891 | /* part to encrypt */ | ||
1892 | |||
1893 | /* encode quoted printable all text parts */ | ||
1894 | |||
1895 | mailprivacy_prepare_mime(mime); | ||
1896 | |||
1897 | original_f = mailprivacy_get_tmp_file(privacy, | ||
1898 | original_filename, sizeof(original_filename)); | ||
1899 | if (original_f == NULL) { | ||
1900 | res = MAIL_ERROR_FILE; | ||
1901 | goto err; | ||
1902 | } | ||
1903 | |||
1904 | col = 0; | ||
1905 | r = mailmime_write(original_f, &col, mime); | ||
1906 | if (r != MAILIMF_NO_ERROR) { | ||
1907 | fclose(original_f); | ||
1908 | res = MAIL_ERROR_FILE; | ||
1909 | goto unlink_original; | ||
1910 | } | ||
1911 | |||
1912 | fclose(original_f); | ||
1913 | |||
1914 | /* prepare destination file for encryption */ | ||
1915 | |||
1916 | encrypted_f = mailprivacy_get_tmp_file(privacy, | ||
1917 | encrypted_filename, | ||
1918 | sizeof(encrypted_filename)); | ||
1919 | if (encrypted_f == NULL) { | ||
1920 | res = MAIL_ERROR_FILE; | ||
1921 | goto unlink_original; | ||
1922 | } | ||
1923 | fclose(encrypted_f); | ||
1924 | |||
1925 | r = mail_quote_filename(quoted_original_filename, | ||
1926 | sizeof(quoted_original_filename), original_filename); | ||
1927 | if (r < 0) { | ||
1928 | res = MAIL_ERROR_MEMORY; | ||
1929 | goto unlink_encrypted; | ||
1930 | } | ||
1931 | |||
1932 | r = mail_quote_filename(quoted_encrypted_filename, | ||
1933 | sizeof(quoted_encrypted_filename), encrypted_filename); | ||
1934 | if (r < 0) { | ||
1935 | res = MAIL_ERROR_MEMORY; | ||
1936 | goto unlink_encrypted; | ||
1937 | } | ||
1938 | |||
1939 | snprintf(command, sizeof(command), | ||
1940 | "gpg -q %s -a --batch --yes --out %s -e %s 2>/dev/null", | ||
1941 | recipient, quoted_encrypted_filename, quoted_original_filename); | ||
1942 | |||
1943 | r = system(command); | ||
1944 | if (WEXITSTATUS(r) != 0) { | ||
1945 | res = MAIL_ERROR_COMMAND; | ||
1946 | goto unlink_encrypted; | ||
1947 | } | ||
1948 | |||
1949 | /* multipart */ | ||
1950 | |||
1951 | multipart = mailprivacy_new_file_part(privacy, NULL, | ||
1952 | "multipart/encrypted", -1); | ||
1953 | |||
1954 | content = multipart->mm_content_type; | ||
1955 | |||
1956 | param = mailmime_param_new_with_data("protocol", | ||
1957 | "application/pgp-encrypted"); | ||
1958 | if (param == NULL) { | ||
1959 | mailmime_free(multipart); | ||
1960 | res = MAIL_ERROR_MEMORY; | ||
1961 | goto unlink_encrypted; | ||
1962 | } | ||
1963 | |||
1964 | r = clist_append(content->ct_parameters, param); | ||
1965 | if (r < 0) { | ||
1966 | mailmime_parameter_free(param); | ||
1967 | mailmime_free(multipart); | ||
1968 | res = MAIL_ERROR_MEMORY; | ||
1969 | goto unlink_encrypted; | ||
1970 | } | ||
1971 | |||
1972 | /* version part */ | ||
1973 | |||
1974 | version_f = mailprivacy_get_tmp_file(privacy, | ||
1975 | version_filename, sizeof(version_filename)); | ||
1976 | if (version_f == NULL) { | ||
1977 | mailprivacy_mime_clear(multipart); | ||
1978 | mailmime_free(multipart); | ||
1979 | res = MAIL_ERROR_FILE; | ||
1980 | goto unlink_encrypted; | ||
1981 | } | ||
1982 | written = fwrite(PGP_VERSION, 1, sizeof(PGP_VERSION) - 1, version_f); | ||
1983 | if (written != sizeof(PGP_VERSION) - 1) { | ||
1984 | fclose(version_f); | ||
1985 | mailprivacy_mime_clear(multipart); | ||
1986 | mailmime_free(multipart); | ||
1987 | res = MAIL_ERROR_FILE; | ||
1988 | goto unlink_encrypted; | ||
1989 | } | ||
1990 | fclose(version_f); | ||
1991 | |||
1992 | version_mime = mailprivacy_new_file_part(privacy, | ||
1993 | version_filename, | ||
1994 | "application/pgp-encrypted", | ||
1995 | MAILMIME_MECHANISM_8BIT); | ||
1996 | if (r != MAIL_NO_ERROR) { | ||
1997 | mailprivacy_mime_clear(multipart); | ||
1998 | mailmime_free(multipart); | ||
1999 | res = r; | ||
2000 | goto unlink_version; | ||
2001 | } | ||
2002 | |||
2003 | r = mailmime_smart_add_part(multipart, version_mime); | ||
2004 | if (r != MAIL_NO_ERROR) { | ||
2005 | mailprivacy_mime_clear(version_mime); | ||
2006 | mailmime_free(version_mime); | ||
2007 | mailprivacy_mime_clear(multipart); | ||
2008 | mailmime_free(multipart); | ||
2009 | res = MAIL_ERROR_MEMORY; | ||
2010 | goto unlink_version; | ||
2011 | } | ||
2012 | |||
2013 | /* encrypted part */ | ||
2014 | |||
2015 | encrypted_mime = mailprivacy_new_file_part(privacy, | ||
2016 | encrypted_filename, | ||
2017 | "application/octet-stream", | ||
2018 | MAILMIME_MECHANISM_8BIT); | ||
2019 | if (r != MAIL_NO_ERROR) { | ||
2020 | mailprivacy_mime_clear(multipart); | ||
2021 | mailmime_free(multipart); | ||
2022 | res = r; | ||
2023 | goto unlink_version; | ||
2024 | } | ||
2025 | |||
2026 | r = mailmime_smart_add_part(multipart, encrypted_mime); | ||
2027 | if (r != MAIL_NO_ERROR) { | ||
2028 | mailprivacy_mime_clear(encrypted_mime); | ||
2029 | mailmime_free(encrypted_mime); | ||
2030 | mailprivacy_mime_clear(multipart); | ||
2031 | mailmime_free(multipart); | ||
2032 | res = MAIL_ERROR_MEMORY; | ||
2033 | goto unlink_version; | ||
2034 | } | ||
2035 | |||
2036 | unlink(version_filename); | ||
2037 | unlink(encrypted_filename); | ||
2038 | unlink(original_filename); | ||
2039 | |||
2040 | * result = multipart; | ||
2041 | |||
2042 | return MAIL_NO_ERROR; | ||
2043 | |||
2044 | unlink_version: | ||
2045 | unlink(version_filename); | ||
2046 | unlink_encrypted: | ||
2047 | unlink(encrypted_filename); | ||
2048 | unlink_original: | ||
2049 | unlink(original_filename); | ||
2050 | err: | ||
2051 | return res; | ||
2052 | } | ||
2053 | |||
2054 | static int pgp_clear_sign(struct mailprivacy * privacy, | ||
2055 | struct mailmime * mime, struct mailmime ** result) | ||
2056 | { | ||
2057 | char default_key[PATH_MAX]; | ||
2058 | char original_filename[PATH_MAX]; | ||
2059 | FILE * original_f; | ||
2060 | char signed_filename[PATH_MAX]; | ||
2061 | FILE * signed_f; | ||
2062 | char quoted_original_filename[PATH_MAX]; | ||
2063 | char quoted_signed_filename[PATH_MAX]; | ||
2064 | int col; | ||
2065 | struct mailmime * signed_mime; | ||
2066 | int res; | ||
2067 | int r; | ||
2068 | char command[PATH_MAX]; | ||
2069 | struct mailmime_content * content_type; | ||
2070 | char * email; | ||
2071 | |||
2072 | if (mime->mm_type != MAILMIME_SINGLE) { | ||
2073 | res = MAIL_ERROR_INVAL; | ||
2074 | goto err; | ||
2075 | } | ||
2076 | |||
2077 | if (mime->mm_data.mm_single == NULL) { | ||
2078 | res = MAIL_ERROR_INVAL; | ||
2079 | goto err; | ||
2080 | } | ||
2081 | |||
2082 | /* get signing key */ | ||
2083 | |||
2084 | * default_key = '\0'; | ||
2085 | email = get_first_from_addr(mime); | ||
2086 | if (email != NULL) | ||
2087 | snprintf(default_key, sizeof(default_key), | ||
2088 | "--default-key %s", email); | ||
2089 | |||
2090 | /* get part to sign */ | ||
2091 | |||
2092 | original_f = mailprivacy_get_tmp_file(privacy, | ||
2093 | original_filename, | ||
2094 | sizeof(original_filename)); | ||
2095 | if (original_f == NULL) { | ||
2096 | res = MAIL_ERROR_FILE; | ||
2097 | goto err; | ||
2098 | } | ||
2099 | |||
2100 | col = 0; | ||
2101 | r = mailmime_data_write(original_f, &col, mime->mm_data.mm_single, 1); | ||
2102 | if (r != MAILIMF_NO_ERROR) { | ||
2103 | fclose(original_f); | ||
2104 | res = MAIL_ERROR_FILE; | ||
2105 | goto unlink_original; | ||
2106 | } | ||
2107 | fclose(original_f); | ||
2108 | |||
2109 | signed_f = mailprivacy_get_tmp_file(privacy, | ||
2110 | signed_filename, | ||
2111 | sizeof(signed_filename)); | ||
2112 | if (signed_f == NULL) { | ||
2113 | res = MAIL_ERROR_FILE; | ||
2114 | goto unlink_original; | ||
2115 | } | ||
2116 | fclose(signed_f); | ||
2117 | |||
2118 | r = mail_quote_filename(quoted_original_filename, | ||
2119 | sizeof(quoted_original_filename), original_filename); | ||
2120 | if (r < 0) { | ||
2121 | res = MAIL_ERROR_MEMORY; | ||
2122 | goto unlink_signed; | ||
2123 | } | ||
2124 | |||
2125 | r = mail_quote_filename(quoted_signed_filename, | ||
2126 | sizeof(quoted_signed_filename), signed_filename); | ||
2127 | if (r < 0) { | ||
2128 | res = MAIL_ERROR_MEMORY; | ||
2129 | goto unlink_signed; | ||
2130 | } | ||
2131 | |||
2132 | snprintf(command, sizeof(command), | ||
2133 | "gpg -q --batch --yes --digest-algo sha1 --out %s %s --clearsign %s 2>/dev/null", | ||
2134 | quoted_signed_filename, default_key, quoted_original_filename); | ||
2135 | |||
2136 | r = system(command); | ||
2137 | if (WEXITSTATUS(r) != 0) { | ||
2138 | res = MAIL_ERROR_COMMAND; | ||
2139 | goto unlink_signed; | ||
2140 | } | ||
2141 | |||
2142 | /* building the signed part */ | ||
2143 | |||
2144 | signed_mime = mailprivacy_new_file_part(privacy, signed_filename, | ||
2145 | NULL, MAILMIME_MECHANISM_8BIT); | ||
2146 | if (signed_mime == NULL) { | ||
2147 | res = MAIL_ERROR_MEMORY; | ||
2148 | goto unlink_signed; | ||
2149 | } | ||
2150 | |||
2151 | /* place original content type */ | ||
2152 | |||
2153 | content_type = mailmime_content_dup(mime->mm_content_type); | ||
2154 | if (content_type == NULL) { | ||
2155 | mailprivacy_mime_clear(signed_mime); | ||
2156 | mailmime_free(signed_mime); | ||
2157 | res = MAIL_ERROR_MEMORY; | ||
2158 | goto unlink_signed; | ||
2159 | } | ||
2160 | |||
2161 | mailmime_content_free(signed_mime->mm_content_type); | ||
2162 | signed_mime->mm_content_type = content_type; | ||
2163 | |||
2164 | /* place original MIME fields */ | ||
2165 | |||
2166 | if (mime->mm_mime_fields != NULL) { | ||
2167 | struct mailmime_fields * mime_fields; | ||
2168 | clistiter * cur; | ||
2169 | |||
2170 | mime_fields = mailprivacy_mime_fields_dup(privacy, | ||
2171 | mime->mm_mime_fields); | ||
2172 | if (mime_fields == NULL) { | ||
2173 | mailprivacy_mime_clear(signed_mime); | ||
2174 | mailmime_free(signed_mime); | ||
2175 | res = MAIL_ERROR_MEMORY; | ||
2176 | goto unlink_signed; | ||
2177 | } | ||
2178 | for(cur = clist_begin(mime_fields->fld_list) ; | ||
2179 | cur != NULL ; cur = clist_next(cur)) { | ||
2180 | struct mailmime_field * field; | ||
2181 | |||
2182 | field = clist_content(cur); | ||
2183 | if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) { | ||
2184 | mailmime_field_free(field); | ||
2185 | clist_delete(mime_fields->fld_list, cur); | ||
2186 | break; | ||
2187 | } | ||
2188 | } | ||
2189 | clist_concat(signed_mime->mm_mime_fields->fld_list, | ||
2190 | mime_fields->fld_list); | ||
2191 | mailmime_fields_free(mime_fields); | ||
2192 | } | ||
2193 | |||
2194 | unlink(signed_filename); | ||
2195 | unlink(original_filename); | ||
2196 | |||
2197 | * result = signed_mime; | ||
2198 | |||
2199 | return MAIL_NO_ERROR; | ||
2200 | |||
2201 | unlink_signed: | ||
2202 | unlink(signed_filename); | ||
2203 | unlink_original: | ||
2204 | unlink(original_filename); | ||
2205 | err: | ||
2206 | return res; | ||
2207 | } | ||
2208 | |||
2209 | |||
2210 | static int pgp_armor_encrypt(struct mailprivacy * privacy, | ||
2211 | struct mailmime * mime, struct mailmime ** result) | ||
2212 | { | ||
2213 | char original_filename[PATH_MAX]; | ||
2214 | FILE * original_f; | ||
2215 | char encrypted_filename[PATH_MAX]; | ||
2216 | FILE * encrypted_f; | ||
2217 | char quoted_original_filename[PATH_MAX]; | ||
2218 | char quoted_encrypted_filename[PATH_MAX]; | ||
2219 | int col; | ||
2220 | struct mailmime * encrypted_mime; | ||
2221 | int res; | ||
2222 | int r; | ||
2223 | char command[PATH_MAX]; | ||
2224 | struct mailmime_content * content_type; | ||
2225 | struct mailmime * root; | ||
2226 | struct mailimf_fields * fields; | ||
2227 | char recipient[PATH_MAX]; | ||
2228 | |||
2229 | if (mime->mm_type != MAILMIME_SINGLE) { | ||
2230 | res = MAIL_ERROR_INVAL; | ||
2231 | goto err; | ||
2232 | } | ||
2233 | |||
2234 | if (mime->mm_data.mm_single == NULL) { | ||
2235 | res = MAIL_ERROR_INVAL; | ||
2236 | goto err; | ||
2237 | } | ||
2238 | |||
2239 | root = mime; | ||
2240 | while (root->mm_parent != NULL) | ||
2241 | root = root->mm_parent; | ||
2242 | |||
2243 | fields = NULL; | ||
2244 | if (root->mm_type == MAILMIME_MESSAGE) | ||
2245 | fields = root->mm_data.mm_message.mm_fields; | ||
2246 | |||
2247 | /* recipient */ | ||
2248 | |||
2249 | collect_recipient(recipient, sizeof(recipient), fields); | ||
2250 | |||
2251 | /* get part to encrypt */ | ||
2252 | |||
2253 | original_f = mailprivacy_get_tmp_file(privacy, original_filename, | ||
2254 | sizeof(original_filename)); | ||
2255 | if (original_f == NULL) { | ||
2256 | res = MAIL_ERROR_FILE; | ||
2257 | goto err; | ||
2258 | } | ||
2259 | |||
2260 | col = 0; | ||
2261 | r = mailmime_data_write(original_f, &col, mime->mm_data.mm_single, 1); | ||
2262 | if (r != MAILIMF_NO_ERROR) { | ||
2263 | fclose(original_f); | ||
2264 | res = MAIL_ERROR_FILE; | ||
2265 | goto unlink_original; | ||
2266 | } | ||
2267 | fclose(original_f); | ||
2268 | |||
2269 | encrypted_f = mailprivacy_get_tmp_file(privacy, | ||
2270 | encrypted_filename, | ||
2271 | sizeof(encrypted_filename)); | ||
2272 | if (encrypted_f == NULL) { | ||
2273 | res = MAIL_ERROR_FILE; | ||
2274 | goto unlink_original; | ||
2275 | } | ||
2276 | fclose(encrypted_f); | ||
2277 | |||
2278 | r = mail_quote_filename(quoted_original_filename, | ||
2279 | sizeof(quoted_original_filename), original_filename); | ||
2280 | if (r < 0) { | ||
2281 | res = MAIL_ERROR_MEMORY; | ||
2282 | goto unlink_encrypted; | ||
2283 | } | ||
2284 | |||
2285 | r = mail_quote_filename(quoted_encrypted_filename, | ||
2286 | sizeof(quoted_encrypted_filename), encrypted_filename); | ||
2287 | if (r < 0) { | ||
2288 | res = MAIL_ERROR_MEMORY; | ||
2289 | goto unlink_encrypted; | ||
2290 | } | ||
2291 | |||
2292 | snprintf(command, sizeof(command), | ||
2293 | "gpg -q %s --batch --yes --out %s -e --armor %s 2>/dev/null", | ||
2294 | recipient, quoted_encrypted_filename, quoted_original_filename); | ||
2295 | |||
2296 | r = system(command); | ||
2297 | if (WEXITSTATUS(r) != 0) { | ||
2298 | res = MAIL_ERROR_COMMAND; | ||
2299 | goto unlink_encrypted; | ||
2300 | } | ||
2301 | |||
2302 | /* building the encrypted part */ | ||
2303 | |||
2304 | encrypted_mime = mailprivacy_new_file_part(privacy, | ||
2305 | encrypted_filename, | ||
2306 | "application/octet-stream", | ||
2307 | MAILMIME_MECHANISM_8BIT); | ||
2308 | if (encrypted_mime == NULL) { | ||
2309 | res = MAIL_ERROR_MEMORY; | ||
2310 | goto unlink_encrypted; | ||
2311 | } | ||
2312 | |||
2313 | /* place original content type */ | ||
2314 | |||
2315 | content_type = mailmime_content_dup(mime->mm_content_type); | ||
2316 | if (content_type == NULL) { | ||
2317 | mailprivacy_mime_clear(encrypted_mime); | ||
2318 | mailmime_free(encrypted_mime); | ||
2319 | res = MAIL_ERROR_MEMORY; | ||
2320 | goto unlink_encrypted; | ||
2321 | } | ||
2322 | |||
2323 | mailmime_content_free(encrypted_mime->mm_content_type); | ||
2324 | encrypted_mime->mm_content_type = content_type; | ||
2325 | |||
2326 | /* place original MIME fields */ | ||
2327 | |||
2328 | if (mime->mm_mime_fields != NULL) { | ||
2329 | struct mailmime_fields * mime_fields; | ||
2330 | clistiter * cur; | ||
2331 | |||
2332 | mime_fields = mailprivacy_mime_fields_dup(privacy, mime->mm_mime_fields); | ||
2333 | if (mime_fields == NULL) { | ||
2334 | mailprivacy_mime_clear(encrypted_mime); | ||
2335 | mailmime_free(encrypted_mime); | ||
2336 | res = MAIL_ERROR_MEMORY; | ||
2337 | goto unlink_encrypted; | ||
2338 | } | ||
2339 | for(cur = clist_begin(mime_fields->fld_list) ; | ||
2340 | cur != NULL ; cur = clist_next(cur)) { | ||
2341 | struct mailmime_field * field; | ||
2342 | |||
2343 | field = clist_content(cur); | ||
2344 | if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) { | ||
2345 | mailmime_field_free(field); | ||
2346 | clist_delete(mime_fields->fld_list, cur); | ||
2347 | break; | ||
2348 | } | ||
2349 | } | ||
2350 | clist_concat(encrypted_mime->mm_mime_fields->fld_list, | ||
2351 | mime_fields->fld_list); | ||
2352 | mailmime_fields_free(mime_fields); | ||
2353 | } | ||
2354 | |||
2355 | unlink(encrypted_filename); | ||
2356 | unlink(original_filename); | ||
2357 | |||
2358 | * result = encrypted_mime; | ||
2359 | |||
2360 | return MAIL_NO_ERROR; | ||
2361 | |||
2362 | unlink_encrypted: | ||
2363 | unlink(encrypted_filename); | ||
2364 | unlink_original: | ||
2365 | unlink(original_filename); | ||
2366 | err: | ||
2367 | return res; | ||
2368 | } | ||
2369 | |||
2370 | |||
2371 | static int pgp_armor_sign_encrypt(struct mailprivacy * privacy, | ||
2372 | struct mailmime * mime, struct mailmime ** result) | ||
2373 | { | ||
2374 | char default_key[PATH_MAX]; | ||
2375 | char original_filename[PATH_MAX]; | ||
2376 | FILE * original_f; | ||
2377 | char encrypted_filename[PATH_MAX]; | ||
2378 | FILE * encrypted_f; | ||
2379 | char quoted_original_filename[PATH_MAX]; | ||
2380 | char quoted_encrypted_filename[PATH_MAX]; | ||
2381 | int col; | ||
2382 | struct mailmime * encrypted_mime; | ||
2383 | int res; | ||
2384 | int r; | ||
2385 | char command[PATH_MAX]; | ||
2386 | struct mailmime_content * content_type; | ||
2387 | struct mailmime * root; | ||
2388 | struct mailimf_fields * fields; | ||
2389 | char recipient[PATH_MAX]; | ||
2390 | char * email; | ||
2391 | |||
2392 | if (mime->mm_type != MAILMIME_SINGLE) { | ||
2393 | res = MAIL_ERROR_INVAL; | ||
2394 | goto err; | ||
2395 | } | ||
2396 | |||
2397 | if (mime->mm_data.mm_single == NULL) { | ||
2398 | res = MAIL_ERROR_INVAL; | ||
2399 | goto err; | ||
2400 | } | ||
2401 | |||
2402 | /* get signing key */ | ||
2403 | |||
2404 | * default_key = '\0'; | ||
2405 | email = get_first_from_addr(mime); | ||
2406 | if (email != NULL) | ||
2407 | snprintf(default_key, sizeof(default_key), | ||
2408 | "--default-key %s", email); | ||
2409 | |||
2410 | root = mime; | ||
2411 | while (root->mm_parent != NULL) | ||
2412 | root = root->mm_parent; | ||
2413 | |||
2414 | fields = NULL; | ||
2415 | if (root->mm_type == MAILMIME_MESSAGE) | ||
2416 | fields = root->mm_data.mm_message.mm_fields; | ||
2417 | |||
2418 | /* recipient */ | ||
2419 | |||
2420 | collect_recipient(recipient, sizeof(recipient), fields); | ||
2421 | |||
2422 | /* get part to encrypt */ | ||
2423 | |||
2424 | original_f = mailprivacy_get_tmp_file(privacy, | ||
2425 | original_filename, | ||
2426 | sizeof(original_filename)); | ||
2427 | if (original_f == NULL) { | ||
2428 | res = MAIL_ERROR_FILE; | ||
2429 | goto err; | ||
2430 | } | ||
2431 | |||
2432 | col = 0; | ||
2433 | r = mailmime_data_write(original_f, &col, mime->mm_data.mm_single, 1); | ||
2434 | if (r != MAILIMF_NO_ERROR) { | ||
2435 | fclose(original_f); | ||
2436 | res = MAIL_ERROR_FILE; | ||
2437 | goto unlink_original; | ||
2438 | } | ||
2439 | fclose(original_f); | ||
2440 | |||
2441 | encrypted_f = mailprivacy_get_tmp_file(privacy, | ||
2442 | encrypted_filename, | ||
2443 | sizeof(encrypted_filename)); | ||
2444 | if (encrypted_f == NULL) { | ||
2445 | res = MAIL_ERROR_FILE; | ||
2446 | goto unlink_original; | ||
2447 | } | ||
2448 | fclose(encrypted_f); | ||
2449 | |||
2450 | r = mail_quote_filename(quoted_original_filename, | ||
2451 | sizeof(quoted_original_filename), original_filename); | ||
2452 | if (r < 0) { | ||
2453 | res = MAIL_ERROR_MEMORY; | ||
2454 | goto unlink_encrypted; | ||
2455 | } | ||
2456 | |||
2457 | r = mail_quote_filename(quoted_encrypted_filename, | ||
2458 | sizeof(quoted_encrypted_filename), encrypted_filename); | ||
2459 | if (r < 0) { | ||
2460 | res = MAIL_ERROR_MEMORY; | ||
2461 | goto unlink_encrypted; | ||
2462 | } | ||
2463 | |||
2464 | snprintf(command, sizeof(command), | ||
2465 | "gpg -q %s --batch --yes --digest-algo sha1 " | ||
2466 | "--out %s %s -e -s -a %s 2>/dev/null", | ||
2467 | recipient, encrypted_filename, default_key, original_filename); | ||
2468 | |||
2469 | r = system(command); | ||
2470 | if (WEXITSTATUS(r) != 0) { | ||
2471 | res = MAIL_ERROR_COMMAND; | ||
2472 | goto unlink_encrypted; | ||
2473 | } | ||
2474 | |||
2475 | /* building the encrypted part */ | ||
2476 | |||
2477 | encrypted_mime = mailprivacy_new_file_part(privacy, | ||
2478 | encrypted_filename, | ||
2479 | "application/octet-stream", | ||
2480 | MAILMIME_MECHANISM_8BIT); | ||
2481 | if (encrypted_mime == NULL) { | ||
2482 | res = MAIL_ERROR_MEMORY; | ||
2483 | goto unlink_encrypted; | ||
2484 | } | ||
2485 | |||
2486 | /* place original content type */ | ||
2487 | |||
2488 | content_type = mailmime_content_dup(mime->mm_content_type); | ||
2489 | if (content_type == NULL) { | ||
2490 | mailprivacy_mime_clear(encrypted_mime); | ||
2491 | mailmime_free(encrypted_mime); | ||
2492 | res = MAIL_ERROR_MEMORY; | ||
2493 | goto unlink_encrypted; | ||
2494 | } | ||
2495 | |||
2496 | mailmime_content_free(encrypted_mime->mm_content_type); | ||
2497 | encrypted_mime->mm_content_type = content_type; | ||
2498 | |||
2499 | /* place original MIME fields */ | ||
2500 | |||
2501 | if (mime->mm_mime_fields != NULL) { | ||
2502 | struct mailmime_fields * mime_fields; | ||
2503 | clistiter * cur; | ||
2504 | |||
2505 | mime_fields = mailprivacy_mime_fields_dup(privacy, mime->mm_mime_fields); | ||
2506 | if (mime_fields == NULL) { | ||
2507 | mailprivacy_mime_clear(encrypted_mime); | ||
2508 | mailmime_free(encrypted_mime); | ||
2509 | res = MAIL_ERROR_MEMORY; | ||
2510 | goto unlink_encrypted; | ||
2511 | } | ||
2512 | for(cur = clist_begin(mime_fields->fld_list) ; | ||
2513 | cur != NULL ; cur = clist_next(cur)) { | ||
2514 | struct mailmime_field * field; | ||
2515 | |||
2516 | field = clist_content(cur); | ||
2517 | if (field->fld_type == MAILMIME_FIELD_TRANSFER_ENCODING) { | ||
2518 | mailmime_field_free(field); | ||
2519 | clist_delete(mime_fields->fld_list, cur); | ||
2520 | break; | ||
2521 | } | ||
2522 | } | ||
2523 | clist_concat(encrypted_mime->mm_mime_fields->fld_list, | ||
2524 | mime_fields->fld_list); | ||
2525 | mailmime_fields_free(mime_fields); | ||
2526 | } | ||
2527 | |||
2528 | unlink(encrypted_filename); | ||
2529 | unlink(original_filename); | ||
2530 | |||
2531 | * result = encrypted_mime; | ||
2532 | |||
2533 | return MAIL_NO_ERROR; | ||
2534 | |||
2535 | unlink_encrypted: | ||
2536 | unlink(encrypted_filename); | ||
2537 | unlink_original: | ||
2538 | unlink(original_filename); | ||
2539 | err: | ||
2540 | return res; | ||
2541 | } | ||
2542 | |||
2543 | |||
2544 | static struct mailprivacy_encryption pgp_encryption_tab[] = { | ||
2545 | /* PGP signed part */ | ||
2546 | { | ||
2547 | .name = "signed", | ||
2548 | .description = "PGP signed part", | ||
2549 | .encrypt = pgp_sign_mime, | ||
2550 | }, | ||
2551 | |||
2552 | /* PGP encrypted part */ | ||
2553 | |||
2554 | { | ||
2555 | .name = "encrypted", | ||
2556 | .description = "PGP encrypted part", | ||
2557 | .encrypt = pgp_encrypt_mime, | ||
2558 | }, | ||
2559 | |||
2560 | /* PGP signed & encrypted part */ | ||
2561 | |||
2562 | { | ||
2563 | .name = "signed-encrypted", | ||
2564 | .description = "PGP signed & encrypted part", | ||
2565 | .encrypt = pgp_sign_encrypt_mime, | ||
2566 | }, | ||
2567 | |||
2568 | /* PGP clear signed part */ | ||
2569 | |||
2570 | { | ||
2571 | .name = "clear-signed", | ||
2572 | .description = "PGP clear signed part", | ||
2573 | .encrypt = pgp_clear_sign, | ||
2574 | }, | ||
2575 | |||
2576 | /* PGP armor encrypted part */ | ||
2577 | |||
2578 | { | ||
2579 | .name = "encrypted-armor", | ||
2580 | .description = "PGP ASCII armor encrypted part", | ||
2581 | .encrypt = pgp_armor_encrypt, | ||
2582 | }, | ||
2583 | |||
2584 | /* PGP armor signed & encrypted part */ | ||
2585 | |||
2586 | { | ||
2587 | .name = "signed-encrypted-armor", | ||
2588 | .description = "PGP ASCII armor signed & encrypted part", | ||
2589 | .encrypt = pgp_armor_sign_encrypt, | ||
2590 | }, | ||
2591 | }; | ||
2592 | |||
2593 | static struct mailprivacy_protocol pgp_protocol = { | ||
2594 | .name = "pgp", | ||
2595 | .description = "OpenPGP", | ||
2596 | |||
2597 | .is_encrypted = pgp_test_encrypted, | ||
2598 | .decrypt = pgp_handler, | ||
2599 | |||
2600 | .encryption_count = | ||
2601 | (sizeof(pgp_encryption_tab) / sizeof(pgp_encryption_tab[0])), | ||
2602 | |||
2603 | .encryption_tab = pgp_encryption_tab, | ||
2604 | }; | ||
2605 | |||
2606 | int mailprivacy_gnupg_init(struct mailprivacy * privacy) | ||
2607 | { | ||
2608 | return mailprivacy_register(privacy, &pgp_protocol); | ||
2609 | } | ||
2610 | |||
2611 | void mailprivacy_gnupg_done(struct mailprivacy * privacy) | ||
2612 | { | ||
2613 | mailprivacy_unregister(privacy, &pgp_protocol); | ||
2614 | } | ||