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 
8 #include "rfc2822.h"
9 
10 #include "sieve-common.h"
11 #include "sieve-ast.h"
12 #include "sieve-validator.h"
13 #include "sieve-generator.h"
14 #include "sieve-binary.h"
15 #include "sieve-commands.h"
16 #include "sieve-code.h"
17 #include "sieve-interpreter.h"
18 
19 /*
20  * Literal arguments
21  */
22 
23 /* Forward declarations */
24 
25 static bool arg_number_generate
26 	(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
27 		struct sieve_command *context);
28 static bool arg_string_generate
29 	(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
30 		struct sieve_command *context);
31 static bool arg_string_list_validate
32 	(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
33 		struct sieve_command *context);
34 static bool arg_string_list_generate
35 	(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
36 		struct sieve_command *context);
37 
38 /* Argument objects */
39 
40 const struct sieve_argument_def number_argument = {
41 	.identifier = "@number",
42 	.generate = arg_number_generate
43 };
44 
45 const struct sieve_argument_def string_argument = {
46 	.identifier = "@string",
47 	.generate = arg_string_generate
48 };
49 
50 const struct sieve_argument_def string_list_argument = {
51 	.identifier = "@string-list",
52 	.validate = arg_string_list_validate,
53 	.generate = arg_string_list_generate
54 };
55 
56 /* Argument implementations */
57 
arg_number_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd ATTR_UNUSED)58 static bool arg_number_generate
59 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
60 	struct sieve_command *cmd ATTR_UNUSED)
61 {
62 	sieve_opr_number_emit(cgenv->sblock, sieve_ast_argument_number(arg));
63 
64 	return TRUE;
65 }
66 
arg_string_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd ATTR_UNUSED)67 static bool arg_string_generate
68 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
69 	struct sieve_command *cmd ATTR_UNUSED)
70 {
71 	sieve_opr_string_emit(cgenv->sblock, sieve_ast_argument_str(arg));
72 
73 	return TRUE;
74 }
75 
arg_string_list_validate(struct sieve_validator * valdtr,struct sieve_ast_argument ** arg,struct sieve_command * cmd)76 static bool arg_string_list_validate
77 (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
78 	struct sieve_command *cmd)
79 {
80 	struct sieve_ast_argument *stritem;
81 
82 	stritem = sieve_ast_strlist_first(*arg);
83 	while ( stritem != NULL ) {
84 		if ( !sieve_validator_argument_activate(valdtr, cmd, stritem, FALSE) )
85 			return FALSE;
86 
87 		stritem = sieve_ast_strlist_next(stritem);
88 	}
89 
90 	return TRUE;
91 }
92 
emit_string_list_operand(const struct sieve_codegen_env * cgenv,const struct sieve_ast_argument * strlist,struct sieve_command * cmd)93 static bool emit_string_list_operand
94 (const struct sieve_codegen_env *cgenv, const struct sieve_ast_argument *strlist,
95 	struct sieve_command *cmd)
96 {
97 	void *list_context;
98 	struct sieve_ast_argument *stritem;
99 
100 	sieve_opr_stringlist_emit_start
101 		(cgenv->sblock, sieve_ast_strlist_count(strlist), &list_context);
102 
103 	stritem = sieve_ast_strlist_first(strlist);
104 	while ( stritem != NULL ) {
105 		if ( !sieve_generate_argument(cgenv, stritem, cmd) )
106 			return FALSE;
107 
108 		stritem = sieve_ast_strlist_next(stritem);
109 	}
110 
111 	sieve_opr_stringlist_emit_end(cgenv->sblock, list_context);
112 
113 	return TRUE;
114 }
115 
arg_string_list_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd)116 static bool arg_string_list_generate
117 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
118 	struct sieve_command *cmd)
119 {
120 	if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
121 		return ( sieve_generate_argument(cgenv, arg, cmd) );
122 
123 	} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
124 		bool result = TRUE;
125 
126 		if ( sieve_ast_strlist_count(arg) == 1 )
127 			return ( sieve_generate_argument
128 				(cgenv, sieve_ast_strlist_first(arg), cmd) );
129 		else {
130 			T_BEGIN {
131 				result=emit_string_list_operand(cgenv, arg, cmd);
132 			} T_END;
133 		}
134 
135 		return result;
136 	}
137 
138 	return FALSE;
139 }
140 
141 /*
142  * Abstract arguments
143  *
144  *   (Generated by processing and not by parsing the grammar)
145  */
146 
147 /* Catenated string */
148 
149 struct sieve_arg_catenated_string {
150 	struct sieve_ast_arg_list *str_parts;
151 };
152 
sieve_arg_catenated_string_create(struct sieve_ast_argument * orig_arg)153 struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
154 (struct sieve_ast_argument *orig_arg)
155 {
156 	pool_t pool = sieve_ast_pool(orig_arg->ast);
157 	struct sieve_ast_arg_list *arglist;
158 	struct sieve_arg_catenated_string *catstr;
159 
160 	arglist = sieve_ast_arg_list_create(pool);
161 
162 	catstr = p_new(pool, struct sieve_arg_catenated_string, 1);
163 	catstr->str_parts = arglist;
164 	(orig_arg)->argument->data = (void *) catstr;
165 
166 	return catstr;
167 }
168 
sieve_arg_catenated_string_add_element(struct sieve_arg_catenated_string * catstr,struct sieve_ast_argument * element)169 void sieve_arg_catenated_string_add_element
170 (struct sieve_arg_catenated_string *catstr,
171 	struct sieve_ast_argument *element)
172 {
173 	sieve_ast_arg_list_add(catstr->str_parts, element);
174 }
175 
176 #define _cat_string_first(catstr) __AST_LIST_FIRST((catstr)->str_parts)
177 #define _cat_string_count(catstr) __AST_LIST_COUNT((catstr)->str_parts)
178 #define _cat_string_next(item) __AST_LIST_NEXT(item)
179 
sieve_arg_catenated_string_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd)180 bool sieve_arg_catenated_string_generate
181 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
182 	struct sieve_command *cmd)
183 {
184 	struct sieve_arg_catenated_string *catstr =
185 		(struct sieve_arg_catenated_string *) arg->argument->data;
186 	struct sieve_ast_argument *strpart;
187 
188 	if ( _cat_string_count(catstr) == 1 )
189 		sieve_generate_argument(cgenv, _cat_string_first(catstr), cmd);
190 	else {
191 		sieve_opr_catenated_string_emit(cgenv->sblock, _cat_string_count(catstr));
192 
193 		strpart = _cat_string_first(catstr);
194 		while ( strpart != NULL ) {
195 			if ( !sieve_generate_argument(cgenv, strpart, cmd) )
196 				return FALSE;
197 
198 			strpart = _cat_string_next(strpart);
199 		}
200 	}
201 
202 	return TRUE;
203 }
204 
205 /*
206  * Argument creation
207  */
208 
sieve_argument_create(struct sieve_ast * ast,const struct sieve_argument_def * def,const struct sieve_extension * ext,int id_code)209 struct sieve_argument *sieve_argument_create
210 (struct sieve_ast *ast, const struct sieve_argument_def *def,
211 	const struct sieve_extension *ext, int id_code)
212 {
213 	struct sieve_argument *arg;
214 	pool_t pool;
215 
216 	pool = sieve_ast_pool(ast);
217 	arg = p_new(pool, struct sieve_argument, 1);
218 	arg->def = def;
219 	arg->ext = ext;
220 	arg->id_code = id_code;
221 
222 	return arg;
223 }
224 
225 /*
226  * Core tests and commands
227  */
228 
229 const struct sieve_command_def *sieve_core_tests[] = {
230 	&tst_false, &tst_true,
231 	&tst_not, &tst_anyof, &tst_allof,
232 	&tst_address, &tst_header, &tst_exists, &tst_size
233 };
234 
235 const unsigned int sieve_core_tests_count = N_ELEMENTS(sieve_core_tests);
236 
237 const struct sieve_command_def *sieve_core_commands[] = {
238 	&cmd_require,
239 	&cmd_stop, &cmd_if, &cmd_elsif, &cmd_else,
240 	&cmd_keep, &cmd_discard, &cmd_redirect
241 };
242 
243 const unsigned int sieve_core_commands_count = N_ELEMENTS(sieve_core_commands);
244 
245 /*
246  * Command context
247  */
248 
sieve_command_prev(struct sieve_command * cmd)249 struct sieve_command *sieve_command_prev
250 (struct sieve_command *cmd)
251 {
252 	struct sieve_ast_node *node = sieve_ast_node_prev(cmd->ast_node);
253 
254 	if ( node != NULL ) {
255 		return node->command;
256 	}
257 
258 	return NULL;
259 }
260 
sieve_command_parent(struct sieve_command * cmd)261 struct sieve_command *sieve_command_parent
262 (struct sieve_command *cmd)
263 {
264 	struct sieve_ast_node *node = sieve_ast_node_parent(cmd->ast_node);
265 
266 	return ( node != NULL ? node->command : NULL );
267 }
268 
sieve_command_create(struct sieve_ast_node * cmd_node,const struct sieve_extension * ext,const struct sieve_command_def * cmd_def,struct sieve_command_registration * cmd_reg)269 struct sieve_command *sieve_command_create
270 (struct sieve_ast_node *cmd_node, const struct sieve_extension *ext,
271 	const struct sieve_command_def *cmd_def,
272 	struct sieve_command_registration *cmd_reg)
273 {
274 	struct sieve_command *cmd;
275 
276 	cmd = p_new(sieve_ast_node_pool(cmd_node), struct sieve_command, 1);
277 
278 	cmd->ast_node = cmd_node;
279 	cmd->def = cmd_def;
280 	cmd->ext = ext;
281 	cmd->reg = cmd_reg;
282 
283 	cmd->block_exit_command = NULL;
284 
285 	return cmd;
286 }
287 
sieve_command_def_type_name(const struct sieve_command_def * cmd_def)288 const char *sieve_command_def_type_name
289 (const struct sieve_command_def *cmd_def)
290 {
291 	switch ( cmd_def->type ) {
292 	case SCT_NONE: return "command of unspecified type (bug)";
293 	case SCT_TEST: return "test";
294 	case SCT_COMMAND: return "command";
295 	case SCT_HYBRID: return "command or test";
296 	default:
297 		break;
298 	}
299 	return "??COMMAND-TYPE??";
300 }
301 
sieve_command_type_name(const struct sieve_command * cmd)302 const char *sieve_command_type_name
303 	(const struct sieve_command *cmd)
304 {
305 	switch ( cmd->def->type ) {
306 	case SCT_NONE: return "command of unspecified type (bug)";
307 	case SCT_TEST: return "test";
308 	case SCT_COMMAND: return "command";
309 	case SCT_HYBRID:
310 		if ( cmd->ast_node->type == SAT_TEST )
311 			return "test";
312 		return "command";
313 	default:
314 		break;
315 	}
316 	return "??COMMAND-TYPE??";
317 }
318 
sieve_command_add_dynamic_tag(struct sieve_command * cmd,const struct sieve_extension * ext,const struct sieve_argument_def * tag,int id_code)319 struct sieve_ast_argument *sieve_command_add_dynamic_tag
320 (struct sieve_command *cmd, const struct sieve_extension *ext,
321 	const struct sieve_argument_def *tag, int id_code)
322 {
323 	struct sieve_ast_argument *arg;
324 
325 	if ( cmd->first_positional != NULL )
326 		arg = sieve_ast_argument_tag_insert
327 			(cmd->first_positional, tag->identifier, cmd->ast_node->source_line);
328 	else
329 		arg = sieve_ast_argument_tag_create
330 			(cmd->ast_node, tag->identifier, cmd->ast_node->source_line);
331 
332 	arg->argument = sieve_argument_create(cmd->ast_node->ast, tag, ext, id_code);
333 
334 	return arg;
335 }
336 
sieve_command_find_argument(struct sieve_command * cmd,const struct sieve_argument_def * arg_def)337 struct sieve_ast_argument *sieve_command_find_argument
338 (struct sieve_command *cmd, const struct sieve_argument_def *arg_def)
339 {
340 	struct sieve_ast_argument *arg = sieve_ast_argument_first(cmd->ast_node);
341 
342 	/* Visit tagged and optional arguments */
343 	while ( arg != NULL ) {
344 		if ( arg->argument != NULL && arg->argument->def == arg_def )
345 			return arg;
346 
347 		arg = sieve_ast_argument_next(arg);
348 	}
349 
350 	return arg;
351 }
352 
353 /* Use this function with caution. The command commits to exiting the block.
354  * When it for some reason does not, the interpretation will break later on,
355  * because exiting jumps are not generated when they would otherwise be
356  * necessary.
357  */
sieve_command_exit_block_unconditionally(struct sieve_command * cmd)358 void sieve_command_exit_block_unconditionally
359 	(struct sieve_command *cmd)
360 {
361 	struct sieve_command *parent = sieve_command_parent(cmd);
362 
363 	/* Only the first unconditional exit is of importance */
364 	if ( parent != NULL && parent->block_exit_command == NULL )
365 		parent->block_exit_command = cmd;
366 }
367 
sieve_command_block_exits_unconditionally(struct sieve_command * cmd)368 bool sieve_command_block_exits_unconditionally
369 	(struct sieve_command *cmd)
370 {
371 	return ( cmd->block_exit_command != NULL );
372 }
373 
374 /*
375  * Command utility functions
376  */
377 
378 /* NOTE: this may be moved */
379 
_verify_header_name_item(void * context,struct sieve_ast_argument * header)380 static int _verify_header_name_item
381 (void *context, struct sieve_ast_argument *header)
382 {
383 	struct sieve_validator *valdtr = (struct sieve_validator *) context;
384 	string_t *name = sieve_ast_argument_str(header);
385 
386 	if ( sieve_argument_is_string_literal(header) &&
387 		!rfc2822_header_field_name_verify(str_c(name), str_len(name)) ) {
388 		sieve_argument_validate_warning
389 			(valdtr, header, "specified header field name '%s' is invalid",
390 				str_sanitize(str_c(name), 80));
391 
392 		return 0;
393 	}
394 
395 	return 1;
396 }
397 
sieve_command_verify_headers_argument(struct sieve_validator * valdtr,struct sieve_ast_argument * headers)398 bool sieve_command_verify_headers_argument
399 (struct sieve_validator *valdtr, struct sieve_ast_argument *headers)
400 {
401 	return ( sieve_ast_stringlist_map
402 		(&headers, (void *) valdtr, _verify_header_name_item) >= 0 );
403 }
404