Mercurial > dovecot > core-2.2
annotate src/lib/istream-base64-decoder.c @ 22664:fea53c2725c0
director: Fix director_max_parallel_moves/kicks type
Should be uint, not time.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Thu, 09 Nov 2017 12:24:16 +0200 |
parents | 2e2563132d5f |
children | cb108f786fb4 |
rev | line source |
---|---|
21390
2e2563132d5f
Updated copyright notices to include the year 2017.
Stephan Bosch <stephan.bosch@dovecot.fi>
parents:
19552
diff
changeset
|
1 /* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */ |
14845 | 2 |
3 #include "lib.h" | |
4 #include "buffer.h" | |
5 #include "base64.h" | |
16773
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
6 #include "hex-binary.h" |
14845 | 7 #include "istream-private.h" |
8 #include "istream-base64.h" | |
9 | |
10 struct base64_decoder_istream { | |
11 struct istream_private istream; | |
12 }; | |
13 | |
14 static int i_stream_read_parent(struct istream_private *stream) | |
15 { | |
16 size_t size; | |
17 ssize_t ret; | |
18 | |
19 size = i_stream_get_data_size(stream->parent); | |
20 if (size >= 4) | |
21 return 1; | |
22 | |
23 /* we have less than one base64 block. | |
24 see if there is more data available. */ | |
25 ret = i_stream_read(stream->parent); | |
26 if (ret <= 0) { | |
27 stream->istream.stream_errno = stream->parent->stream_errno; | |
28 stream->istream.eof = stream->parent->eof; | |
29 return ret; | |
30 } | |
31 size = i_stream_get_data_size(stream->parent); | |
32 i_assert(size != 0); | |
33 return 1; | |
34 } | |
35 | |
36 static int | |
37 i_stream_base64_try_decode_block(struct base64_decoder_istream *bstream) | |
38 { | |
39 struct istream_private *stream = &bstream->istream; | |
40 const unsigned char *data; | |
41 size_t size, avail, buffer_avail, pos; | |
42 buffer_t buf; | |
43 | |
44 data = i_stream_get_data(stream->parent, &size); | |
45 if (size == 0) | |
46 return 0; | |
47 | |
48 i_stream_try_alloc(stream, (size+3)/4*3, &avail); | |
49 buffer_avail = stream->buffer_size - stream->pos; | |
50 | |
51 if ((size + 3) / 4 * 3 > buffer_avail) { | |
52 /* can't fit everything to destination buffer. | |
53 write as much as we can. */ | |
54 size = (buffer_avail / 3) * 4; | |
55 if (size == 0) | |
56 return -2; | |
57 } | |
58 | |
15034
7efef678bca8
Renamed buffer_create_*data() to buffer_create_from_*data() for consistency.
Timo Sirainen <tss@iki.fi>
parents:
14948
diff
changeset
|
59 buffer_create_from_data(&buf, stream->w_buffer + stream->pos, |
7efef678bca8
Renamed buffer_create_*data() to buffer_create_from_*data() for consistency.
Timo Sirainen <tss@iki.fi>
parents:
14948
diff
changeset
|
60 buffer_avail); |
14845 | 61 if (base64_decode(data, size, &pos, &buf) < 0) { |
16773
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
62 io_stream_set_error(&stream->iostream, |
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
63 "Invalid base64 data: 0x%s", |
17506
c65b4c41698c
lib: Fixed read buffer overflow in istream-base64-decoder error handling
Timo Sirainen <tss@iki.fi>
parents:
17130
diff
changeset
|
64 binary_to_hex(data+pos, I_MIN(size-pos, 8))); |
14845 | 65 stream->istream.stream_errno = EINVAL; |
66 return -1; | |
67 } | |
68 | |
69 stream->pos += buf.used; | |
70 i_stream_skip(stream->parent, pos); | |
71 return pos > 0 ? 1 : 0; | |
72 } | |
73 | |
74 static ssize_t i_stream_base64_decoder_read(struct istream_private *stream) | |
75 { | |
76 struct base64_decoder_istream *bstream = | |
77 (struct base64_decoder_istream *)stream; | |
16773
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
78 const unsigned char *data; |
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
79 size_t pre_count, post_count, size; |
14845 | 80 int ret; |
81 | |
82 do { | |
83 ret = i_stream_read_parent(stream); | |
84 if (ret <= 0) { | |
85 if (ret < 0 && stream->istream.stream_errno == 0 && | |
86 i_stream_get_data_size(stream->parent) > 0) { | |
87 /* base64 input with a partial block */ | |
16773
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
88 data = i_stream_get_data(stream->parent, &size); |
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
89 io_stream_set_error(&stream->iostream, |
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
90 "base64 input ends with a partial block: 0x%s", |
76d5e3c8cec3
iostreams: Set stream error string when it provides extra information.
Timo Sirainen <tss@iki.fi>
parents:
15715
diff
changeset
|
91 binary_to_hex(data, size)); |
14845 | 92 stream->istream.stream_errno = EINVAL; |
93 } | |
94 return ret; | |
95 } | |
96 | |
97 /* encode as many blocks as fits into destination buffer */ | |
98 pre_count = stream->pos - stream->skip; | |
99 while ((ret = i_stream_base64_try_decode_block(bstream)) > 0) ; | |
100 post_count = stream->pos - stream->skip; | |
14846
4d13da5c571b
Various fixes to istream-base64-encoder/decoder
Timo Sirainen <tss@iki.fi>
parents:
14845
diff
changeset
|
101 } while (ret == 0 && pre_count == post_count); |
14845 | 102 |
14948
5cf1cedb75e6
istream-base64: Fixed returning -2 too early.
Timo Sirainen <tss@iki.fi>
parents:
14846
diff
changeset
|
103 if (ret < 0 && pre_count == post_count) |
14845 | 104 return ret; |
105 | |
106 i_assert(post_count > pre_count); | |
107 return post_count - pre_count; | |
108 } | |
109 | |
110 static void | |
111 i_stream_base64_decoder_seek(struct istream_private *stream, | |
112 uoff_t v_offset, bool mark) | |
113 { | |
114 if (v_offset < stream->istream.v_offset) { | |
115 /* seeking backwards - go back to beginning and seek | |
116 forward from there. */ | |
117 stream->parent_expected_offset = stream->parent_start_offset; | |
118 stream->skip = stream->pos = 0; | |
119 stream->istream.v_offset = 0; | |
120 i_stream_seek(stream->parent, 0); | |
121 } | |
122 i_stream_default_seek_nonseekable(stream, v_offset, mark); | |
123 } | |
124 | |
125 struct istream * | |
126 i_stream_create_base64_decoder(struct istream *input) | |
127 { | |
128 struct base64_decoder_istream *bstream; | |
129 | |
130 bstream = i_new(struct base64_decoder_istream, 1); | |
131 bstream->istream.max_buffer_size = input->real_stream->max_buffer_size; | |
132 | |
133 bstream->istream.read = i_stream_base64_decoder_read; | |
134 bstream->istream.seek = i_stream_base64_decoder_seek; | |
135 | |
136 bstream->istream.istream.readable_fd = FALSE; | |
137 bstream->istream.istream.blocking = input->blocking; | |
138 bstream->istream.istream.seekable = input->seekable; | |
139 return i_stream_create(&bstream->istream, input, | |
140 i_stream_get_fd(input)); | |
141 } |