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