1 /*
2 ** Copyright 2001-2006 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 static const char rcsid[]="$Id: gpg.c,v 1.12 2007/07/04 02:24:38 mrsam Exp $";
7
8 #include "config.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <time.h>
16 #if HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif
19 #include <sys/types.h>
20 #if HAVE_SYS_TIME_H
21 #include <sys/time.h>
22 #endif
23 #if HAVE_SYS_WAIT_H
24 #include <sys/wait.h>
25 #endif
26 #ifndef WEXITSTATUS
27 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
28 #endif
29 #ifndef WIFEXITED
30 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
31 #endif
32
33 #include "mimegpgheader.h"
34 #include "mimegpgstack.h"
35 #include "mimegpgfork.h"
36 #include "tempname.h"
37 #include "gpglib.h"
38 #include "rfc822/encode.h"
39 #include "rfc2045/rfc2045.h"
40
my_rewind(FILE * fp)41 static int my_rewind(FILE *fp)
42 {
43 if (fflush(fp) || ferror(fp) || fseek(fp, 0L, SEEK_SET))
44 return (-1);
45 clearerr(fp);
46 return (0);
47 }
48
libmail_gpg_inputfunc_readfp(char * buf,size_t cnt,void * vp)49 int libmail_gpg_inputfunc_readfp(char *buf, size_t cnt, void *vp)
50 {
51 FILE *fp=(FILE *)vp;
52 size_t i;
53 int c;
54
55 if (cnt == 0)
56 return -1;
57
58 --cnt;
59
60 for (i=0; i<cnt; i++)
61 {
62 if ((c=getc(fp)) == EOF)
63 {
64 if (i == 0)
65 return -1;
66 break;
67 }
68 buf[i]=c;
69
70 if (c == '\n')
71 {
72 ++i;
73 break;
74 }
75 }
76 buf[i]=0;
77 return 0;
78 }
79
libmail_gpg_noexec(int fd)80 void libmail_gpg_noexec(int fd)
81 {
82 #ifdef FD_CLOEXEC
83 fcntl(fd, F_SETFD, FD_CLOEXEC);
84 #endif
85 }
86
87 /*
88 ** Check if the line just read is a MIME boundary line. Search the
89 ** current MIME stack for a matching MIME boundary delimiter.
90 */
91
is_boundary(struct mimestack * s,const char * line,int * isclosing)92 static struct mimestack *is_boundary(struct mimestack *s, const char *line,
93 int *isclosing)
94 {
95 struct mimestack *b;
96
97 if (line[0] != '-' || line[1] != '-' ||
98 (b=libmail_mimestack_search(s, line+2)) == 0)
99 return (NULL);
100
101
102 *isclosing=strncmp(line+2+strlen(b->boundary), "--", 2) == 0;
103 return (b);
104 }
105
106 static const char *get_boundary(struct mimestack *,
107 const char *,
108 FILE *);
109
110 /*
111 ** Skip until EOF or a MIME boundary delimiter other than a closing MIME
112 ** boundary delimiter. After returning from bind_boundary we expect to
113 ** see MIME headers. Copy any intermediate lines to fpout.
114 */
115
find_boundary(struct mimestack ** stack,int * iseof,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int doappend)116 static void find_boundary(struct mimestack **stack, int *iseof,
117 int (*input_func)(char *, size_t, void *vp),
118 void *input_func_arg,
119 void (*output_func)(const char *,
120 size_t,
121 void *),
122 void *output_func_arg,
123 int doappend)
124 {
125 char buf[BUFSIZ];
126
127 for (;;)
128 {
129 int is_closing;
130 struct mimestack *b;
131
132 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
133 {
134 *iseof=1;
135 return;
136 }
137
138 if (!(b=is_boundary(*stack, buf, &is_closing)))
139 {
140 if (output_func)
141 (*output_func)(buf, strlen(buf),
142 output_func_arg);
143
144 while (strchr(buf, '\n') == 0)
145 {
146 if ( (*input_func)(buf, sizeof(buf),
147 input_func_arg))
148 {
149 *iseof=1;
150 return;
151 }
152 if (output_func)
153 (*output_func)(buf, strlen(buf),
154 output_func_arg);
155 }
156 continue;
157 }
158
159 if (output_func)
160 {
161 (*output_func)("--", 2, output_func_arg);
162 (*output_func)(b->boundary, strlen(b->boundary),
163 output_func_arg);
164
165 if (is_closing)
166 (*output_func)("--", 2, output_func_arg);
167
168 (*output_func)("\n", 1, output_func_arg);
169 }
170
171 if (is_closing)
172 {
173 libmail_mimestack_pop_to(stack, b);
174 continue;
175 }
176 break;
177 }
178 }
179
180
181 /*
182 ** Read a set of headers.
183 */
184
read_headers(struct mimestack ** stack,int * iseof,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int doappend,int * errflag)185 static struct header *read_headers(struct mimestack **stack, int *iseof,
186 int (*input_func)(char *, size_t, void *vp),
187 void *input_func_arg,
188 void (*output_func)(const char *,
189 size_t,
190 void *),
191 void *output_func_arg,
192 int doappend,
193 int *errflag)
194 {
195 char buf[BUFSIZ];
196 struct read_header_context rhc;
197 struct header *h;
198
199 *errflag=0;
200 libmail_readheader_init(&rhc);
201
202 while (!*iseof)
203 {
204 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
205 {
206 *iseof=1;
207 break;
208 }
209
210 if (READ_START_OF_LINE(rhc))
211 {
212 struct mimestack *b;
213 int is_closing;
214
215 if (strcmp(buf, "\n") == 0
216 || strcmp(buf, "\r\n") == 0)
217 break;
218
219 b=is_boundary(*stack, buf, &is_closing);
220
221 if (b)
222 {
223 /*
224 ** Corrupted MIME message. We should NOT
225 ** see a MIME boundary in the middle of the
226 ** headers!
227 **
228 ** Ignore this damage.
229 */
230
231 struct header *p;
232
233 h=libmail_readheader_finish(&rhc);
234
235 for (p=h; p; p=p->next)
236 (*output_func)(p->header,
237 strlen(p->header),
238 output_func_arg);
239
240 (*output_func)("--", 2, output_func_arg);
241 (*output_func)(b->boundary,
242 strlen(b->boundary),
243 output_func_arg);
244
245 if (is_closing)
246 (*output_func)("--", 2,
247 output_func_arg);
248
249 (*output_func)("\n", 1, output_func_arg);
250
251 if (is_closing)
252 {
253 libmail_mimestack_pop_to(stack, b);
254 find_boundary(stack, iseof,
255 input_func,
256 input_func_arg,
257 output_func,
258 output_func_arg,
259 doappend);
260 }
261 libmail_header_free(h);
262
263 libmail_readheader_init(&rhc);
264 continue; /* From the top */
265 }
266 }
267 if (libmail_readheader(&rhc, buf) < 0)
268 {
269 libmail_header_free(libmail_readheader_finish(&rhc));
270 *errflag= -1;
271 return NULL;
272 }
273 }
274
275 return (libmail_readheader_finish(&rhc));
276 }
277
278 /*
279 ** Here we do actual signing/encoding
280 */
281
encode_header(const char * h)282 static int encode_header(const char *h)
283 {
284 if (strncasecmp(h, "content-", 8) == 0)
285 return (1);
286 return (0);
287 }
288
289 struct gpg_fork_output_info {
290 void (*output_func)(const char *, size_t, void *);
291 void *output_func_arg;
292 struct gpgmime_forkinfo *gpgptr;
293 };
294
gpg_fork_output(const char * p,size_t n,void * dummy)295 static int gpg_fork_output(const char *p, size_t n, void *dummy)
296 {
297 struct gpg_fork_output_info *info=(struct gpg_fork_output_info *)dummy;
298
299 (*info->output_func)(p, n, info->output_func_arg);
300 return 0;
301 }
302
303
dogpgencrypt(const char * gpghome,const char * passphrase_fd,struct mimestack ** stack,struct header * h,int * iseof,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int argc,char ** argv,int dosign,void (* errhandler)(const char *,void *),void * errhandler_arg)304 static int dogpgencrypt(const char *gpghome,
305 const char *passphrase_fd,
306 struct mimestack **stack,
307 struct header *h, int *iseof,
308 int (*input_func)(char *, size_t, void *vp),
309 void *input_func_arg,
310 void (*output_func)(const char *,
311 size_t,
312 void *),
313 void *output_func_arg,
314 int argc,
315 char **argv,
316 int dosign,
317 void (*errhandler)(const char *, void *),
318 void *errhandler_arg)
319 {
320 struct header *hp;
321 char buf[BUFSIZ];
322 struct gpgmime_forkinfo gpg;
323 int clos_flag=0;
324 struct mimestack *b=0;
325 int rc;
326 const char *boundary;
327 int need_crlf;
328 struct gpg_fork_output_info gfoi;
329
330 boundary=get_boundary(*stack, "", NULL);
331
332 gfoi.output_func=output_func;
333 gfoi.output_func_arg=output_func_arg;
334
335 if (libmail_gpgmime_forksignencrypt(gpghome, passphrase_fd,
336 (dosign ? GPG_SE_SIGN:0)
337 | GPG_SE_ENCRYPT,
338 argc, argv,
339 &gpg_fork_output, &gfoi,
340 &gpg))
341 {
342 return -1;
343 }
344
345 for (hp=h; hp; hp=hp->next)
346 {
347 if (encode_header(hp->header))
348 continue;
349
350 (*output_func)(hp->header, strlen(hp->header),
351 output_func_arg);
352 }
353
354 #define C(s) (*output_func)( s, sizeof(s)-1, output_func_arg)
355 #define S(s) (*output_func)( s, strlen(s), output_func_arg)
356
357
358 C("Content-Type: multipart/encrypted;\n"
359 " boundary=\"");
360
361 S(boundary);
362
363 C("\";\n"
364 " protocol=\"application/pgp-encrypted\"\n"
365 "\n"
366 "This is a MIME GnuPG-encrypted message. If you see this text, it means\n"
367 "that your E-mail or Usenet software does not support MIME encrypted messages.\n"
368 "The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.\n"
369 "To open this message correctly you will need to install E-mail or Usenet\n"
370 "software that supports modern Internet standards.\n"
371 "\n--");
372
373 S(boundary);
374
375 C("\n"
376 "Content-Type: application/pgp-encrypted\n"
377 "Content-Transfer-Encoding: 7bit\n"
378 "\n"
379 "Version: 1\n"
380 "\n--");
381
382 S(boundary);
383
384 C("\n"
385 "Content-Type: application/octet-stream\n"
386 "Content-Transfer-Encoding: 7bit\n\n");
387
388 #undef C
389 #undef S
390
391 /* For Eudora compatiblity */
392 libmail_gpgmime_write(&gpg, "Mime-Version: 1.0\r\n", 19);
393
394 for (hp=h; hp; hp=hp->next)
395 {
396 const char *p;
397
398 if (!encode_header(hp->header))
399 continue;
400
401 for (p=hp->header; *p; p++)
402 {
403 if (*p == '\r')
404 continue;
405
406 if (*p == '\n')
407 libmail_gpgmime_write(&gpg, "\r\n", 2);
408 else
409 libmail_gpgmime_write(&gpg, p, 1);
410 }
411 }
412
413 /*
414 ** Chew the content until the next MIME boundary.
415 */
416 need_crlf=1;
417
418 while (!*iseof)
419 {
420 const char *p;
421
422 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
423 {
424 *iseof=1;
425 break;
426 }
427
428 if (need_crlf)
429 {
430 if ((b=is_boundary(*stack, buf, &clos_flag)) != NULL)
431 break;
432
433 libmail_gpgmime_write(&gpg, "\r\n", 2);
434 }
435
436 need_crlf=0;
437 for (;;)
438 {
439 for (p=buf; *p; p++)
440 {
441 if (*p == '\r')
442 continue;
443 if (*p == '\n')
444 {
445 need_crlf=1;
446 break;
447 }
448
449 libmail_gpgmime_write(&gpg, p, 1);
450 }
451 if (*p == '\n')
452 break;
453
454 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
455 {
456 *iseof=1;
457 break;
458 }
459 }
460 }
461
462 /*
463 ** This needs some 'splainin. Note that we spit out a newline at
464 ** the BEGINNING of each line, above. This generates the blank
465 ** header->body separator line. Now, if we're NOT doing multiline
466 ** content, we need to follow the last line of the content with a
467 ** newline. If we're already doing multiline content, that extra
468 ** newline (if it exists) is already there.
469 */
470
471 if (!*stack)
472 {
473 libmail_gpgmime_write(&gpg, "\r\n", 2);
474 }
475
476 rc=libmail_gpgmime_finish(&gpg);
477
478 if (rc)
479 {
480 (*errhandler)(libmail_gpgmime_getoutput(&gpg), errhandler_arg);
481 return (-1);
482 }
483
484 (*output_func)("\n--", 3, output_func_arg);
485 (*output_func)(boundary, strlen(boundary), output_func_arg);
486 (*output_func)("--\n", 3, output_func_arg);
487
488 if (*iseof)
489 return 0;
490
491 (*output_func)("\n--", 3, output_func_arg);
492 (*output_func)(b->boundary, strlen(b->boundary), output_func_arg);
493 if (clos_flag)
494 (*output_func)("--", 2, output_func_arg);
495 (*output_func)("\n", 1, output_func_arg);
496
497 if (clos_flag)
498 {
499 libmail_mimestack_pop_to(stack, b);
500 find_boundary(stack, iseof, input_func,
501 input_func_arg, output_func,
502 output_func_arg, 1);
503 }
504
505 return 0;
506 }
507
dogpgsign(const char * gpghome,const char * passphrase_fd,struct mimestack ** stack,struct header * h,int * iseof,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int argc,char ** argv,void (* errhandler)(const char *,void *),void * errhandler_arg)508 static int dogpgsign(const char *gpghome, const char *passphrase_fd,
509 struct mimestack **stack, struct header *h, int *iseof,
510 int (*input_func)(char *, size_t, void *vp),
511 void *input_func_arg,
512 void (*output_func)(const char *,
513 size_t,
514 void *),
515 void *output_func_arg,
516 int argc,
517 char **argv,
518 void (*errhandler)(const char *, void *),
519 void *errhandler_arg)
520 {
521 struct header *hp;
522 char buf[8192];
523 struct gpgmime_forkinfo gpg;
524 int clos_flag=0;
525 struct mimestack *b=0;
526 int rc=0;
527 char signed_content_name[TEMPNAMEBUFSIZE];
528 int signed_content;
529 FILE *signed_content_fp;
530 const char *boundary;
531 int need_crlf;
532 struct gpg_fork_output_info gfoi;
533
534 for (hp=h; hp; hp=hp->next)
535 {
536 if (encode_header(hp->header))
537 continue;
538 (*output_func)(hp->header, strlen(hp->header),
539 output_func_arg);
540 }
541
542 signed_content=libmail_tempfile(signed_content_name);
543 if (signed_content < 0 ||
544 (signed_content_fp=fdopen(signed_content, "w+")) == NULL)
545 {
546 if (signed_content >= 0)
547 {
548 close(signed_content);
549 unlink(signed_content_name);
550 }
551 return -1;
552
553 }
554 libmail_gpg_noexec(fileno(signed_content_fp));
555 unlink(signed_content_name); /* UNIX semantics */
556
557 for (hp=h; hp; hp=hp->next)
558 {
559 const char *p;
560
561 if (!encode_header(hp->header))
562 continue;
563
564 for (p=hp->header; *p; p++)
565 {
566 if (*p == '\r')
567 continue;
568
569 if (*p == '\n')
570 putc('\r', signed_content_fp);
571 putc(*p, signed_content_fp);
572 }
573 }
574
575 /*
576 ** Chew the content until the next MIME boundary.
577 */
578 need_crlf=1;
579 while (!*iseof)
580 {
581 const char *p;
582
583 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
584 {
585 *iseof=1;
586 break;
587 }
588
589 if (need_crlf)
590 {
591 if ((b=is_boundary(*stack, buf, &clos_flag)) != NULL)
592 break;
593
594 fprintf(signed_content_fp, "\r\n");
595 }
596
597 need_crlf=0;
598 for (;;)
599 {
600 for (p=buf; *p; p++)
601 {
602 if (*p == '\r')
603 continue;
604 if (*p == '\n')
605 {
606 need_crlf=1;
607 break;
608 }
609
610 putc(*p, signed_content_fp);
611 }
612 if (*p == '\n')
613 break;
614
615 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
616 {
617 *iseof=1;
618 break;
619 }
620 }
621 }
622
623 /*
624 ** This needs some 'splainin. Note that we spit out a newline at
625 ** the BEGINNING of each line, above. This generates the blank
626 ** header->body separator line. Now, if we're NOT doing multiline
627 ** content, we need to follow the last line of the content with a
628 ** newline. If we're already doing multiline content, that extra
629 ** newline (if it exists) is already there.
630 */
631
632 if (!*stack)
633 {
634 fprintf(signed_content_fp, "\r\n");
635 }
636
637 if (fflush(signed_content_fp) < 0 || ferror(signed_content_fp))
638 {
639 fclose(signed_content_fp);
640 return (-1);
641 }
642
643 boundary=get_boundary(*stack, "", signed_content_fp);
644
645 if (my_rewind(signed_content_fp) < 0)
646 {
647 fclose(signed_content_fp);
648 return (-1);
649 }
650
651 #define C(s) (*output_func)( s, sizeof(s)-1, output_func_arg)
652 #define S(s) (*output_func)( s, strlen(s), output_func_arg)
653
654 C("Content-Type: multipart/signed;\n"
655 " boundary=\"");
656 S(boundary);
657 C("\";\n"
658 " micalg=pgp-sha1;"
659 " protocol=\"application/pgp-signature\"\n"
660 "\n"
661 "This is a MIME GnuPG-signed message. If you see this text, it means that\n"
662 "your E-mail or Usenet software does not support MIME signed messages.\n"
663 "The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.\n"
664 "To open this message correctly you will need to install E-mail or Usenet\n"
665 "software that supports modern Internet standards.\n"
666 "\n--");
667 S(boundary);
668 C("\n");
669
670
671 gfoi.output_func=output_func;
672 gfoi.output_func_arg=output_func_arg;
673 gfoi.gpgptr= &gpg;
674
675 if (libmail_gpgmime_forksignencrypt(gpghome, passphrase_fd,
676 GPG_SE_SIGN,
677 argc, argv,
678 &gpg_fork_output, &gfoi,
679 &gpg))
680 {
681 fclose(signed_content_fp);
682 return (-1);
683 }
684
685 while (fgets(buf, sizeof(buf), signed_content_fp) != NULL)
686 {
687 char *p;
688 size_t j, k;
689
690 libmail_gpgmime_write(&gpg, buf, strlen(buf));
691
692 p=buf;
693 for (j=k=0; p[j]; j++)
694 if (p[j] != '\r')
695 p[k++]=p[j];
696
697 if (k)
698 (*output_func)(p, k, output_func_arg);
699 }
700
701 C("\n--");
702 S(boundary);
703
704 C("\n"
705 "Content-Type: application/pgp-signature\n"
706 "Content-Transfer-Encoding: 7bit\n\n");
707
708 #undef C
709 #undef S
710
711 if (libmail_gpgmime_finish(&gpg))
712 rc= -1; /* TODO */
713
714 if (rc)
715 {
716 (*errhandler)(libmail_gpgmime_getoutput(&gpg),
717 errhandler_arg);
718 fclose(signed_content_fp);
719 return -1;
720 }
721
722 (*output_func)("\n--", 3, output_func_arg);
723 (*output_func)(boundary, strlen(boundary), output_func_arg);
724 (*output_func)("--\n", 3, output_func_arg);
725
726 fclose(signed_content_fp);
727 if (*iseof)
728 return 0;
729
730 (*output_func)("\n--", 3, output_func_arg);
731 (*output_func)(b->boundary, strlen(b->boundary), output_func_arg);
732 if (clos_flag)
733 (*output_func)("--", 2, output_func_arg);
734 (*output_func)("\n", 1, output_func_arg);
735
736 if (clos_flag)
737 {
738 libmail_mimestack_pop_to(stack, b);
739 find_boundary(stack, iseof, input_func, input_func_arg,
740 output_func, output_func_arg, 1);
741 }
742 return 0;
743 }
744
745 static int isgpg(struct mime_header *);
746 static int checksign(const char *gpghome,
747 const char *passphrase_fd,
748 struct mimestack **, int *, struct header *,
749 int (*input_func)(char *, size_t, void *vp),
750 void *input_func_arg,
751 void (*)(const char *, size_t, void *),
752 void *,
753 int, char **,
754 int *);
755 static int decrypt(const char *gpghome,
756 const char *passphrase_fd,
757 struct mimestack **, int *, struct header *,
758 int (*input_func)(char *, size_t, void *vp),
759 void *input_func_arg,
760 void (*)(const char *, size_t, void *),
761 void *,
762 int, char **,
763 int *);
764
print_noncontent_headers(struct header * h,void (* output_func)(const char *,size_t,void *),void * output_func_arg)765 static void print_noncontent_headers(struct header *h,
766 void (*output_func)(const char *,
767 size_t,
768 void *),
769 void *output_func_arg)
770 {
771 struct header *p;
772
773 for (p=h; p; p=p->next)
774 {
775 if (strncasecmp(p->header, "content-", 8) == 0)
776 continue;
777 (*output_func)(p->header, strlen(p->header), output_func_arg);
778 }
779 }
780
dosignencode2(int dosign,int doencode,int dodecode,const char * gpghome,const char * passphrase_fd,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,void (* errhandler_func)(const char *,void *),void * errhandler_arg,int argc,char ** argv,int * status)781 static int dosignencode2(int dosign, int doencode, int dodecode,
782 const char *gpghome,
783 const char *passphrase_fd,
784 int (*input_func)(char *, size_t, void *vp),
785 void *input_func_arg,
786 void (*output_func)(const char *,
787 size_t,
788 void *),
789 void *output_func_arg,
790 void (*errhandler_func)(const char *, void *),
791 void *errhandler_arg,
792 int argc, char **argv,
793 int *status)
794 {
795 struct mimestack *boundary_stack=0;
796 int iseof=0;
797
798 *status=0;
799
800 while (!iseof)
801 {
802 int errflag;
803
804 static const char ct_s[]="content-type:";
805 struct header *h=read_headers(&boundary_stack, &iseof,
806 input_func, input_func_arg,
807 output_func,
808 output_func_arg,
809 dodecode ? 0:1,
810 &errflag),
811 *hct;
812
813 if (errflag)
814 return 1;
815
816 if (iseof && !h)
817 continue; /* Artifact */
818
819 hct=libmail_header_find(h, ct_s);
820
821 /*
822 ** If this is a multipart MIME section, we can keep on
823 ** truckin'.
824 **
825 */
826
827 if (hct)
828 {
829 struct mime_header *mh=
830 libmail_mimeheader_parse(hct->header+
831 (sizeof(ct_s)-1));
832 const char *bv;
833
834 if (!mh)
835 {
836 libmail_header_free(h);
837 return (-1);
838 }
839
840 if (strcasecmp(mh->header_name, "multipart/x-mimegpg")
841 == 0)
842 {
843 /* Punt */
844
845 char *buf=malloc(strlen(hct->header)+100);
846 const char *p;
847
848 if (!buf)
849 {
850 libmail_mimeheader_free(mh);
851 libmail_header_free(h);
852 return (-1);
853 }
854 strcpy(buf, "Content-Type: multipart/mixed");
855 p=strchr(hct->header, ';');
856 strcat(buf, p ? p:"");
857 free(hct->header);
858 hct->header=buf;
859
860 libmail_mimeheader_free(mh);
861 mh=libmail_mimeheader_parse(hct->header+
862 sizeof(ct_s)-1);
863 if (!mh)
864 {
865 libmail_header_free(h);
866 return (-1);
867 }
868 }
869
870 if (strncasecmp(mh->header_name, "multipart/", 10)==0
871 && (bv=libmail_mimeheader_getattr(mh, "boundary")) != 0
872
873 && (doencode & LIBMAIL_GPG_ENCAPSULATE) == 0
874
875 && !dosign
876 )
877 {
878 struct header *p;
879
880 if (libmail_mimestack_push(&boundary_stack,
881 bv) < 0)
882 {
883 libmail_header_free(h);
884 return (-1);
885 }
886
887 if (dodecode)
888 {
889 int rc;
890
891 if (strcasecmp(mh->header_name,
892 "multipart/signed")==0
893 && (dodecode & LIBMAIL_GPG_CHECKSIGN)
894 && isgpg(mh))
895 {
896 int errflag;
897
898 print_noncontent_headers(h,
899 output_func,
900 output_func_arg
901 );
902 libmail_mimeheader_free(mh);
903 rc=checksign(gpghome,
904 passphrase_fd,
905 &boundary_stack,
906 &iseof,
907 h,
908 input_func,
909 input_func_arg,
910 output_func,
911 output_func_arg,
912 argc, argv,
913 &errflag);
914 libmail_header_free(h);
915
916 if (errflag)
917 *status |=
918 LIBMAIL_ERR_VERIFYSIG;
919 if (rc)
920 return -1;
921
922 continue;
923 }
924
925 if (strcasecmp(mh->header_name,
926 "multipart/encrypted")
927 ==0
928 && (dodecode & LIBMAIL_GPG_UNENCRYPT)
929 && isgpg(mh))
930 {
931 int errflag;
932
933 print_noncontent_headers(h,
934 output_func,
935 output_func_arg
936 );
937 libmail_mimeheader_free(mh);
938 rc=decrypt(gpghome,
939 passphrase_fd,
940 &boundary_stack,
941 &iseof,
942 h,
943 input_func,
944 input_func_arg,
945 output_func,
946 output_func_arg,
947 argc, argv,
948 &errflag);
949 libmail_header_free(h);
950
951 if (errflag)
952 *status |=
953 LIBMAIL_ERR_DECRYPT;
954 if (rc)
955 return -1;
956 continue;
957 }
958 }
959
960 for (p=h; p; p=p->next)
961 {
962 (*output_func)(p->header,
963 strlen(p->header),
964 output_func_arg);
965 }
966
967 (*output_func)("\n", 1, output_func_arg);
968 libmail_header_free(h);
969 libmail_mimeheader_free(mh);
970
971 find_boundary(&boundary_stack, &iseof,
972 input_func,
973 input_func_arg,
974 output_func,
975 output_func_arg, dodecode ? 0:1);
976 continue;
977 }
978 libmail_mimeheader_free(mh);
979 }
980
981 if (dodecode)
982 {
983 struct header *p;
984 int is_message_rfc822=0;
985
986 for (p=h; p; p=p->next)
987 {
988 (*output_func)(p->header,
989 strlen(p->header),
990 output_func_arg);
991 }
992 (*output_func)("\n", 1, output_func_arg);
993
994 /*
995 ** If this is a message/rfc822 attachment, we can
996 ** resume reading the next set of headers.
997 */
998
999 hct=libmail_header_find(h, ct_s);
1000 if (hct)
1001 {
1002 struct mime_header *mh=
1003 libmail_mimeheader_parse(hct->header+
1004 (sizeof(ct_s)
1005 -1));
1006 if (!mh)
1007 {
1008 libmail_header_free(h);
1009 return (-1);
1010 }
1011
1012 if (strcasecmp(mh->header_name,
1013 "message/rfc822") == 0)
1014 is_message_rfc822=1;
1015 libmail_mimeheader_free(mh);
1016 }
1017 libmail_header_free(h);
1018
1019 if (!is_message_rfc822)
1020 find_boundary(&boundary_stack, &iseof,
1021 input_func,
1022 input_func_arg,
1023 output_func,
1024 output_func_arg, 0);
1025 continue;
1026 }
1027
1028 if (doencode ?
1029 dogpgencrypt(gpghome,
1030 passphrase_fd,
1031 &boundary_stack, h, &iseof,
1032 input_func,
1033 input_func_arg,
1034 output_func,
1035 output_func_arg,
1036 argc, argv, dosign,
1037 errhandler_func, errhandler_arg)
1038 :
1039 dogpgsign(gpghome,
1040 passphrase_fd,
1041 &boundary_stack, h, &iseof,
1042 input_func,
1043 input_func_arg,
1044 output_func,
1045 output_func_arg,
1046 argc, argv,
1047 errhandler_func, errhandler_arg))
1048 {
1049 libmail_header_free(h);
1050 return 1;
1051 }
1052
1053 libmail_header_free(h);
1054 }
1055
1056 return (0);
1057 }
1058
1059
isgpg(struct mime_header * mh)1060 static int isgpg(struct mime_header *mh)
1061 {
1062 const char *attr;
1063
1064 attr=libmail_mimeheader_getattr(mh, "protocol");
1065
1066 if (!attr)
1067 return (0);
1068
1069 if (strcasecmp(attr, "application/pgp-encrypted") == 0)
1070 return (1);
1071
1072 if (strcasecmp(attr, "application/pgp-signature") == 0)
1073 {
1074 return (1);
1075 }
1076 return (0);
1077 }
1078
nybble(char c)1079 static int nybble(char c)
1080 {
1081 static const char x[]="0123456789ABCDEFabcdef";
1082
1083 const char *p=strchr(x, c);
1084 int n;
1085
1086 if (!p) p=x;
1087
1088 n= p-x;
1089 if (n >= 16)
1090 n -= 6;
1091 return (n);
1092 }
1093
1094 /*
1095 ** Check signature
1096 */
1097
1098 static int dochecksign(const char *, const char *,
1099 struct mimestack *,
1100 FILE *,
1101 void (*output_func)(const char *,
1102 size_t,
1103 void *),
1104 void *output_func_arg,
1105 const char *,
1106 const char *,
1107 int, char **, int *);
1108
checksign(const char * gpghome,const char * passphrase_fd,struct mimestack ** stack,int * iseof,struct header * h,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int argc,char ** argv,int * errptr)1109 static int checksign(const char *gpghome,
1110 const char *passphrase_fd,
1111 struct mimestack **stack, int *iseof,
1112 struct header *h,
1113 int (*input_func)(char *, size_t, void *vp),
1114 void *input_func_arg,
1115 void (*output_func)(const char *,
1116 size_t,
1117 void *),
1118 void *output_func_arg,
1119 int argc, char **argv, int *errptr)
1120 {
1121 char buf[BUFSIZ];
1122 struct header *h2;
1123
1124 char signed_content[TEMPNAMEBUFSIZE];
1125 char signature[TEMPNAMEBUFSIZE];
1126 int signed_file, signature_file;
1127 FILE *signed_file_fp, *signature_file_fp;
1128 int clos_flag;
1129 int need_nl, check_boundary;
1130 struct mimestack *b=0;
1131 struct mime_header *mh;
1132 int qpdecode=0;
1133 int errflag;
1134
1135 *errptr=0;
1136
1137 signed_file=libmail_tempfile(signed_content);
1138
1139 if (signed_file < 0 || (signed_file_fp=fdopen(signed_file, "w+")) == 0)
1140 {
1141 if (signed_file > 0)
1142 {
1143 close(signed_file);
1144 unlink(signed_content);
1145 }
1146 return -1;
1147 }
1148 libmail_gpg_noexec(fileno(signed_file_fp));
1149
1150 find_boundary(stack, iseof, input_func,
1151 input_func_arg, NULL, NULL, 0);
1152 if (*iseof)
1153 return 0;
1154
1155 need_nl=0;
1156 check_boundary=1;
1157
1158 while (!*iseof)
1159 {
1160 const char *p;
1161
1162 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
1163 {
1164 *iseof=1;
1165 continue;
1166 }
1167
1168 if (check_boundary
1169 && (b=is_boundary(*stack, buf, &clos_flag)) != 0)
1170 break;
1171 if (need_nl)
1172 fprintf(signed_file_fp, "\r\n");
1173
1174 for (p=buf; *p && *p != '\n'; p++)
1175 putc(*p, signed_file_fp);
1176 need_nl=check_boundary= *p != 0;
1177 }
1178
1179 if (my_rewind(signed_file_fp) < 0)
1180 {
1181 fclose(signed_file_fp);
1182 unlink(signed_content);
1183 return -1;
1184 }
1185
1186 if (clos_flag)
1187 {
1188 fclose(signed_file_fp);
1189 unlink(signed_content);
1190 if (b)
1191 libmail_mimestack_pop_to(stack, b);
1192 find_boundary(stack, iseof, input_func, input_func_arg,
1193 output_func, output_func_arg, 1);
1194 return 0;
1195 }
1196
1197 h=read_headers(stack, iseof, input_func, input_func_arg,
1198 output_func, output_func_arg, 0, &errflag);
1199
1200 if (errflag)
1201 {
1202 fclose(signed_file_fp);
1203 unlink(signed_content);
1204
1205 return (-1);
1206 }
1207
1208 if (!h || !(h2=libmail_header_find(h, "content-type:")))
1209 {
1210 if (h)
1211 libmail_header_free(h);
1212 fclose(signed_file_fp);
1213 unlink(signed_content);
1214 if (!*iseof)
1215 find_boundary(stack, iseof, input_func, input_func_arg,
1216 output_func, output_func_arg, 1);
1217 return 0;
1218 }
1219
1220 mh=libmail_mimeheader_parse(h2->header+sizeof("content-type:")-1);
1221
1222 if (!mh)
1223 {
1224 libmail_header_free(h);
1225 fclose(signed_file_fp);
1226 unlink(signed_content);
1227 return (-1);
1228 }
1229
1230 if (strcasecmp(mh->header_name, "application/pgp-signature"))
1231 {
1232 libmail_mimeheader_free(mh);
1233 libmail_header_free(h);
1234 fclose(signed_file_fp);
1235 unlink(signed_content);
1236 if (!*iseof)
1237 find_boundary(stack, iseof, input_func, input_func_arg,
1238 output_func, output_func_arg, 1);
1239 return (0);
1240 }
1241 libmail_mimeheader_free(mh);
1242
1243 /*
1244 ** In rare instances, the signature is qp-encoded.
1245 */
1246
1247 if ((h2=libmail_header_find(h, "content-transfer-encoding:")) != NULL)
1248 {
1249 mh=libmail_mimeheader_parse
1250 (h2->header+sizeof("content-transfer-encoding:")-1);
1251
1252 if (!mh)
1253 {
1254 libmail_header_free(h);
1255 fclose(signed_file_fp);
1256 unlink(signed_content);
1257 return -1;
1258 }
1259
1260 if (strcasecmp(mh->header_name,
1261 "quoted-printable") == 0)
1262 qpdecode=1;
1263 libmail_mimeheader_free(mh);
1264 }
1265 libmail_header_free(h);
1266
1267 signature_file=libmail_tempfile(signature);
1268
1269 if (signature_file < 0
1270 || (signature_file_fp=fdopen(signature_file, "w+")) == 0)
1271 {
1272 if (signature_file > 0)
1273 {
1274 close(signature_file);
1275 unlink(signature);
1276 }
1277 unlink(signed_content);
1278 return (-1);
1279 }
1280
1281 while (!*iseof)
1282 {
1283 const char *p;
1284
1285 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
1286 {
1287 *iseof=1;
1288 continue;
1289 }
1290
1291 if ((b=is_boundary(*stack, buf, &clos_flag)) != 0)
1292 break;
1293
1294 for (p=buf; *p; p++)
1295 {
1296 int n;
1297
1298 if (!qpdecode)
1299 {
1300 putc(*p, signature_file_fp);
1301 continue;
1302 }
1303
1304 if (*p == '=' && p[1] == '\n')
1305 break;
1306
1307 if (*p == '=' && p[1] && p[2])
1308 {
1309 n=nybble(p[1]) * 16 + nybble(p[2]);
1310 if ( (char)n )
1311 {
1312 putc((char)n, signature_file_fp);
1313 p += 2;
1314 }
1315 p += 2;
1316 continue;
1317 }
1318 putc(*p, signature_file_fp);
1319
1320 /* If some spits out qp-lines > BUFSIZ, they deserve
1321 ** this crap.
1322 */
1323 }
1324 }
1325
1326 fflush(signature_file_fp);
1327 if (ferror(signature_file_fp))
1328 {
1329 unlink(signature);
1330 fclose(signed_file_fp);
1331 unlink(signed_content);
1332 return -1;
1333 }
1334 if (fclose(signature_file_fp))
1335 {
1336 unlink(signature);
1337 unlink(signed_content);
1338 return -1;
1339 }
1340
1341 errflag=dochecksign(gpghome,
1342 passphrase_fd,
1343 *stack, signed_file_fp,
1344 output_func, output_func_arg, signed_content,
1345 signature,
1346 argc, argv, errptr);
1347
1348 fclose(signed_file_fp);
1349 unlink(signature);
1350 unlink(signed_content);
1351
1352 if (errflag)
1353 return -1;
1354
1355 while (!clos_flag)
1356 {
1357 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
1358 {
1359 *iseof=1;
1360 break;
1361 }
1362 if (!(b=is_boundary(*stack, buf, &clos_flag)))
1363 clos_flag=0;
1364 }
1365 if (b)
1366 libmail_mimestack_pop_to(stack, b);
1367
1368 return 0;
1369 }
1370
newboundary()1371 static const char *newboundary()
1372 {
1373 static char buffer[256];
1374 static unsigned counter=0;
1375 time_t t;
1376 char hostnamebuf[256];
1377
1378 time(&t);
1379 hostnamebuf[sizeof(hostnamebuf)-1]=0;
1380 if (gethostname(hostnamebuf, sizeof(hostnamebuf)-1) < 0)
1381 hostnamebuf[0]=0;
1382
1383 sprintf(buffer, "=_mimegpg-%1.128s-%u-%u-%04u",
1384 hostnamebuf, (unsigned)getpid(),
1385 (unsigned)t, ++counter);
1386 return (buffer);
1387 }
1388
good_boundary(const char * boundary,struct mimestack * m,const char * errmsg,FILE * fp)1389 static int good_boundary(const char *boundary,
1390 struct mimestack *m, const char *errmsg, FILE *fp)
1391 {
1392 int dummy;
1393 int l=strlen(boundary);
1394 const char *p;
1395 char buf[BUFSIZ];
1396
1397 if (is_boundary(m, boundary, &dummy))
1398 return (0);
1399
1400 for (p=errmsg; *p; )
1401 {
1402 if (*p == '-' && p[1] == '-' && strncasecmp(p+2, boundary, l)
1403 == 0)
1404 return (0);
1405
1406 while (*p)
1407 if (*p++ == '\n')
1408 break;
1409 }
1410
1411 if (fp)
1412 {
1413 if (my_rewind(fp) < 0)
1414 return 0;
1415
1416 while (fgets(buf, sizeof(buf), fp))
1417 {
1418 if (buf[0] == '-' && buf[1] == '-' &&
1419 strncasecmp(buf+2, boundary, l) == 0)
1420 return (0);
1421 }
1422 }
1423 return (1);
1424 }
1425
get_boundary(struct mimestack * m,const char * errmsg,FILE * fp)1426 static const char *get_boundary(struct mimestack *m,
1427 const char *errmsg,
1428 FILE *fp)
1429 {
1430 const char *p;
1431
1432 do
1433 {
1434 p=newboundary();
1435 } while (!good_boundary(p, m, errmsg, fp));
1436 return (p);
1437 }
1438
encoding_str(const char * p)1439 static const char *encoding_str(const char *p)
1440 {
1441 while (*p)
1442 {
1443 if (*p <= 0 || *p >= 0x7F)
1444 return ("8bit");
1445 ++p;
1446 }
1447 return ("7bit");
1448 }
1449
1450
copyfp(FILE * t,void (* output_func)(const char *,size_t,void *),void * output_func_arg)1451 static int copyfp(FILE *t,
1452 void (*output_func)(const char *,
1453 size_t,
1454 void *),
1455 void *output_func_arg)
1456 {
1457 char buf[BUFSIZ];
1458 int rc=0;
1459
1460 while ((rc=fread(buf, 1, sizeof(buf), t)) > 0)
1461 (*output_func)(buf, rc, output_func_arg);
1462
1463 return rc;
1464 }
1465
1466 static void open_result_multipart(void (*)(const char *, size_t, void *),
1467 void *,
1468 int, const char *, const char *,
1469 const char *);
1470
dochecksign(const char * gpghome,const char * passphrase_fd,struct mimestack * stack,FILE * content_fp,void (* output_func)(const char *,size_t,void *),void * output_func_arg,const char * content_filename,const char * signature_filename,int argc,char ** argv,int * errptr)1471 static int dochecksign(const char *gpghome,
1472 const char *passphrase_fd,
1473 struct mimestack *stack,
1474 FILE *content_fp,
1475 void (*output_func)(const char *,
1476 size_t,
1477 void *),
1478 void *output_func_arg,
1479 const char *content_filename,
1480 const char *signature_filename,
1481 int argc,
1482 char **argv, int *errptr)
1483 {
1484 struct gpgmime_forkinfo gpg;
1485 int i;
1486 const char *new_boundary;
1487 const char *output;
1488
1489 if (libmail_gpgmime_forkchecksign(gpghome, passphrase_fd,
1490 content_filename,
1491 signature_filename,
1492 argc, argv,
1493 &gpg))
1494 {
1495 return -1;
1496 }
1497
1498 *errptr=i=libmail_gpgmime_finish(&gpg);
1499
1500 output=libmail_gpgmime_getoutput(&gpg);
1501
1502 new_boundary=get_boundary(stack, output, content_fp);
1503
1504 open_result_multipart(output_func, output_func_arg,
1505 i, new_boundary, output,
1506 libmail_gpgmime_getcharset(&gpg));
1507
1508 (*output_func)("\n--", 3, output_func_arg);
1509 (*output_func)(new_boundary, strlen(new_boundary), output_func_arg);
1510 (*output_func)("\n", 1, output_func_arg);
1511
1512 if (my_rewind(content_fp) < 0)
1513 {
1514 return -1;
1515 }
1516
1517 if (copyfp(content_fp, output_func, output_func_arg))
1518 return -1;
1519
1520 (*output_func)("\n--", 3, output_func_arg);
1521 (*output_func)(new_boundary, strlen(new_boundary), output_func_arg);
1522 (*output_func)("--\n", 3, output_func_arg);
1523 return 0;
1524 }
1525
open_result_multipart(void (* output_func)(const char *,size_t,void *),void * output_func_arg,int rc,const char * new_boundary,const char * err_str,const char * err_charset)1526 static void open_result_multipart(void (*output_func)(const char *,
1527 size_t,
1528 void *),
1529 void *output_func_arg,
1530 int rc,
1531 const char *new_boundary,
1532 const char *err_str,
1533 const char *err_charset)
1534 {
1535 #define C(s) (*output_func)( s, sizeof(s)-1, output_func_arg)
1536 #define S(s) (*output_func)( s, strlen(s), output_func_arg)
1537
1538 char n[10];
1539 const char *p;
1540
1541 sprintf(n, "%d", rc);
1542
1543 C("Content-Type: multipart/x-mimegpg; xpgpstatus=");
1544
1545 S(n);
1546
1547 C("; boundary=\"");
1548
1549 S(new_boundary);
1550
1551 C("\"\n"
1552 "\nThis is a MIME GnuPG-processed message. If you see this text, it means\n"
1553 "that your E-mail or Usenetsoftware does not support MIME-formatted messages.\n\n"
1554 "--");
1555
1556 S(new_boundary);
1557 C("\nContent-Type: text/x-gpg-output; charset=");
1558 S(err_charset);
1559 C("\nContent-Transfer-Encoding: ");
1560
1561 p=encoding_str(err_str);
1562 S(p);
1563 C("\n\n");
1564 S(err_str);
1565 #undef C
1566 #undef S
1567 }
1568
close_mime(struct mimestack ** stack,int * iseof,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg)1569 static void close_mime(struct mimestack **stack, int *iseof,
1570 int (*input_func)(char *, size_t, void *vp),
1571 void *input_func_arg,
1572 void (*output_func)(const char *,
1573 size_t,
1574 void *),
1575 void *output_func_arg)
1576 {
1577 char buf[BUFSIZ];
1578 int is_closing;
1579 struct mimestack *b;
1580
1581 for (;;)
1582 {
1583 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
1584 {
1585 *iseof=1;
1586 break;
1587 }
1588
1589 (*output_func)(buf, strlen(buf), output_func_arg);
1590 if (!(b=is_boundary(*stack, buf, &is_closing)))
1591 continue;
1592 if (!is_closing)
1593 continue;
1594
1595 libmail_mimestack_pop_to(stack, b);
1596 break;
1597 }
1598 }
1599
1600 static int dodecrypt(const char *, const char *,
1601 struct mimestack **, int *,
1602 int (*input_func)(char *, size_t, void *vp),
1603 void *input_func_arg,
1604 FILE *, int, char **, const char *,
1605 void (*)(const char *,
1606 size_t,
1607 void *),
1608 void *,
1609 int *);
1610
write_temp_fp(const char * p,size_t n,void * vp)1611 static void write_temp_fp(const char *p, size_t n, void *vp)
1612 {
1613 if (fwrite(p, n, 1, (FILE *)vp) != 1)
1614 ; /* ignored */
1615 }
1616
decrypt(const char * gpghome,const char * passphrase_fd,struct mimestack ** stack,int * iseof,struct header * h,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int argc,char ** argv,int * errptr)1617 static int decrypt(const char *gpghome,
1618 const char *passphrase_fd,
1619 struct mimestack **stack, int *iseof,
1620 struct header *h,
1621 int (*input_func)(char *, size_t, void *vp),
1622 void *input_func_arg,
1623 void (*output_func)(const char *,
1624 size_t,
1625 void *),
1626 void *output_func_arg,
1627 int argc, char **argv,
1628 int *errptr)
1629 {
1630 struct header *p, *q;
1631 char temp_file[TEMPNAMEBUFSIZE];
1632 int temp_fd;
1633 FILE *temp_fp;
1634 struct mime_header *mh;
1635 int flag;
1636 int errflag;
1637
1638 *errptr=0;
1639 temp_fd=libmail_tempfile(temp_file);
1640 if (temp_fd < 0 || (temp_fp=fdopen(temp_fd, "w+")) == 0)
1641 {
1642 if (temp_fd >= 0)
1643 close(temp_fd);
1644 return -1;
1645 }
1646
1647 for (p=h; p; p=p->next)
1648 {
1649 fprintf(temp_fp, "%s", p->header);
1650 }
1651 putc('\n', temp_fp);
1652
1653 find_boundary(stack, iseof, input_func, input_func_arg,
1654 write_temp_fp, temp_fp, 0);
1655 if (*iseof)
1656 {
1657 fclose(temp_fp);
1658 unlink(temp_file);
1659 return (0);
1660 }
1661
1662 p=read_headers(stack, iseof, input_func, input_func_arg, write_temp_fp,
1663 temp_fp, 0, &errflag);
1664
1665 if (*iseof || errflag)
1666 {
1667 libmail_header_free(p);
1668 fclose(temp_fp);
1669 unlink(temp_file);
1670
1671 if (errflag)
1672 return -1;
1673 return 0;
1674 }
1675
1676 q=libmail_header_find(p, "content-type:");
1677
1678 flag=0;
1679
1680 if (q)
1681 {
1682 mh=libmail_mimeheader_parse(q->header+13);
1683 if (!mh)
1684 {
1685 libmail_header_free(p);
1686 fclose(temp_fp);
1687 unlink(temp_file);
1688 return -1;
1689 }
1690
1691 if (strcasecmp(mh->header_name, "application/pgp-encrypted")
1692 == 0)
1693 flag=1;
1694 libmail_mimeheader_free(mh);
1695 }
1696
1697 for (q=p; q; q=q->next)
1698 {
1699 fprintf(temp_fp, "%s", q->header);
1700 }
1701 libmail_header_free(p);
1702 putc('\n', temp_fp);
1703
1704 p=read_headers(stack, iseof, input_func, input_func_arg,
1705 write_temp_fp, temp_fp, 0,
1706 &errflag);
1707
1708 if (*iseof || errflag)
1709 {
1710 libmail_header_free(p);
1711 fclose(temp_fp);
1712 unlink(temp_file);
1713
1714 if (errflag)
1715 return -1;
1716
1717 return 0;
1718 }
1719
1720 q=libmail_header_find(p, "version:");
1721
1722 if (flag)
1723 {
1724 if (!q || atoi(p->header + 8) != 1)
1725 flag=0;
1726 }
1727 for (q=p; q; q=q->next)
1728 {
1729 fprintf(temp_fp, "%s", q->header);
1730 }
1731 libmail_header_free(p);
1732 putc('\n', temp_fp);
1733
1734 find_boundary(stack, iseof, input_func, input_func_arg,
1735 write_temp_fp, temp_fp, 0);
1736
1737 if (*iseof)
1738 {
1739 fclose(temp_fp);
1740 unlink(temp_file);
1741 return 0;
1742 }
1743
1744 p=read_headers(stack, iseof, input_func, input_func_arg, write_temp_fp,
1745 temp_fp, 0, &errflag);
1746
1747 if (*iseof || errflag)
1748 {
1749 libmail_header_free(p);
1750 fclose(temp_fp);
1751 unlink(temp_file);
1752
1753 if (errflag)
1754 return -1;
1755
1756 return 0;
1757 }
1758
1759 q=libmail_header_find(p, "content-type:");
1760
1761 if (q && flag)
1762 {
1763 flag=0;
1764 mh=libmail_mimeheader_parse(q->header+13);
1765 if (!mh)
1766 {
1767 libmail_header_free(p);
1768 fclose(temp_fp);
1769 unlink(temp_file);
1770 return -1;
1771 }
1772
1773 if (strcasecmp(mh->header_name, "application/octet-stream")
1774 == 0)
1775 flag=1;
1776 libmail_mimeheader_free(mh);
1777
1778 q=libmail_header_find(p, "content-transfer-encoding:");
1779 if (q && flag)
1780 {
1781 flag=0;
1782 mh=libmail_mimeheader_parse(strchr(q->header, ':')+1);
1783 if (!mh)
1784 {
1785 libmail_header_free(p);
1786 fclose(temp_fp);
1787 unlink(temp_file);
1788 return -1;
1789 }
1790
1791 if (strcasecmp(mh->header_name, "7bit") == 0 ||
1792 strcasecmp(mh->header_name, "8bit") == 0)
1793 flag=1;
1794 libmail_mimeheader_free(mh);
1795 }
1796 }
1797
1798 for (q=p; q; q=q->next)
1799 {
1800 fprintf(temp_fp, "%s", q->header);
1801 }
1802 libmail_header_free(p);
1803 putc('\n', temp_fp);
1804
1805 if (fflush(temp_fp) || ferror(temp_fp) || my_rewind(temp_fp) < 0)
1806 {
1807 fclose(temp_fp);
1808 unlink(temp_file);
1809 return -1;
1810 }
1811
1812 if (!flag)
1813 {
1814 int c=copyfp(temp_fp, output_func, output_func_arg);
1815
1816 fclose(temp_fp);
1817 unlink(temp_file);
1818 close_mime(stack, iseof, input_func, input_func_arg,
1819 output_func, output_func_arg);
1820 return (c);
1821 }
1822
1823 fclose(temp_fp);
1824 if ((temp_fp=fopen(temp_file, "w+")) == NULL)
1825 {
1826 unlink(temp_file);
1827 return (-1);
1828 }
1829 libmail_gpg_noexec(fileno(temp_fp));
1830 errflag=dodecrypt(gpghome, passphrase_fd,
1831 stack, iseof, input_func, input_func_arg,
1832 temp_fp, argc, argv, temp_file,
1833 output_func, output_func_arg, errptr);
1834 fclose(temp_fp);
1835 unlink(temp_file);
1836 return errflag;
1837 }
1838
dumpdecrypt(const char * c,size_t n,void * vp)1839 static int dumpdecrypt(const char *c, size_t n, void *vp)
1840 {
1841 FILE *fp=(FILE *)vp;
1842
1843 if (n == 0)
1844 return 0;
1845
1846 if (fwrite(c, n, 1, fp) != 1)
1847 return -1;
1848 return (0);
1849 }
1850
dodecrypt(const char * gpghome,const char * passphrase_fd,struct mimestack ** stack,int * iseof,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,FILE * fpout,int argc,char ** argv,const char * temp_file,void (* output_func)(const char *,size_t,void *),void * output_func_arg,int * errptr)1851 static int dodecrypt(const char *gpghome,
1852 const char *passphrase_fd,
1853 struct mimestack **stack, int *iseof,
1854 int (*input_func)(char *, size_t, void *vp),
1855 void *input_func_arg,
1856 FILE *fpout, int argc, char **argv,
1857 const char *temp_file,
1858 void (*output_func)(const char *,
1859 size_t,
1860 void *),
1861 void *output_func_arg,
1862 int *errptr)
1863 {
1864 struct gpgmime_forkinfo gpg;
1865 char buf[BUFSIZ];
1866 int is_closing;
1867 struct mimestack *b=NULL;
1868 int dowrite=1;
1869 int rc;
1870 const char *new_boundary;
1871 const char *output;
1872
1873 if (libmail_gpgmime_forkdecrypt(gpghome,
1874 passphrase_fd,
1875 argc, argv, &dumpdecrypt, fpout, &gpg))
1876 return -1;
1877
1878 for (;;)
1879 {
1880 if ( (*input_func)(buf, sizeof(buf), input_func_arg))
1881 {
1882 *iseof=1;
1883 break;
1884 }
1885
1886 if (dowrite)
1887 libmail_gpgmime_write(&gpg, buf, strlen(buf));
1888
1889 if (!(b=is_boundary(*stack, buf, &is_closing)))
1890 continue;
1891 dowrite=0;
1892 if (!is_closing)
1893 continue;
1894 break;
1895 }
1896
1897 rc=libmail_gpgmime_finish(&gpg);
1898 if (fflush(fpout) || ferror(fpout) || my_rewind(fpout) < 0)
1899 {
1900 fclose(fpout);
1901 unlink(temp_file);
1902 return -1;
1903 }
1904
1905 if (*iseof)
1906 return 0;
1907
1908 output=libmail_gpgmime_getoutput(&gpg),
1909
1910 new_boundary=get_boundary(*stack, output, rc ? NULL:fpout);
1911
1912 open_result_multipart(output_func,
1913 output_func_arg, rc, new_boundary,
1914 output,
1915 libmail_gpgmime_getcharset(&gpg));
1916
1917 *errptr=rc;
1918
1919 #if 0
1920
1921 /*
1922 ** gnupg returns non-zero exit even if succesfully unencrypted, when
1923 ** just the signature is bad.
1924 */
1925 if (rc == 0)
1926 #endif
1927 {
1928 if (fseek(fpout, 0L, SEEK_SET) < 0)
1929 {
1930 fclose(fpout);
1931 unlink(temp_file);
1932 return -1;
1933 }
1934
1935 (*output_func)("\n--", 3, output_func_arg);
1936 (*output_func)(new_boundary, strlen(new_boundary),
1937 output_func_arg);
1938 (*output_func)("\n", 1, output_func_arg);
1939
1940 if (copyfp(fpout, output_func, output_func_arg))
1941 return -1;
1942 }
1943
1944 (*output_func)("\n--", 3, output_func_arg);
1945 (*output_func)(new_boundary, strlen(new_boundary),
1946 output_func_arg);
1947 (*output_func)("--\n", 3, output_func_arg);
1948
1949 libmail_mimestack_pop_to(stack, b);
1950 return 0;
1951 }
1952
1953 struct libmail_gpg_errhandler {
1954
1955 struct libmail_gpg_info *options;
1956 int err_flag;
1957 };
1958
libmail_gpg_errfunc(const char * errmsg,void * vp)1959 static void libmail_gpg_errfunc(const char *errmsg, void *vp)
1960 {
1961 struct libmail_gpg_errhandler *eh=(struct libmail_gpg_errhandler *)vp;
1962
1963 if (!eh->err_flag)
1964 {
1965 eh->err_flag=1;
1966
1967 (*eh->options->errhandler_func)(errmsg,
1968 eh->options->errhandler_arg);
1969 }
1970 }
1971
input_func_from_fp(char * buf,size_t cnt,void * vp)1972 static int input_func_from_fp(char *buf, size_t cnt, void *vp)
1973 {
1974 if (fgets(buf, cnt, (FILE *)vp) == NULL)
1975 return (-1);
1976 return (0);
1977 }
1978
1979 /*
1980 ** When signing, but not encoding, signed text must be 7bit, as per RFC.
1981 **
1982 ** Use rfc2045's rewriter to do this.
1983 */
1984
dosignencode(int dosign,int doencode,int dodecode,const char * gpghome,const char * passphrase_fd,int (* input_func)(char *,size_t,void * vp),void * input_func_arg,void (* output_func)(const char *,size_t,void *),void * output_func_arg,void (* errhandler_func)(const char *,void *),void * errhandler_arg,int argc,char ** argv,int * status)1985 static int dosignencode(int dosign, int doencode, int dodecode,
1986 const char *gpghome,
1987 const char *passphrase_fd,
1988 int (*input_func)(char *, size_t, void *vp),
1989 void *input_func_arg,
1990 void (*output_func)(const char *,
1991 size_t,
1992 void *),
1993 void *output_func_arg,
1994 void (*errhandler_func)(const char *, void *),
1995 void *errhandler_arg,
1996 int argc, char **argv,
1997 int *status)
1998 {
1999 char temp_decode_name[TEMPNAMEBUFSIZE];
2000 int fdin;
2001 int fdout;
2002 FILE *fdin_fp;
2003 char buffer[8192];
2004 struct rfc2045 *rfcp;
2005 int rc;
2006
2007 if (!dosign || doencode)
2008 return dosignencode2(dosign, doencode, dodecode,
2009 gpghome,
2010 passphrase_fd,
2011 input_func,
2012 input_func_arg,
2013 output_func,
2014 output_func_arg,
2015 errhandler_func,
2016 errhandler_arg,
2017 argc, argv, status);
2018
2019 /* Save the message into a temp file, first */
2020
2021 fdin=libmail_tempfile(temp_decode_name);
2022
2023 if (fdin < 0 ||
2024 (fdin_fp=fdopen(fdin, "w+")) == NULL)
2025 {
2026 if (fdin >= 0)
2027 close(fdin);
2028
2029 (*errhandler_func)("Cannot create temporary file",
2030 errhandler_arg);
2031 return (-1);
2032 }
2033
2034 unlink(temp_decode_name);
2035
2036 if (!(rfcp=rfc2045_alloc_ac()))
2037 {
2038 (*errhandler_func)(strerror(errno), errhandler_arg);
2039 fclose(fdin_fp);
2040 return (-1);
2041 }
2042
2043 while ( (*input_func)(buffer, sizeof(buffer), input_func_arg) == 0)
2044 {
2045 size_t l=strlen(buffer);
2046
2047 if (fwrite(buffer, l, 1, fdin_fp) != 1)
2048 {
2049 (*errhandler_func)(strerror(errno), errhandler_arg);
2050 fclose(fdin_fp);
2051 rfc2045_free(rfcp);
2052 return (-1);
2053 }
2054
2055 /* Parse the message at the same time it's being saved */
2056
2057 rfc2045_parse(rfcp, buffer, l);
2058 }
2059
2060 if (fseek(fdin_fp, 0L, SEEK_SET) < 0)
2061 {
2062 (*errhandler_func)(strerror(errno), errhandler_arg);
2063 fclose(fdin_fp);
2064 rfc2045_free(rfcp);
2065 return (-1);
2066 }
2067
2068 if (!rfc2045_ac_check(rfcp, RFC2045_RW_7BIT))
2069 {
2070 rfc2045_free(rfcp);
2071
2072 /* No need to rewrite, just do this */
2073
2074 rc=dosignencode2(dosign, doencode, dodecode,
2075 gpghome,
2076 passphrase_fd,
2077 input_func_from_fp,
2078 fdin_fp,
2079 output_func,
2080 output_func_arg,
2081 errhandler_func,
2082 errhandler_arg,
2083 argc, argv, status);
2084
2085 fclose(fdin_fp);
2086
2087 return rc;
2088 }
2089
2090 /* Rewrite the message into another temp file */
2091
2092 fdout=libmail_tempfile(temp_decode_name);
2093
2094 if (fdout < 0 ||
2095 rfc2045_rewrite(rfcp, fileno(fdin_fp), fdout, "mimegpg") < 0 ||
2096 lseek(fdout, 0L, SEEK_SET) < 0)
2097 {
2098 if (fdout >= 0)
2099 close(fdout);
2100 (*errhandler_func)(strerror(errno), errhandler_arg);
2101 rfc2045_free(rfcp);
2102 fclose(fdin_fp);
2103 return (-1);
2104 }
2105 fclose(fdin_fp);
2106 rfc2045_free(rfcp);
2107
2108 /* Now, read the converted message, from the temp file */
2109
2110 if ((fdin_fp=fdopen(fdout, "w+")) == NULL)
2111 {
2112 close(fdout);
2113
2114 (*errhandler_func)("Cannot create temporary file",
2115 errhandler_arg);
2116 return (-1);
2117 }
2118
2119 rc=dosignencode2(dosign, doencode, dodecode,
2120 gpghome,
2121 passphrase_fd,
2122 input_func_from_fp,
2123 fdin_fp,
2124 output_func,
2125 output_func_arg,
2126 errhandler_func,
2127 errhandler_arg,
2128 argc, argv, status);
2129 fclose(fdin_fp);
2130 return rc;
2131 }
2132
libmail_gpg_signencode(int dosign,int doencode,struct libmail_gpg_info * options)2133 int libmail_gpg_signencode(int dosign,
2134 int doencode,
2135 /*
2136 ** One of LIBMAIL_GPG_INDIVIDUAL or
2137 ** LIBMAIL_GPG_ENCAPSULATE
2138 */
2139 struct libmail_gpg_info *options)
2140 {
2141 int rc;
2142 struct libmail_gpg_errhandler eh;
2143
2144 eh.options=options;
2145 eh.err_flag=0;
2146
2147 if (doencode != LIBMAIL_GPG_INDIVIDUAL &&
2148 doencode != LIBMAIL_GPG_ENCAPSULATE)
2149 doencode=0;
2150
2151 if (!dosign && !doencode)
2152 {
2153 (*options->errhandler_func)("Invalid arguments to"
2154 " libmail_gpg_signencode",
2155 options->errhandler_arg);
2156 return -1;
2157 }
2158
2159 rc=dosignencode(dosign, doencode, 0,
2160 options->gnupghome,
2161 options->passphrase_fd,
2162 options->input_func,
2163 options->input_func_arg,
2164 options->output_func,
2165 options->output_func_arg,
2166 &libmail_gpg_errfunc,
2167 &eh,
2168 options->argc,
2169 options->argv,
2170 &options->errstatus);
2171
2172 if (rc && !eh.err_flag)
2173 (*options->errhandler_func)(strerror(errno),
2174 options->errhandler_arg);
2175 return rc;
2176 }
2177
libmail_gpg_decode(int mode,struct libmail_gpg_info * options)2178 int libmail_gpg_decode(int mode,
2179 /*
2180 ** LIBMAIL_GPG_UNENCRYPT OR LIBMAIL_GPG_CHECKSIGN
2181 */
2182 struct libmail_gpg_info *options)
2183 {
2184 int rc;
2185 struct libmail_gpg_errhandler eh;
2186
2187 eh.options=options;
2188 eh.err_flag=0;
2189
2190 if ((mode & (LIBMAIL_GPG_UNENCRYPT|LIBMAIL_GPG_CHECKSIGN)) == 0)
2191 {
2192 (*options->errhandler_func)("Invalid arguments to"
2193 " libmail_gpg_decode",
2194 options->errhandler_arg);
2195 return -1;
2196 }
2197
2198 rc=dosignencode(0, 0, mode,
2199 options->gnupghome,
2200 options->passphrase_fd,
2201 options->input_func,
2202 options->input_func_arg,
2203 options->output_func,
2204 options->output_func_arg,
2205 &libmail_gpg_errfunc,
2206 &eh,
2207 options->argc,
2208 options->argv,
2209 &options->errstatus);
2210
2211 if (rc && !eh.err_flag)
2212 (*options->errhandler_func)(strerror(errno),
2213 options->errhandler_arg);
2214 return rc;
2215 }
2216