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             &current_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