chiark / gitweb /
gnupg2 (2.1.17-3) unstable; urgency=medium
[gnupg2.git] / tools / mime-maker.c
1 /* mime-maker.c - Create MIME structures
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "util.h"
26 #include "zb32.h"
27 #include "mime-maker.h"
28
29
30 /* All valid characters in a header name.  */
31 #define HEADER_NAME_CHARS  ("abcdefghijklmnopqrstuvwxyz" \
32                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
33                             "-01234567890")
34
35 /* An object to store an header.  Also used for a list of headers.  */
36 struct header_s
37 {
38   struct header_s *next;
39   char *value;   /* Malloced value.  */
40   char name[1]; /* Name.  */
41 };
42 typedef struct header_s *header_t;
43
44
45 /* An object to store a MIME part.  A part is the header plus the
46  * content (body). */
47 struct part_s
48 {
49   struct part_s *next;  /* Next part in the current container.  */
50   struct part_s *child; /* Child container.  */
51   char *boundary;       /* Malloced boundary string.  */
52   header_t headers;     /* List of headers.  */
53   header_t *headers_tail;/* Address of last header in chain.  */
54   size_t bodylen;       /* Length of BODY.   */
55   char *body;           /* Malloced buffer with the body.  This is the
56                          * non-encoded value.  */
57   unsigned int partid;   /* The part ID.  */
58 };
59 typedef struct part_s *part_t;
60
61
62
63 /* Definition of the mime parser object.  */
64 struct mime_maker_context_s
65 {
66   void *cookie;                /* Cookie passed to all callbacks.  */
67
68   unsigned int verbose:1;      /* Enable verbose mode.  */
69   unsigned int debug:1;        /* Enable debug mode.  */
70
71   part_t mail;                 /* The MIME tree.  */
72   part_t current_part;
73
74   unsigned int partid_counter; /* Counter assign part ids.  */
75
76   int boundary_counter;  /* Used to create easy to read boundaries.  */
77   char *boundary_suffix; /* Random string used in the boundaries.  */
78
79   struct b64state *b64state;     /* NULL or malloced Base64 decoder state.  */
80
81   /* Helper to convey the output stream to recursive functions. */
82   estream_t outfp;
83 };
84
85
86 /* Create a new mime make object.  COOKIE is a values woich will be
87  * used as first argument for all callbacks registered with this
88  * object.  */
89 gpg_error_t
90 mime_maker_new (mime_maker_t *r_maker, void *cookie)
91 {
92   mime_maker_t ctx;
93
94   *r_maker = NULL;
95
96   ctx = xtrycalloc (1, sizeof *ctx);
97   if (!ctx)
98     return gpg_error_from_syserror ();
99   ctx->cookie = cookie;
100
101   *r_maker = ctx;
102   return 0;
103 }
104
105
106 static void
107 release_parts (part_t part)
108 {
109   while (part)
110     {
111       part_t partnext = part->next;
112       while (part->headers)
113         {
114           header_t hdrnext = part->headers->next;
115           xfree (part->headers);
116           part->headers = hdrnext;
117         }
118       release_parts (part->child);
119       xfree (part->boundary);
120       xfree (part->body);
121       xfree (part);
122       part = partnext;
123     }
124 }
125
126
127 /* Release a mime maker object.  */
128 void
129 mime_maker_release (mime_maker_t ctx)
130 {
131   if (!ctx)
132     return;
133
134   release_parts (ctx->mail);
135   xfree (ctx->boundary_suffix);
136   xfree (ctx);
137 }
138
139
140 /* Set verbose and debug mode.  */
141 void
142 mime_maker_set_verbose (mime_maker_t ctx, int level)
143 {
144   if (!level)
145     {
146       ctx->verbose = 0;
147       ctx->debug = 0;
148     }
149   else
150     {
151       ctx->verbose = 1;
152       if (level > 10)
153         ctx->debug = 1;
154     }
155 }
156
157
158 static void
159 dump_parts (part_t part, int level)
160 {
161   header_t hdr;
162
163   for (; part; part = part->next)
164     {
165       log_debug ("%*s[part %u]\n", level*2, "", part->partid);
166       for (hdr = part->headers; hdr; hdr = hdr->next)
167         {
168           log_debug ("%*s%s: %s\n", level*2, "", hdr->name, hdr->value);
169         }
170       if (part->body)
171         log_debug ("%*s[body %zu bytes]\n", level*2, "", part->bodylen);
172       if (part->child)
173         {
174           log_debug ("%*s[container]\n", level*2, "");
175           dump_parts (part->child, level+1);
176         }
177     }
178 }
179
180
181 /* Dump the mime tree for debugging.  */
182 void
183 mime_maker_dump_tree (mime_maker_t ctx)
184 {
185   dump_parts (ctx->mail, 0);
186 }
187
188
189 /* Find the parent node for NEEDLE starting at ROOT.  */
190 static part_t
191 find_parent (part_t root, part_t needle)
192 {
193   part_t node, n;
194
195   for (node = root->child; node; node = node->next)
196     {
197       if (node == needle)
198         return root;
199       if ((n = find_parent (node, needle)))
200         return n;
201     }
202   return NULL;
203 }
204
205 /* Find the part node from the PARTID.  */
206 static part_t
207 find_part (part_t root, unsigned int partid)
208 {
209   part_t node, n;
210
211   for (node = root->child; node; node = node->next)
212     {
213       if (node->partid == partid)
214         return root;
215       if ((n = find_part (node, partid)))
216         return n;
217     }
218   return NULL;
219 }
220
221
222 /* Create a boundary string.  Outr codes is aware of the general
223  * structure of that string (gebins with "=-=") so that
224  * it can protect against accidentally-used boundaries within the
225  * content.   */
226 static char *
227 generate_boundary (mime_maker_t ctx)
228 {
229   if (!ctx->boundary_suffix)
230     {
231       char buffer[12];
232
233       gcry_create_nonce (buffer, sizeof buffer);
234       ctx->boundary_suffix = zb32_encode (buffer, 8 * sizeof buffer);
235       if (!ctx->boundary_suffix)
236         return NULL;
237     }
238
239   ctx->boundary_counter++;
240   return es_bsprintf ("=-=%02d-%s=-=",
241                       ctx->boundary_counter, ctx->boundary_suffix);
242 }
243
244
245 /* Ensure that the context has a MAIL and CURRENT_PART object and
246  * return the parent object if available  */
247 static gpg_error_t
248 ensure_part (mime_maker_t ctx, part_t *r_parent)
249 {
250   if (!ctx->mail)
251     {
252       ctx->mail = xtrycalloc (1, sizeof *ctx->mail);
253       if (!ctx->mail)
254         {
255           if (r_parent)
256             *r_parent = NULL;
257           return gpg_error_from_syserror ();
258         }
259       log_assert (!ctx->current_part);
260       ctx->current_part = ctx->mail;
261       ctx->current_part->headers_tail = &ctx->current_part->headers;
262     }
263   log_assert (ctx->current_part);
264   if (r_parent)
265     *r_parent = find_parent (ctx->mail, ctx->current_part);
266
267   return 0;
268 }
269
270
271 /* Transform a header name into a standard capitalized format.
272  * "Content-Type".  Conversion stops at the colon. */
273 static void
274 capitalize_header_name (char *name)
275 {
276   unsigned char *p = name;
277   int first = 1;
278
279   /* Special cases first.  */
280   if (!ascii_strcasecmp (name, "MIME-Version"))
281     {
282       strcpy (name, "MIME-Version");
283       return;
284     }
285
286   /* Regular cases.  */
287   for (; *p && *p != ':'; p++)
288     {
289       if (*p == '-')
290         first = 1;
291       else if (first)
292         {
293           if (*p >= 'a' && *p <= 'z')
294             *p = *p - 'a' + 'A';
295           first = 0;
296         }
297       else if (*p >= 'A' && *p <= 'Z')
298         *p = *p - 'A' + 'a';
299     }
300 }
301
302
303 /* Check whether a header with NAME has already been set into PART.
304  * NAME must be in canonical capitalized format.  Return true or
305  * false. */
306 static int
307 have_header (part_t part, const char *name)
308 {
309   header_t hdr;
310
311   for (hdr = part->headers; hdr; hdr = hdr->next)
312     if (!strcmp (hdr->name, name))
313       return 1;
314   return 0;
315 }
316
317
318 /* Helper to add a header to a part.  */
319 static gpg_error_t
320 add_header (part_t part, const char *name, const char *value)
321 {
322   gpg_error_t err;
323   header_t hdr;
324   size_t namelen;
325   const char *s;
326   char *p;
327
328   if (!value)
329     {
330       s = strchr (name, '=');
331       if (!s)
332         return gpg_error (GPG_ERR_INV_ARG);
333       namelen = s - name;
334       value = s+1;
335     }
336   else
337     namelen = strlen (name);
338
339   hdr = xtrymalloc (sizeof *hdr + namelen);
340   if (!hdr)
341     return gpg_error_from_syserror ();
342   hdr->next = NULL;
343   memcpy (hdr->name, name, namelen);
344   hdr->name[namelen] = 0;
345
346   /* Check that the header name is valid.  We allow all lower and
347    * uppercase letters and, except for the first character, digits and
348    * the dash.  */
349   if (strspn (hdr->name, HEADER_NAME_CHARS) != namelen
350       || strchr ("-0123456789", *hdr->name))
351     {
352       xfree (hdr);
353       return gpg_error (GPG_ERR_INV_NAME);
354     }
355
356   capitalize_header_name (hdr->name);
357   hdr->value = xtrystrdup (value);
358   if (!hdr->value)
359     {
360       err = gpg_error_from_syserror ();
361       xfree (hdr);
362       return err;
363     }
364
365   for (p = hdr->value + strlen (hdr->value) - 1;
366        (p >= hdr->value
367         && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'));
368        p--)
369     *p = 0;
370   if (!(p >= hdr->value))
371     {
372       xfree (hdr->value);
373       xfree (hdr);
374       return gpg_error (GPG_ERR_INV_VALUE);  /* Only spaces.  */
375     }
376
377   if (part)
378     {
379       *part->headers_tail = hdr;
380       part->headers_tail = &hdr->next;
381     }
382   else
383     xfree (hdr);
384
385   return 0;
386 }
387
388
389 /* Add a header with NAME and VALUE to the current mail.  A LF in the
390  * VALUE will be handled automagically.  If NULL is used for VALUE it
391  * is expected that the NAME has the format "NAME=VALUE" and VALUE is
392  * taken from there.
393  *
394  * If no container has been added, the header will be used for the
395  * regular mail headers and not for a MIME part.  If the current part
396  * is in a container and a body has been added, we append a new part
397  * to the current container.  Thus for a non-MIME mail the caller
398  * needs to call this function followed by a call to add a body.  When
399  * adding a Content-Type the boundary parameter must not be included.
400  */
401 gpg_error_t
402 mime_maker_add_header (mime_maker_t ctx, const char *name, const char *value)
403 {
404   gpg_error_t err;
405   part_t part, parent;
406
407   /* Hack to use this function for a syntax check of NAME and VALUE.  */
408   if (!ctx)
409     return add_header (NULL, name, value);
410
411   err = ensure_part (ctx, &parent);
412   if (err)
413     return err;
414   part = ctx->current_part;
415
416   if ((part->body || part->child) && !parent)
417     {
418       /* We already have a body but no parent.  Adding another part is
419        * thus not possible.  */
420       return gpg_error (GPG_ERR_CONFLICT);
421     }
422   if (part->body || part->child)
423     {
424       /* We already have a body and there is a parent.  We now append
425        * a new part to the current container.  */
426       part = xtrycalloc (1, sizeof *part);
427       if (!part)
428         return gpg_error_from_syserror ();
429       part->partid = ++ctx->partid_counter;
430       part->headers_tail = &part->headers;
431       log_assert (!ctx->current_part->next);
432       ctx->current_part->next = part;
433       ctx->current_part = part;
434     }
435
436   /* If no NAME and no VALUE has been given we do not add a header.
437    * This can be used to create a new part without any header.  */
438   if (!name && !value)
439     return 0;
440
441   /* If we add Content-Type, make sure that we have a MIME-version
442    * header first; this simply looks better.  */
443   if (!ascii_strcasecmp (name, "Content-Type")
444       && !have_header (ctx->mail, "MIME-Version"))
445     {
446       err = add_header (ctx->mail, "MIME-Version", "1.0");
447       if (err)
448         return err;
449     }
450   return add_header (part, name, value);
451 }
452
453
454 /* Helper for mime_maker_add_{body,stream}.  */
455 static gpg_error_t
456 add_body (mime_maker_t ctx, const void *data, size_t datalen)
457 {
458   gpg_error_t err;
459   part_t part, parent;
460
461   err = ensure_part (ctx, &parent);
462   if (err)
463     return err;
464   part = ctx->current_part;
465   if (part->body)
466     return gpg_error (GPG_ERR_CONFLICT);
467
468   part->body = xtrymalloc (datalen? datalen : 1);
469   if (!part->body)
470     return gpg_error_from_syserror ();
471   part->bodylen = datalen;
472   if (data)
473     memcpy (part->body, data, datalen);
474
475   return 0;
476 }
477
478
479 /* Add STRING as body to the mail or the current MIME container.  A
480  * second call to this function is not allowed.
481  *
482  * FIXME: We may want to have an append_body to add more data to a body.
483  */
484 gpg_error_t
485 mime_maker_add_body (mime_maker_t ctx, const char *string)
486 {
487   return add_body (ctx, string, strlen (string));
488 }
489
490
491 /* This is the same as mime_maker_add_body but takes a stream as
492  * argument.  As of now the stream is copied to the MIME object but
493  * eventually we may delay that and read the stream only at the time
494  * it is needed.  Note that the address of the stream object must be
495  * passed and that the ownership of the stream is transferred to this
496  * MIME object.  To indicate the latter the function will store NULL
497  * at the ADDR_STREAM so that a caller can't use that object anymore
498  * except for es_fclose which accepts a NULL pointer.  */
499 gpg_error_t
500 mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr)
501 {
502   void *data;
503   size_t datalen;
504
505   es_rewind (*stream_addr);
506   if (es_fclose_snatch (*stream_addr, &data, &datalen))
507     return gpg_error_from_syserror ();
508   *stream_addr = NULL;
509   return add_body (ctx, data, datalen);
510 }
511
512
513 /* Add a new MIME container.  A container can be used instead of a
514  * body.  */
515 gpg_error_t
516 mime_maker_add_container (mime_maker_t ctx)
517 {
518   gpg_error_t err;
519   part_t part;
520
521   err = ensure_part (ctx, NULL);
522   if (err)
523     return err;
524   part = ctx->current_part;
525
526   if (part->body)
527     return gpg_error (GPG_ERR_CONFLICT); /* There is already a body. */
528   if (part->child || part->boundary)
529     return gpg_error (GPG_ERR_CONFLICT); /* There is already a container. */
530
531   /* Create a child node.  */
532   part->child = xtrycalloc (1, sizeof *part->child);
533   if (!part->child)
534     return gpg_error_from_syserror ();
535   part->child->headers_tail = &part->child->headers;
536
537   part->boundary = generate_boundary (ctx);
538   if (!part->boundary)
539     {
540       err = gpg_error_from_syserror ();
541       xfree (part->child);
542       part->child = NULL;
543       return err;
544     }
545
546   part = part->child;
547   part->partid = ++ctx->partid_counter;
548   ctx->current_part = part;
549
550   return 0;
551 }
552
553
554 /* Finish the current container.  */
555 gpg_error_t
556 mime_maker_end_container (mime_maker_t ctx)
557 {
558   gpg_error_t err;
559   part_t parent;
560
561   err = ensure_part (ctx, &parent);
562   if (err)
563     return err;
564   if (!parent)
565     return gpg_error (GPG_ERR_CONFLICT); /* No container.  */
566   while (parent->next)
567     parent = parent->next;
568   ctx->current_part = parent;
569   return 0;
570 }
571
572
573 /* Return the part-ID of the current part. */
574 unsigned int
575 mime_maker_get_partid (mime_maker_t ctx)
576 {
577   if (ensure_part (ctx, NULL))
578     return 0; /* Ooops.  */
579   return ctx->current_part->partid;
580 }
581
582
583 /* Write a header and handle emdedded LFs.  If BOUNDARY is not NULL it
584  * is appended to the value.  */
585 /* Fixme: Add automatic line wrapping.  */
586 static gpg_error_t
587 write_header (mime_maker_t ctx, const char *name, const char *value,
588               const char *boundary)
589 {
590   const char *s;
591
592   es_fprintf (ctx->outfp, "%s: ", name);
593
594   /* Note that add_header made sure that VALUE does not end with a LF.
595    * Thus we can assume that a LF is followed by non-whitespace.  */
596   for (s = value; *s; s++)
597     {
598       if (*s == '\n')
599         es_fputs ("\r\n\t", ctx->outfp);
600       else
601         es_fputc (*s, ctx->outfp);
602     }
603   if (boundary)
604     {
605       if (s > value && s[-1] != ';')
606         es_fputc (';', ctx->outfp);
607       es_fprintf (ctx->outfp, "\r\n\tboundary=\"%s\"", boundary);
608     }
609
610   es_fputs ("\r\n", ctx->outfp);
611
612   return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
613 }
614
615
616 static gpg_error_t
617 write_gap (mime_maker_t ctx)
618 {
619   es_fputs ("\r\n", ctx->outfp);
620   return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
621 }
622
623
624 static gpg_error_t
625 write_boundary (mime_maker_t ctx, const char *boundary, int last)
626 {
627   es_fprintf (ctx->outfp, "\r\n--%s%s\r\n", boundary, last?"--":"");
628   return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
629 }
630
631
632 /* Fixme: Apply required encoding.  */
633 static gpg_error_t
634 write_body (mime_maker_t ctx, const void *body, size_t bodylen)
635 {
636   const char *s;
637
638   for (s = body; bodylen; s++, bodylen--)
639     {
640       if (*s == '\n' && !(s > (const char *)body && s[-1] == '\r'))
641         es_fputc ('\r', ctx->outfp);
642       es_fputc (*s, ctx->outfp);
643     }
644
645   return es_ferror (ctx->outfp)? gpg_error_from_syserror () : 0;
646 }
647
648
649 /* Recursive worker for mime_maker_make.  */
650 static gpg_error_t
651 write_tree (mime_maker_t ctx, part_t parent, part_t part)
652 {
653   gpg_error_t err;
654   header_t hdr;
655
656   for (; part; part = part->next)
657     {
658       for (hdr = part->headers; hdr; hdr = hdr->next)
659         {
660           if (part->child && !strcmp (hdr->name, "Content-Type"))
661             err = write_header (ctx, hdr->name, hdr->value, part->boundary);
662           else
663             err = write_header (ctx, hdr->name, hdr->value, NULL);
664           if (err)
665             return err;
666         }
667       err = write_gap (ctx);
668       if (err)
669         return err;
670       if (part->body)
671         {
672           err = write_body (ctx, part->body, part->bodylen);
673           if (err)
674             return err;
675         }
676       if (part->child)
677         {
678           log_assert (part->boundary);
679           err = write_boundary (ctx, part->boundary, 0);
680           if (!err)
681             err = write_tree (ctx, part, part->child);
682           if (!err)
683             err = write_boundary (ctx, part->boundary, 1);
684           if (err)
685             return err;
686         }
687
688       if (part->next)
689         {
690           log_assert (parent && parent->boundary);
691           err = write_boundary (ctx, parent->boundary, 0);
692           if (err)
693             return err;
694         }
695     }
696   return 0;
697 }
698
699
700 /* Add headers we always require.  */
701 static gpg_error_t
702 add_missing_headers (mime_maker_t ctx)
703 {
704   gpg_error_t err;
705
706   if (!ctx->mail)
707     return gpg_error (GPG_ERR_NO_DATA);
708   if (!have_header (ctx->mail, "MIME-Version"))
709     {
710       /* Even if a Content-Type has never been set, we want to
711        * announce that we do MIME.  */
712       err = add_header (ctx->mail, "MIME-Version", "1.0");
713       if (err)
714         goto leave;
715     }
716
717   if (!have_header (ctx->mail, "Date"))
718     {
719       char *p = rfctimestamp (make_timestamp ());
720       if (!p)
721         err = gpg_error_from_syserror ();
722       else
723         err = add_header (ctx->mail, "Date", p);
724       xfree (p);
725       if (err)
726         goto leave;
727     }
728
729   err = 0;
730
731  leave:
732   return err;
733 }
734
735
736 /* Create message from the tree MIME and write it to FP.  Note that
737  * the output uses only a LF and a later called sendmail(1) is
738  * expected to convert them to network line endings.  */
739 gpg_error_t
740 mime_maker_make (mime_maker_t ctx, estream_t fp)
741 {
742   gpg_error_t err;
743
744   err = add_missing_headers (ctx);
745   if (err)
746     return err;
747
748   ctx->outfp = fp;
749   err = write_tree (ctx, NULL, ctx->mail);
750
751   ctx->outfp = NULL;
752   return err;
753 }
754
755
756 /* Create a stream object from the MIME part identified by PARTID and
757  * store it at R_STREAM.  If PARTID identifies a container the entire
758  * tree is returned. Using that function may read stream objects
759  * which have been added as MIME bodies.  The caller must close the
760  * stream object. */
761 gpg_error_t
762 mime_maker_get_part (mime_maker_t ctx, unsigned int partid, estream_t *r_stream)
763 {
764   gpg_error_t err;
765   part_t part;
766   estream_t fp;
767
768   *r_stream = NULL;
769
770   /* When the entire tree is requested, we make sure that all missing
771    * headers are applied.  We don't do that if only a part is
772    * requested because the additional headers (like Date:) will only
773    * be added to part 0 headers anyway. */
774   if (!partid)
775     {
776        err = add_missing_headers (ctx);
777        if (err)
778          return err;
779        part = ctx->mail;
780     }
781   else
782     part = find_part (ctx->mail, partid);
783
784   /* For now we use a memory stream object; however it would also be
785    * possible to create an object created on the fly while the caller
786    * is reading the returned stream.  */
787   fp = es_fopenmem (0, "w+b");
788   if (!fp)
789     return gpg_error_from_syserror ();
790
791   ctx->outfp = fp;
792   err = write_tree (ctx, NULL, part);
793   ctx->outfp = NULL;
794
795   if (!err)
796     {
797       es_rewind (fp);
798       *r_stream = fp;
799     }
800   else
801     es_fclose (fp);
802
803   return err;
804 }