~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib-mail/message-parser.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "str.h"
54
54
                                       struct message_block *block_r);
55
55
static int parse_next_body_to_eof(struct message_parser_ctx *ctx,
56
56
                                  struct message_block *block_r);
 
57
static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx,
 
58
                                         struct message_block *block_r);
57
59
static int preparsed_parse_next_header_init(struct message_parser_ctx *ctx,
58
60
                                            struct message_block *block_r);
59
61
 
151
153
                }
152
154
        }
153
155
 
154
 
        ctx->want_count = 1;
 
156
        if (!*full_r) {
 
157
                /* reset number of wanted characters if we actually got them */
 
158
                ctx->want_count = 1;
 
159
        }
155
160
        return 1;
156
161
}
157
162
 
264
269
        ptr = memchr(block_r->data, '\n', block_r->size);
265
270
        if (ptr == NULL) {
266
271
                parse_body_add_block(ctx, block_r);
267
 
                return 1;
 
272
                if (block_r->size > 0 &&
 
273
                    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
 
274
                        return 1;
 
275
                return 0;
268
276
        }
269
277
 
270
278
        /* found the LF */
271
279
        block_r->size = (ptr - block_r->data) + 1;
272
280
        parse_body_add_block(ctx, block_r);
273
281
 
274
 
        /* a new MIME part begins */
275
 
        ctx->parse_next_block = parse_next_mime_header_init;
276
 
        return 1;
 
282
        if (ctx->boundaries == NULL || ctx->boundaries->part != ctx->part) {
 
283
                /* epilogue */
 
284
                if (ctx->boundaries != NULL)
 
285
                        ctx->parse_next_block = parse_next_body_to_boundary;
 
286
                else
 
287
                        ctx->parse_next_block = parse_next_body_to_eof;
 
288
        } else {
 
289
                /* a new MIME part begins */
 
290
                ctx->parse_next_block = parse_next_mime_header_init;
 
291
        }
 
292
        if (block_r->size > 0 &&
 
293
            (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
 
294
                return 1;
 
295
        return ctx->parse_next_block(ctx, block_r);
277
296
}
278
297
 
279
298
static int parse_part_finish(struct message_parser_ctx *ctx,
281
300
                             struct message_block *block_r, bool first_line)
282
301
{
283
302
        struct message_part *part;
 
303
        size_t line_size;
284
304
 
285
305
        /* get back to parent MIME part, summing the child MIME part sizes
286
306
           into parent's body sizes */
293
313
        if (boundary->epilogue_found) {
294
314
                /* this boundary isn't needed anymore */
295
315
                ctx->boundaries = boundary->next;
296
 
 
297
 
                if (ctx->boundaries != NULL)
298
 
                        ctx->parse_next_block = parse_next_body_to_boundary;
299
 
                else
300
 
                        ctx->parse_next_block = parse_next_body_to_eof;
301
 
                return ctx->parse_next_block(ctx, block_r);
 
316
        } else {
 
317
                /* forget about the boundaries we possibly skipped */
 
318
                ctx->boundaries = boundary;
302
319
        }
303
320
 
304
 
        /* forget about the boundaries we possibly skipped */
305
 
        ctx->boundaries = boundary;
306
 
 
307
321
        /* the boundary itself should already be in buffer. add that. */
308
322
        block_r->data = i_stream_get_data(ctx->input, &block_r->size);
309
 
        i_assert(block_r->size >= ctx->skip + 2 + boundary->len +
310
 
                 (first_line ? 0 : 1));
 
323
        i_assert(block_r->size >= ctx->skip);
311
324
        block_r->data += ctx->skip;
312
 
        /* [\n]--<boundary> */
313
 
        block_r->size = (first_line ? 0 : 1) + 2 + boundary->len;
 
325
        /* [[\r]\n]--<boundary>[--] */
 
326
        if (first_line)
 
327
                line_size = 0;
 
328
        else if (block_r->data[0] == '\r') {
 
329
                i_assert(block_r->data[1] == '\n');
 
330
                line_size = 2;
 
331
        } else {
 
332
                i_assert(block_r->data[0] == '\n');
 
333
                line_size = 1;
 
334
        }
 
335
        line_size += 2 + boundary->len + (boundary->epilogue_found ? 2 : 0);
 
336
        i_assert(block_r->size >= ctx->skip + line_size);
 
337
        block_r->size = line_size;
314
338
        parse_body_add_block(ctx, block_r);
315
339
 
316
340
        ctx->parse_next_block = parse_next_body_skip_boundary_line;
317
 
        return 1;
 
341
 
 
342
        if ((ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0)
 
343
                return 1;
 
344
        return ctx->parse_next_block(ctx, block_r);
318
345
}
319
346
 
320
347
static int parse_next_body_to_boundary(struct message_parser_ctx *ctx,
376
403
        } else if (boundary_start == 0) {
377
404
                /* no linefeeds in this block. we can just skip it. */
378
405
                ret = 0;
 
406
                if (block_r->data[block_r->size-1] == '\r' && !ctx->eof) {
 
407
                        /* this may be the beginning of the \r\n--boundary */
 
408
                        block_r->size--;
 
409
                }
379
410
                boundary_start = block_r->size;
380
411
        } else {
381
412
                /* the boundary wasn't found from this data block,
392
423
        }
393
424
        if (block_r->size != 0) {
394
425
                parse_body_add_block(ctx, block_r);
 
426
 
 
427
                if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
 
428
                    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
 
429
                        return 0;
 
430
 
395
431
                return 1;
396
432
        }
397
433
        return ret <= 0 ? ret :
408
444
                return ret;
409
445
 
410
446
        parse_body_add_block(ctx, block_r);
 
447
 
 
448
        if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
 
449
            (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0)
 
450
                return 0;
 
451
 
411
452
        return 1;
412
453
}
413
454
 
423
464
        ctx->part_seen_content_type = TRUE;
424
465
 
425
466
        rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
426
 
        (void)rfc822_skip_lwsp(&parser);
 
467
        rfc822_skip_lwsp(&parser);
427
468
 
428
469
        content_type = t_str_new(64);
429
470
        if (rfc822_parse_content_type(&parser, content_type) < 0)
446
487
            ctx->last_boundary != NULL)
447
488
                return;
448
489
 
449
 
        (void)rfc2231_parse(&parser, &results);
 
490
        rfc2231_parse(&parser, &results);
450
491
        for (; *results != NULL; results += 2) {
451
492
                if (strcasecmp(results[0], "boundary") == 0) {
452
493
                        ctx->last_boundary =
464
505
{
465
506
        struct message_part *part = ctx->part;
466
507
        struct message_header_line *hdr;
467
 
        size_t size;
468
508
        int ret;
469
509
 
470
510
        if (ctx->skip > 0) {
474
514
 
475
515
        ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
476
516
        if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
477
 
                (void)i_stream_get_data(ctx->input, &size);
478
 
                ctx->want_count = size + 1;
 
517
                ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
479
518
                return ret;
480
519
        }
481
520
 
583
622
                        ctx->part = ctx->part->next;
584
623
                        break;
585
624
                }
 
625
 
 
626
                /* parse epilogue of multipart parent if requested */
 
627
                if (ctx->part->parent != NULL &&
 
628
                    (ctx->part->parent->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
 
629
                    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0) {
 
630
                        /* check for presence of epilogue */
 
631
                        uoff_t part_end = ctx->part->physical_pos +
 
632
                                ctx->part->header_size.physical_size +
 
633
                                ctx->part->body_size.physical_size;
 
634
                        uoff_t parent_end = ctx->part->parent->physical_pos +
 
635
                                ctx->part->parent->header_size.physical_size +
 
636
                                ctx->part->parent->body_size.physical_size;
 
637
 
 
638
                        if (parent_end > part_end) {
 
639
                                ctx->parse_next_block = preparsed_parse_epilogue_init;
 
640
                                break;
 
641
                        }
 
642
                }
586
643
                ctx->part = ctx->part->parent;
587
644
        }
588
645
        if (ctx->part == NULL)
599
656
        return ctx->parse_next_block(ctx, block_r);
600
657
}
601
658
 
 
659
static int preparsed_parse_prologue_finish(struct message_parser_ctx *ctx,
 
660
                                           struct message_block *block_r)
 
661
{
 
662
        i_stream_skip(ctx->input, ctx->skip);
 
663
        ctx->skip = 0;
 
664
 
 
665
        ctx->parse_next_block = preparsed_parse_next_header_init;
 
666
        ctx->part = ctx->part->children;
 
667
        return ctx->parse_next_block(ctx, block_r);
 
668
}
 
669
 
602
670
static int preparsed_parse_body_more(struct message_parser_ctx *ctx,
603
671
                                     struct message_block *block_r)
604
672
{
619
687
        return 1;
620
688
}
621
689
 
 
690
static int preparsed_parse_prologue_more(struct message_parser_ctx *ctx,
 
691
                                         struct message_block *block_r)
 
692
{
 
693
        uoff_t boundary_min_start, end_offset;
 
694
        const unsigned char *cur;
 
695
        bool full;
 
696
        int ret;
 
697
 
 
698
        i_assert(ctx->part->children != NULL);
 
699
        end_offset = ctx->part->children->physical_pos;
 
700
 
 
701
        if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
 
702
                return ret;
 
703
 
 
704
        if (ctx->input->v_offset + block_r->size >= end_offset) {
 
705
                /* we've got the full prologue: clip off the initial boundary */
 
706
                block_r->size = end_offset - ctx->input->v_offset;
 
707
                cur = block_r->data + block_r->size - 1;
 
708
 
 
709
                /* [\r]\n--boundary[\r]\n */ 
 
710
                if (block_r->size < 5 || *cur != '\n') {
 
711
                        ctx->broken = TRUE;
 
712
                        return -1;
 
713
                }
 
714
                
 
715
                cur--;
 
716
                if (*cur == '\r') cur--;
 
717
 
 
718
                /* find newline just before boundary */
 
719
                for (; cur >= block_r->data; cur--) {
 
720
                        if (*cur == '\n') break;
 
721
                }
 
722
 
 
723
                if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
 
724
                        ctx->broken = TRUE;
 
725
                        return -1;
 
726
                }
 
727
 
 
728
                if (cur != block_r->data && cur[-1] == '\r') cur--;
 
729
 
 
730
                /* clip boundary */
 
731
                block_r->size = cur - block_r->data;                    
 
732
 
 
733
                ctx->parse_next_block = preparsed_parse_prologue_finish;
 
734
                ctx->skip = block_r->size;
 
735
                return 1;
 
736
        }
 
737
                
 
738
        /* retain enough data in the stream buffer to contain initial boundary */
 
739
        if (end_offset > BOUNDARY_END_MAX_LEN)
 
740
                boundary_min_start = end_offset - BOUNDARY_END_MAX_LEN;
 
741
        else
 
742
                boundary_min_start = 0;
 
743
 
 
744
        if (ctx->input->v_offset + block_r->size >= boundary_min_start) {
 
745
                if (boundary_min_start <= ctx->input->v_offset)
 
746
                        return 0;
 
747
                block_r->size = boundary_min_start - ctx->input->v_offset;
 
748
        }
 
749
        ctx->skip = block_r->size;
 
750
        return 1;
 
751
}
 
752
 
 
753
static int preparsed_parse_epilogue_more(struct message_parser_ctx *ctx,
 
754
                                         struct message_block *block_r)
 
755
{
 
756
        uoff_t end_offset = ctx->part->physical_pos +
 
757
                ctx->part->header_size.physical_size +
 
758
                ctx->part->body_size.physical_size;
 
759
        bool full;
 
760
        int ret;
 
761
 
 
762
        if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
 
763
                return ret;
 
764
 
 
765
        if (ctx->input->v_offset + block_r->size >= end_offset) {
 
766
                block_r->size = end_offset - ctx->input->v_offset;
 
767
                ctx->parse_next_block = preparsed_parse_body_finish;
 
768
        }
 
769
        ctx->skip = block_r->size;
 
770
        return 1;
 
771
}
 
772
 
 
773
static int preparsed_parse_epilogue_boundary(struct message_parser_ctx *ctx,
 
774
                                             struct message_block *block_r)
 
775
{
 
776
        uoff_t end_offset = ctx->part->physical_pos +
 
777
                ctx->part->header_size.physical_size +
 
778
                ctx->part->body_size.physical_size;
 
779
        const unsigned char *data, *cur;
 
780
        size_t size;
 
781
        bool full;
 
782
        int ret;
 
783
 
 
784
        if (end_offset - ctx->input->v_offset < 7) {
 
785
                ctx->broken = TRUE;
 
786
                return -1;
 
787
        }
 
788
 
 
789
        if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0)
 
790
                return ret;
 
791
 
 
792
        /* [\r]\n--boundary--[\r]\n */
 
793
        if (block_r->size < 7) {
 
794
                ctx->want_count = 7;
 
795
                return 0;
 
796
        }
 
797
 
 
798
        data = block_r->data;
 
799
        size = block_r->size;
 
800
        cur = data;
 
801
 
 
802
        if (*cur == '\r') cur++;
 
803
 
 
804
        if (cur[0] != '\n' || cur[1] != '-' || data[2] != '-') {
 
805
                ctx->broken = TRUE;
 
806
                return -1;
 
807
        }
 
808
 
 
809
        /* find the end of the line */
 
810
        cur += 3;
 
811
        if ((cur = memchr(cur, '\n', size - (cur-data))) == NULL) {
 
812
                if (end_offset < ctx->input->v_offset + size) {
 
813
                        ctx->broken = TRUE;
 
814
                        return -1;
 
815
                } else if (ctx->input->v_offset + size < end_offset &&
 
816
                           size < BOUNDARY_END_MAX_LEN &&
 
817
                           !ctx->input->eof && !full) {
 
818
                        ctx->want_count = BOUNDARY_END_MAX_LEN;
 
819
                        return 0;
 
820
                }
 
821
        }
 
822
 
 
823
        block_r->size = 0;
 
824
        ctx->parse_next_block = preparsed_parse_epilogue_more;
 
825
        ctx->skip = cur - data + 1;
 
826
        return 0;
 
827
}
 
828
 
622
829
static int preparsed_parse_body_init(struct message_parser_ctx *ctx,
623
830
                                     struct message_block *block_r)
624
831
{
632
839
        }
633
840
        i_stream_skip(ctx->input, offset - ctx->input->v_offset);
634
841
 
635
 
        ctx->parse_next_block = preparsed_parse_body_more;
636
 
        return preparsed_parse_body_more(ctx, block_r);
 
842
        /* multipart messages may begin with --boundary--, which makes them
 
843
           not have any children. */
 
844
        if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) == 0 ||
 
