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