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