845
            ctx->part->children == NULL)
 
846
                ctx->parse_next_block = preparsed_parse_body_more;
 
847
        else
 
848
                ctx->parse_next_block = preparsed_parse_prologue_more;
 
849
        return ctx->parse_next_block(ctx, block_r);
 
850
}
 
851
 
 
852
static int preparsed_parse_epilogue_init(struct message_parser_ctx *ctx,
 
853
                                         struct message_block *block_r)
 
854
{
 
855
        uoff_t offset = ctx->part->physical_pos +
 
856
                ctx->part->header_size.physical_size +
 
857
                ctx->part->body_size.physical_size;
 
858
 
 
859
        ctx->part = ctx->part->parent;
 
860
 
 
861
        if (offset < ctx->input->v_offset) {
 
862
                /* last child was actually larger than the cached size
 
863
                   suggested */
 
864
                ctx->broken = TRUE;
 
865
                return -1;
 
866
        }
 
867
        i_stream_skip(ctx->input, offset - ctx->input->v_offset);
 
868
 
 
869
        ctx->parse_next_block = preparsed_parse_epilogue_boundary;
 
870
        return ctx->parse_next_block(ctx, block_r);
637
871
}
638
872
 
639
873
static int preparsed_parse_finish_header(struct message_parser_ctx *ctx,
640
874
                                         struct message_block *block_r)
641
875
{
642
876
        if (ctx->part->children != NULL) {
643
 
                ctx->parse_next_block = preparsed_parse_next_header_init;
644
 
                ctx->part = ctx->part->children;
 
877
                if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 &&
 
878
                    (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) != 0)
 
879
                        ctx->parse_next_block = preparsed_parse_body_init;
 
880
                else {
 
881
                        ctx->parse_next_block = preparsed_parse_next_header_init;
 
882
                        ctx->part = ctx->part->children;
 
883
                }
645
884
        } else if ((ctx->flags & MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK) == 0) {
646
885
                ctx->parse_next_block = preparsed_parse_body_init;
647
886
        } else {
654
893
                                       struct message_block *block_r)
655
894
{
656
895
        struct message_header_line *hdr;
657
 
        size_t size;
658
896
        int ret;
659
897
 
660
898
        ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
661
899
        if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
662
 
                (void)i_stream_get_data(ctx->input, &size);
663
 
                ctx->want_count = size + 1;
 
900
                ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
664
901
                return ret;
665
902
        }
666
903