summaryrefslogtreecommitdiffabout
path: root/libetpan/src/engine/mailprivacy_gnupg.c
Unidiff
Diffstat (limited to 'libetpan/src/engine/mailprivacy_gnupg.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/engine/mailprivacy_gnupg.c2614
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
51static 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
74static 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
99int 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
110int 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
122enum {
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
131static 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
181static 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
211static 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
411static int
412pgp_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
602static 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
843static 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
1046static 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
1065static 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
1123static 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
1208static 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
1267static 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
1297static 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
1504static 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
1523static 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
1543static 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
1549static 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
1568static 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
1589static 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
1641static 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
1854static 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
2054static 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
2210static 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
2371static 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
2544static 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
2593static 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
2606int mailprivacy_gnupg_init(struct mailprivacy * privacy)
2607{
2608 return mailprivacy_register(privacy, &pgp_protocol);
2609}
2610
2611void mailprivacy_gnupg_done(struct mailprivacy * privacy)
2612{
2613 mailprivacy_unregister(privacy, &pgp_protocol);
2614}