1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "str.h"
6 #include "str-sanitize.h"
7 #include "mempool.h"
8 #include "buffer.h"
9 #include "hash.h"
10 #include "array.h"
11 #include "ostream.h"
12
13 #include "sieve-common.h"
14 #include "sieve-error.h"
15 #include "sieve-extensions.h"
16 #include "sieve-code.h"
17 #include "sieve-script.h"
18
19 #include "sieve-binary-private.h"
20
21 /*
22 * Forward declarations
23 */
24
25 static inline sieve_size_t
26 sieve_binary_emit_dynamic_data(struct sieve_binary_block *sblock,
27 const void *data, size_t size);
28
29 /*
30 * Emission functions
31 */
32
33 /* Low-level emission functions */
34
35 static inline void
_sieve_binary_emit_data(struct sieve_binary_block * sblock,const void * data,sieve_size_t size)36 _sieve_binary_emit_data(struct sieve_binary_block *sblock,
37 const void *data, sieve_size_t size)
38 {
39 buffer_append(sblock->data, data, size);
40 }
41
42 static inline void
_sieve_binary_emit_byte(struct sieve_binary_block * sblock,uint8_t byte)43 _sieve_binary_emit_byte(struct sieve_binary_block *sblock, uint8_t byte)
44 {
45 _sieve_binary_emit_data(sblock, &byte, 1);
46 }
47
48 static inline void
_sieve_binary_update_data(struct sieve_binary_block * sblock,sieve_size_t address,const void * data,sieve_size_t size)49 _sieve_binary_update_data(struct sieve_binary_block *sblock,
50 sieve_size_t address, const void *data,
51 sieve_size_t size)
52 {
53 buffer_write(sblock->data, address, data, size);
54 }
55
sieve_binary_emit_data(struct sieve_binary_block * sblock,const void * data,sieve_size_t size)56 sieve_size_t sieve_binary_emit_data(struct sieve_binary_block *sblock,
57 const void *data, sieve_size_t size)
58 {
59 sieve_size_t address = _sieve_binary_block_get_size(sblock);
60
61 _sieve_binary_emit_data(sblock, data, size);
62
63 return address;
64 }
65
sieve_binary_emit_byte(struct sieve_binary_block * sblock,uint8_t byte)66 sieve_size_t sieve_binary_emit_byte(struct sieve_binary_block *sblock,
67 uint8_t byte)
68 {
69 sieve_size_t address = _sieve_binary_block_get_size(sblock);
70
71 _sieve_binary_emit_data(sblock, &byte, 1);
72
73 return address;
74 }
75
sieve_binary_update_data(struct sieve_binary_block * sblock,sieve_size_t address,const void * data,sieve_size_t size)76 void sieve_binary_update_data(struct sieve_binary_block *sblock,
77 sieve_size_t address, const void *data,
78 sieve_size_t size)
79 {
80 _sieve_binary_update_data(sblock, address, data, size);
81 }
82
83 /* Offset emission functions */
84
sieve_binary_emit_offset(struct sieve_binary_block * sblock,sieve_offset_t offset)85 sieve_size_t sieve_binary_emit_offset(struct sieve_binary_block *sblock,
86 sieve_offset_t offset)
87 {
88 sieve_size_t address = _sieve_binary_block_get_size(sblock);
89 uint8_t encoded[sizeof(offset)];
90 int i;
91
92 for (i = sizeof(offset)-1; i >= 0; i--) {
93 encoded[i] = (uint8_t)offset;
94 offset >>= 8;
95 }
96
97 _sieve_binary_emit_data(sblock, encoded, sizeof(offset));
98
99 return address;
100 }
101
sieve_binary_resolve_offset(struct sieve_binary_block * sblock,sieve_size_t address)102 void sieve_binary_resolve_offset(struct sieve_binary_block *sblock,
103 sieve_size_t address)
104 {
105 sieve_size_t cur_address = _sieve_binary_block_get_size(sblock);
106 sieve_offset_t offset;
107 uint8_t encoded[sizeof(offset)];
108 int i;
109
110 i_assert(cur_address > address);
111 i_assert((cur_address - address) <= (sieve_offset_t)-1);
112 offset = cur_address - address;
113 for (i = sizeof(offset)-1; i >= 0; i--) {
114 encoded[i] = (uint8_t)offset;
115 offset >>= 8;
116 }
117
118 _sieve_binary_update_data(sblock, address, encoded, sizeof(offset));
119 }
120
121 /* Literal emission */
122
sieve_binary_emit_integer(struct sieve_binary_block * sblock,sieve_number_t integer)123 sieve_size_t sieve_binary_emit_integer(struct sieve_binary_block *sblock,
124 sieve_number_t integer)
125 {
126 sieve_size_t address = _sieve_binary_block_get_size(sblock);
127 uint8_t buffer[sizeof(sieve_number_t) + 1];
128 int bufpos = sizeof(buffer) - 1;
129
130 /* Encode last byte [0xxxxxxx]; msb == 0 marks the last byte */
131 buffer[bufpos] = integer & 0x7F;
132 bufpos--;
133
134 /* Encode first bytes [1xxxxxxx] */
135 integer >>= 7;
136 while (integer > 0) {
137 buffer[bufpos] = (integer & 0x7F) | 0x80;
138 bufpos--;
139 integer >>= 7;
140 }
141
142 /* Emit encoded integer */
143 bufpos++;
144 _sieve_binary_emit_data(sblock, buffer + bufpos, sizeof(buffer) - bufpos);
145
146 return address;
147 }
148
149 static inline sieve_size_t
sieve_binary_emit_dynamic_data(struct sieve_binary_block * sblock,const void * data,sieve_size_t size)150 sieve_binary_emit_dynamic_data(struct sieve_binary_block *sblock,
151 const void *data, sieve_size_t size)
152 {
153 sieve_size_t address =
154 sieve_binary_emit_integer(sblock, (sieve_number_t)size);
155
156 _sieve_binary_emit_data(sblock, data, size);
157
158 return address;
159 }
160
sieve_binary_emit_cstring(struct sieve_binary_block * sblock,const char * str)161 sieve_size_t sieve_binary_emit_cstring(struct sieve_binary_block *sblock,
162 const char *str)
163 {
164 sieve_size_t address =
165 sieve_binary_emit_dynamic_data(sblock, (void *)str,
166 (sieve_size_t)strlen(str));
167
168 _sieve_binary_emit_byte(sblock, 0);
169 return address;
170 }
171
sieve_binary_emit_string(struct sieve_binary_block * sblock,const string_t * str)172 sieve_size_t sieve_binary_emit_string(struct sieve_binary_block *sblock,
173 const string_t *str)
174 {
175 sieve_size_t address =
176 sieve_binary_emit_dynamic_data(sblock, (void *)str_data(str),
177 (sieve_size_t)str_len(str));
178
179 _sieve_binary_emit_byte(sblock, 0);
180 return address;
181 }
182
183 /*
184 * Extension emission
185 */
186
sieve_binary_emit_extension(struct sieve_binary_block * sblock,const struct sieve_extension * ext,unsigned int offset)187 sieve_size_t sieve_binary_emit_extension(struct sieve_binary_block *sblock,
188 const struct sieve_extension *ext,
189 unsigned int offset)
190 {
191 sieve_size_t address = _sieve_binary_block_get_size(sblock);
192 struct sieve_binary_extension_reg *ereg = NULL;
193
194 (void)sieve_binary_extension_register(sblock->sbin, ext, &ereg);
195
196 i_assert(ereg != NULL);
197
198 _sieve_binary_emit_byte(sblock, offset + ereg->index);
199 return address;
200 }
201
sieve_binary_emit_extension_object(struct sieve_binary_block * sblock,const struct sieve_extension_objects * objs,unsigned int code)202 void sieve_binary_emit_extension_object(
203 struct sieve_binary_block *sblock,
204 const struct sieve_extension_objects *objs, unsigned int code)
205 {
206 if (objs->count > 1)
207 _sieve_binary_emit_byte(sblock, code);
208 }
209
210 /*
211 * Code retrieval
212 */
213
214 #define ADDR_CODE_READ(block) \
215 size_t _code_size; \
216 const int8_t *_code = buffer_get_data((block)->data, &_code_size)
217
218 #define ADDR_CODE_AT(address) \
219 ((int8_t)(_code[*address]))
220 #define ADDR_DATA_AT(address) \
221 ((uint8_t)(_code[*address]))
222 #define ADDR_POINTER(address) \
223 ((const int8_t *)(&_code[*address]))
224
225 #define ADDR_BYTES_LEFT(address) \
226 ((*address) > _code_size ? 0 : ((_code_size) - (*address)))
227 #define ADDR_JUMP(address, offset) \
228 (*address) += offset
229
230 /* Literals */
231
sieve_binary_read_byte(struct sieve_binary_block * sblock,sieve_size_t * address,unsigned int * byte_r)232 bool sieve_binary_read_byte(struct sieve_binary_block *sblock,
233 sieve_size_t *address, unsigned int *byte_r)
234 {
235 ADDR_CODE_READ(sblock);
236
237 if (ADDR_BYTES_LEFT(address) >= 1) {
238 if (byte_r != NULL)
239 *byte_r = ADDR_DATA_AT(address);
240 ADDR_JUMP(address, 1);
241
242 return TRUE;
243 }
244
245 if (byte_r != NULL)
246 *byte_r = 0;
247 return FALSE;
248 }
249
sieve_binary_read_code(struct sieve_binary_block * sblock,sieve_size_t * address,signed int * code_r)250 bool sieve_binary_read_code(struct sieve_binary_block *sblock,
251 sieve_size_t *address, signed int *code_r)
252 {
253 ADDR_CODE_READ(sblock);
254
255 if (ADDR_BYTES_LEFT(address) >= 1) {
256 if (code_r != NULL)
257 *code_r = ADDR_CODE_AT(address);
258 ADDR_JUMP(address, 1);
259
260 return TRUE;
261 }
262
263 if (code_r != NULL)
264 *code_r = 0;
265 return FALSE;
266 }
267
268
sieve_binary_read_offset(struct sieve_binary_block * sblock,sieve_size_t * address,sieve_offset_t * offset_r)269 bool sieve_binary_read_offset(struct sieve_binary_block *sblock,
270 sieve_size_t *address, sieve_offset_t *offset_r)
271 {
272 sieve_offset_t offs = 0;
273 ADDR_CODE_READ(sblock);
274
275 if (ADDR_BYTES_LEFT(address) >= 4) {
276 int i;
277
278 for (i = 0; i < 4; i++) {
279 offs = (offs << 8) + ADDR_DATA_AT(address);
280 ADDR_JUMP(address, 1);
281 }
282
283 if (offset_r != NULL)
284 *offset_r = offs;
285
286 return TRUE;
287 }
288 return FALSE;
289 }
290
291 /* FIXME: might need negative numbers in the future */
sieve_binary_read_integer(struct sieve_binary_block * sblock,sieve_size_t * address,sieve_number_t * int_r)292 bool sieve_binary_read_integer(struct sieve_binary_block *sblock,
293 sieve_size_t *address, sieve_number_t *int_r)
294 {
295 int bits = sizeof(sieve_number_t) * 8;
296 sieve_number_t integer = 0;
297
298 ADDR_CODE_READ(sblock);
299
300 if (ADDR_BYTES_LEFT(address) == 0)
301 return FALSE;
302
303 /* Read first integer bytes [1xxxxxxx] */
304 while ((ADDR_DATA_AT(address) & 0x80) > 0) {
305 if (ADDR_BYTES_LEFT(address) > 0 && bits > 0) {
306 integer |= ADDR_DATA_AT(address) & 0x7F;
307 ADDR_JUMP(address, 1);
308
309 /* Each byte encodes 7 bits of the integer */
310 integer <<= 7;
311 bits -= 7;
312 } else {
313 /* This is an error */
314 return FALSE;
315 }
316 }
317
318 /* Read last byte [0xxxxxxx] */
319 integer |= ADDR_DATA_AT(address) & 0x7F;
320 ADDR_JUMP(address, 1);
321
322 if (int_r != NULL)
323 *int_r = integer;
324 return TRUE;
325 }
326
sieve_binary_read_string(struct sieve_binary_block * sblock,sieve_size_t * address,string_t ** str_r)327 bool sieve_binary_read_string(struct sieve_binary_block *sblock,
328 sieve_size_t *address, string_t **str_r)
329 {
330 unsigned int strlen = 0;
331 const char *strdata;
332
333 ADDR_CODE_READ(sblock);
334
335 if (!sieve_binary_read_unsigned(sblock, address, &strlen))
336 return FALSE;
337
338 if (strlen > ADDR_BYTES_LEFT(address))
339 return FALSE;
340
341 strdata = (const char *)ADDR_POINTER(address);
342 ADDR_JUMP(address, strlen);
343
344 if (ADDR_CODE_AT(address) != 0)
345 return FALSE;
346
347 if (str_r != NULL)
348 *str_r = t_str_new_const(strdata, strlen);
349
350 ADDR_JUMP(address, 1);
351
352 return TRUE;
353 }
354
sieve_binary_read_extension(struct sieve_binary_block * sblock,sieve_size_t * address,unsigned int * offset_r,const struct sieve_extension ** ext_r)355 bool sieve_binary_read_extension(struct sieve_binary_block *sblock,
356 sieve_size_t *address, unsigned int *offset_r,
357 const struct sieve_extension **ext_r)
358 {
359 unsigned int code;
360 unsigned int offset = *offset_r;
361 const struct sieve_extension *ext = NULL;
362
363 ADDR_CODE_READ(sblock);
364
365 if (ADDR_BYTES_LEFT(address) == 0)
366 return FALSE;
367
368 *offset_r = code = ADDR_DATA_AT(address);
369 ADDR_JUMP(address, 1);
370
371 if (code >= offset) {
372 ext = sieve_binary_extension_get_by_index(sblock->sbin,
373 (code - offset));
374 if (ext == NULL)
375 return FALSE;
376 }
377
378 if (ext_r != NULL)
379 *ext_r = ext;
380 return TRUE;
381 }
382
383 const void *
sieve_binary_read_extension_object(struct sieve_binary_block * sblock,sieve_size_t * address,const struct sieve_extension_objects * objs)384 sieve_binary_read_extension_object(struct sieve_binary_block *sblock,
385 sieve_size_t *address,
386 const struct sieve_extension_objects *objs)
387 {
388 unsigned int code;
389
390 ADDR_CODE_READ(sblock);
391
392 if (objs->count == 0)
393 return NULL;
394 if (objs->count == 1)
395 return objs->objects;
396 if (ADDR_BYTES_LEFT(address) == 0)
397 return NULL;
398
399 code = ADDR_DATA_AT(address);
400 ADDR_JUMP(address, 1);
401
402 if (code >= objs->count)
403 return NULL;
404 return ((const void *const *)objs->objects)[code];
405 }
406