/src/pigeonhole/src/lib-sieve/sieve-address-parts.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "compat.h" |
5 | | #include "mempool.h" |
6 | | #include "hash.h" |
7 | | #include "array.h" |
8 | | #include "str-sanitize.h" |
9 | | |
10 | | #include "sieve-extensions.h" |
11 | | #include "sieve-code.h" |
12 | | #include "sieve-address.h" |
13 | | #include "sieve-commands.h" |
14 | | #include "sieve-binary.h" |
15 | | #include "sieve-comparators.h" |
16 | | #include "sieve-match-types.h" |
17 | | #include "sieve-validator.h" |
18 | | #include "sieve-generator.h" |
19 | | #include "sieve-interpreter.h" |
20 | | #include "sieve-dump.h" |
21 | | #include "sieve-match.h" |
22 | | |
23 | | #include "sieve-address-parts.h" |
24 | | |
25 | | #include <string.h> |
26 | | |
27 | | /* |
28 | | * Default address parts |
29 | | */ |
30 | | |
31 | | const struct sieve_address_part_def *sieve_core_address_parts[] = { |
32 | | &all_address_part, &local_address_part, &domain_address_part |
33 | | }; |
34 | | |
35 | | const unsigned int sieve_core_address_parts_count = |
36 | | N_ELEMENTS(sieve_core_address_parts); |
37 | | |
38 | | /* |
39 | | * Address-part 'extension' |
40 | | */ |
41 | | |
42 | | static bool |
43 | | addrp_validator_load(const struct sieve_extension *ext, |
44 | | struct sieve_validator *valdtr); |
45 | | |
46 | | const struct sieve_extension_def address_part_extension = { |
47 | | .name = "@address-parts", |
48 | | .validator_load = addrp_validator_load |
49 | | }; |
50 | | |
51 | | /* |
52 | | * Validator context: |
53 | | * name-based address-part registry. |
54 | | */ |
55 | | |
56 | | static struct sieve_validator_object_registry * |
57 | | _get_object_registry(struct sieve_validator *valdtr) |
58 | 0 | { |
59 | 0 | struct sieve_instance *svinst; |
60 | 0 | const struct sieve_extension *adrp_ext; |
61 | |
|
62 | 0 | svinst = sieve_validator_svinst(valdtr); |
63 | 0 | adrp_ext = sieve_get_address_part_extension(svinst); |
64 | 0 | return sieve_validator_object_registry_get(valdtr, adrp_ext); |
65 | 0 | } |
66 | | |
67 | | void sieve_address_part_register( |
68 | | struct sieve_validator *valdtr, const struct sieve_extension *ext, |
69 | | const struct sieve_address_part_def *addrp_def) |
70 | 0 | { |
71 | 0 | struct sieve_validator_object_registry *regs = |
72 | 0 | _get_object_registry(valdtr); |
73 | |
|
74 | 0 | sieve_validator_object_registry_add(regs, ext, &addrp_def->obj_def); |
75 | 0 | } |
76 | | |
77 | | static bool |
78 | | sieve_address_part_exists(struct sieve_validator *valdtr, |
79 | | const char *identifier) |
80 | 0 | { |
81 | 0 | struct sieve_validator_object_registry *regs = |
82 | 0 | _get_object_registry(valdtr); |
83 | |
|
84 | 0 | return sieve_validator_object_registry_find(regs, identifier, NULL); |
85 | 0 | } |
86 | | |
87 | | static const struct sieve_address_part * |
88 | | sieve_address_part_create_instance(struct sieve_validator *valdtr, |
89 | | struct sieve_command *cmd, |
90 | | const char *identifier) |
91 | 0 | { |
92 | 0 | struct sieve_validator_object_registry *regs = |
93 | 0 | _get_object_registry(valdtr); |
94 | 0 | struct sieve_object object; |
95 | 0 | struct sieve_address_part *addrp; |
96 | |
|
97 | 0 | if (!sieve_validator_object_registry_find(regs, identifier, &object)) |
98 | 0 | return NULL; |
99 | | |
100 | 0 | addrp = p_new(sieve_command_pool(cmd), struct sieve_address_part, 1); |
101 | 0 | addrp->object = object; |
102 | 0 | addrp->def = (const struct sieve_address_part_def *) object.def; |
103 | |
|
104 | 0 | return addrp; |
105 | 0 | } |
106 | | |
107 | | static bool |
108 | | addrp_validator_load(const struct sieve_extension *ext, |
109 | | struct sieve_validator *valdtr) |
110 | 0 | { |
111 | 0 | struct sieve_validator_object_registry *regs = |
112 | 0 | sieve_validator_object_registry_init(valdtr, ext); |
113 | 0 | unsigned int i; |
114 | | |
115 | | /* Register core address-parts */ |
116 | 0 | for (i = 0; i < sieve_core_address_parts_count; i++) { |
117 | 0 | sieve_validator_object_registry_add( |
118 | 0 | regs, NULL, &(sieve_core_address_parts[i]->obj_def)); |
119 | 0 | } |
120 | |
|
121 | 0 | return TRUE; |
122 | 0 | } |
123 | | |
124 | | void sieve_address_parts_link_tags(struct sieve_validator *valdtr, |
125 | | struct sieve_command_registration *cmd_reg, |
126 | | int id_code) |
127 | 0 | { |
128 | 0 | struct sieve_instance *svinst; |
129 | 0 | const struct sieve_extension *adrp_ext; |
130 | |
|
131 | 0 | svinst = sieve_validator_svinst(valdtr); |
132 | 0 | adrp_ext = sieve_get_address_part_extension(svinst); |
133 | |
|
134 | 0 | sieve_validator_register_tag(valdtr, cmd_reg, adrp_ext, |
135 | 0 | &address_part_tag, id_code); |
136 | 0 | } |
137 | | |
138 | | /* |
139 | | * Address-part tagged argument |
140 | | */ |
141 | | |
142 | | /* Forward declarations */ |
143 | | |
144 | | static bool |
145 | | tag_address_part_is_instance_of(struct sieve_validator *valdtr, |
146 | | struct sieve_command *cmd, |
147 | | const struct sieve_extension *ext, |
148 | | const char *identifier, void **data); |
149 | | static bool |
150 | | tag_address_part_validate(struct sieve_validator *valdtr, |
151 | | struct sieve_ast_argument **arg, |
152 | | struct sieve_command *cmd); |
153 | | static bool |
154 | | tag_address_part_generate(const struct sieve_codegen_env *cgenv, |
155 | | struct sieve_ast_argument *arg, |
156 | | struct sieve_command *cmd); |
157 | | |
158 | | /* Argument object */ |
159 | | |
160 | | const struct sieve_argument_def address_part_tag = { |
161 | | .identifier = "ADDRESS-PART", |
162 | | .is_instance_of = tag_address_part_is_instance_of, |
163 | | .validate = tag_address_part_validate, |
164 | | .generate = tag_address_part_generate |
165 | | }; |
166 | | |
167 | | /* Argument implementation */ |
168 | | |
169 | | static bool |
170 | | tag_address_part_is_instance_of(struct sieve_validator *valdtr, |
171 | | struct sieve_command *cmd, |
172 | | const struct sieve_extension *ext ATTR_UNUSED, |
173 | | const char *identifier, void **data) |
174 | 0 | { |
175 | 0 | const struct sieve_address_part *addrp; |
176 | |
|
177 | 0 | if (data == NULL) |
178 | 0 | return sieve_address_part_exists(valdtr, identifier); |
179 | | |
180 | 0 | if ((addrp = sieve_address_part_create_instance( |
181 | 0 | valdtr, cmd, identifier)) == NULL) |
182 | 0 | return FALSE; |
183 | | |
184 | 0 | *data = (void *)addrp; |
185 | 0 | return TRUE; |
186 | 0 | } |
187 | | |
188 | | static bool |
189 | | tag_address_part_validate(struct sieve_validator *valdtr ATTR_UNUSED, |
190 | | struct sieve_ast_argument **arg, |
191 | | struct sieve_command *cmd ATTR_UNUSED) |
192 | 0 | { |
193 | | /* NOTE: Currenly trivial, but might need to allow for further |
194 | | validation for future extensions. |
195 | | */ |
196 | | |
197 | | /* Syntax: |
198 | | ":localpart" / ":domain" / ":all" (subject to extension) |
199 | | */ |
200 | | |
201 | | /* Skip tag */ |
202 | 0 | *arg = sieve_ast_argument_next(*arg); |
203 | |
|
204 | 0 | return TRUE; |
205 | 0 | } |
206 | | |
207 | | static bool |
208 | | tag_address_part_generate(const struct sieve_codegen_env *cgenv, |
209 | | struct sieve_ast_argument *arg, |
210 | | struct sieve_command *cmd ATTR_UNUSED) |
211 | 0 | { |
212 | 0 | struct sieve_address_part *addrp = |
213 | 0 | (struct sieve_address_part *)arg->argument->data; |
214 | |
|
215 | 0 | sieve_opr_address_part_emit(cgenv->sblock, addrp); |
216 | 0 | return TRUE; |
217 | 0 | } |
218 | | |
219 | | /* |
220 | | * Address-part operand |
221 | | */ |
222 | | |
223 | | const struct sieve_operand_class sieve_address_part_operand_class = |
224 | | { "address part" }; |
225 | | |
226 | | static const struct sieve_extension_objects core_address_parts = |
227 | | SIEVE_EXT_DEFINE_MATCH_TYPES(sieve_core_address_parts); |
228 | | |
229 | | const struct sieve_operand_def address_part_operand = { |
230 | | .name = "address-part", |
231 | | .code = SIEVE_OPERAND_ADDRESS_PART, |
232 | | .class = &sieve_address_part_operand_class, |
233 | | .interface = &core_address_parts |
234 | | }; |
235 | | |
236 | | /* |
237 | | * Address-part string list |
238 | | */ |
239 | | |
240 | | static int |
241 | | sieve_address_part_stringlist_next_item(struct sieve_stringlist *_strlist, |
242 | | string_t **str_r); |
243 | | static void |
244 | | sieve_address_part_stringlist_reset(struct sieve_stringlist *_strlist); |
245 | | static int |
246 | | sieve_address_part_stringlist_get_length(struct sieve_stringlist *_strlist); |
247 | | static void |
248 | | sieve_address_part_stringlist_set_trace(struct sieve_stringlist *_strlist, |
249 | | bool trace); |
250 | | |
251 | | struct sieve_address_part_stringlist { |
252 | | struct sieve_stringlist strlist; |
253 | | |
254 | | const struct sieve_address_part *addrp; |
255 | | struct sieve_address_list *addresses; |
256 | | }; |
257 | | |
258 | | struct sieve_stringlist * |
259 | | sieve_address_part_stringlist_create(const struct sieve_runtime_env *renv, |
260 | | const struct sieve_address_part *addrp, |
261 | | struct sieve_address_list *addresses) |
262 | 0 | { |
263 | 0 | struct sieve_address_part_stringlist *strlist; |
264 | |
|
265 | 0 | strlist = t_new(struct sieve_address_part_stringlist, 1); |
266 | 0 | strlist->strlist.runenv = renv; |
267 | 0 | strlist->strlist.next_item = sieve_address_part_stringlist_next_item; |
268 | 0 | strlist->strlist.reset = sieve_address_part_stringlist_reset; |
269 | 0 | strlist->strlist.get_length = sieve_address_part_stringlist_get_length; |
270 | 0 | strlist->strlist.set_trace = sieve_address_part_stringlist_set_trace; |
271 | |
|
272 | 0 | strlist->addrp = addrp; |
273 | 0 | strlist->addresses = addresses; |
274 | |
|
275 | 0 | return &strlist->strlist; |
276 | 0 | } |
277 | | |
278 | | static int |
279 | | sieve_address_part_stringlist_next_item(struct sieve_stringlist *_strlist, |
280 | | string_t **str_r) |
281 | 0 | { |
282 | 0 | struct sieve_address_part_stringlist *strlist = |
283 | 0 | (struct sieve_address_part_stringlist *)_strlist; |
284 | 0 | struct smtp_address item; |
285 | 0 | string_t *item_unparsed; |
286 | 0 | int ret; |
287 | |
|
288 | 0 | *str_r = NULL; |
289 | |
|
290 | 0 | while (*str_r == NULL) { |
291 | 0 | if ((ret = sieve_address_list_next_item( |
292 | 0 | strlist->addresses, &item, &item_unparsed)) <= 0) |
293 | 0 | return ret; |
294 | | |
295 | 0 | if (item.localpart == NULL) { |
296 | 0 | if (item_unparsed != NULL) { |
297 | 0 | if (_strlist->trace) { |
298 | 0 | sieve_runtime_trace( |
299 | 0 | _strlist->runenv, 0, |
300 | 0 | "extracting '%s' part from non-address value '%s'", |
301 | 0 | sieve_address_part_name(strlist->addrp), |
302 | 0 | str_sanitize(str_c(item_unparsed), 80)); |
303 | 0 | } |
304 | |
|
305 | 0 | if (str_len(item_unparsed) == 0 || |
306 | 0 | sieve_address_part_is(strlist->addrp, all_address_part)) |
307 | 0 | *str_r = item_unparsed; |
308 | 0 | } |
309 | 0 | } else { |
310 | 0 | const struct sieve_address_part *addrp = strlist->addrp; |
311 | 0 | const char *part = NULL; |
312 | |
|
313 | 0 | if (_strlist->trace) { |
314 | 0 | sieve_runtime_trace( |
315 | 0 | _strlist->runenv, 0, |
316 | 0 | "extracting '%s' part from address %s", |
317 | 0 | sieve_address_part_name(strlist->addrp), |
318 | 0 | smtp_address_encode_path(&item)); |
319 | 0 | } |
320 | |
|
321 | 0 | if (addrp->def != NULL && |
322 | 0 | addrp->def->extract_from != NULL) |
323 | 0 | part = addrp->def->extract_from(addrp, &item); |
324 | |
|
325 | 0 | if (part != NULL) |
326 | 0 | *str_r = t_str_new_const(part, strlen(part)); |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | 0 | return 1; |
331 | 0 | } |
332 | | |
333 | | static void |
334 | | sieve_address_part_stringlist_reset(struct sieve_stringlist *_strlist) |
335 | 0 | { |
336 | 0 | struct sieve_address_part_stringlist *strlist = |
337 | 0 | (struct sieve_address_part_stringlist *)_strlist; |
338 | |
|
339 | 0 | sieve_address_list_reset(strlist->addresses); |
340 | 0 | } |
341 | | |
342 | | static int |
343 | | sieve_address_part_stringlist_get_length(struct sieve_stringlist *_strlist) |
344 | 0 | { |
345 | 0 | struct sieve_address_part_stringlist *strlist = |
346 | 0 | (struct sieve_address_part_stringlist *)_strlist; |
347 | |
|
348 | 0 | return sieve_address_list_get_length(strlist->addresses); |
349 | 0 | } |
350 | | |
351 | | static void |
352 | | sieve_address_part_stringlist_set_trace(struct sieve_stringlist *_strlist, |
353 | | bool trace) |
354 | 0 | { |
355 | 0 | struct sieve_address_part_stringlist *strlist = |
356 | 0 | (struct sieve_address_part_stringlist *)_strlist; |
357 | |
|
358 | 0 | sieve_address_list_set_trace(strlist->addresses, trace); |
359 | 0 | } |
360 | | |
361 | | /* |
362 | | * Default ADDRESS-PART, MATCH-TYPE, COMPARATOR access |
363 | | */ |
364 | | |
365 | | int sieve_addrmatch_opr_optional_dump(const struct sieve_dumptime_env *denv, |
366 | | sieve_size_t *address, |
367 | | signed int *opt_code) |
368 | 0 | { |
369 | 0 | signed int _opt_code = 0; |
370 | 0 | bool final = FALSE, opok = TRUE; |
371 | |
|
372 | 0 | if (opt_code == NULL) { |
373 | 0 | opt_code = &_opt_code; |
374 | 0 | final = TRUE; |
375 | 0 | } |
376 | |
|
377 | 0 | while (opok) { |
378 | 0 | int opt; |
379 | |
|
380 | 0 | if ((opt = sieve_opr_optional_dump( |
381 | 0 | denv, address, opt_code)) <= 0) |
382 | 0 | return opt; |
383 | | |
384 | 0 | switch (*opt_code) { |
385 | 0 | case SIEVE_MATCH_OPT_COMPARATOR: |
386 | 0 | opok = sieve_opr_comparator_dump(denv, address); |
387 | 0 | break; |
388 | 0 | case SIEVE_MATCH_OPT_MATCH_TYPE: |
389 | 0 | opok = sieve_opr_match_type_dump(denv, address); |
390 | 0 | break; |
391 | 0 | case SIEVE_AM_OPT_ADDRESS_PART: |
392 | 0 | opok = sieve_opr_address_part_dump(denv, address); |
393 | 0 | break; |
394 | 0 | default: |
395 | 0 | return (final ? -1 : 1); |
396 | 0 | } |
397 | 0 | } |
398 | | |
399 | 0 | return -1; |
400 | 0 | } |
401 | | |
402 | | int sieve_addrmatch_opr_optional_read(const struct sieve_runtime_env *renv, |
403 | | sieve_size_t *address, |
404 | | signed int *opt_code, int *exec_status, |
405 | | struct sieve_address_part *addrp, |
406 | | struct sieve_match_type *mtch, |
407 | | struct sieve_comparator *cmp) |
408 | 0 | { |
409 | 0 | signed int _opt_code = 0; |
410 | 0 | bool final = FALSE; |
411 | 0 | int status = SIEVE_EXEC_OK; |
412 | |
|
413 | 0 | if (opt_code == NULL) { |
414 | 0 | opt_code = &_opt_code; |
415 | 0 | final = TRUE; |
416 | 0 | } |
417 | |
|
418 | 0 | if (exec_status != NULL) |
419 | 0 | *exec_status = SIEVE_EXEC_OK; |
420 | |
|
421 | 0 | while (status == SIEVE_EXEC_OK) { |
422 | 0 | int opt; |
423 | |
|
424 | 0 | if ((opt = sieve_opr_optional_read( |
425 | 0 | renv, address, opt_code)) <= 0){ |
426 | 0 | if (opt < 0 && exec_status != NULL) |
427 | 0 | *exec_status = SIEVE_EXEC_BIN_CORRUPT; |
428 | 0 | return opt; |
429 | 0 | } |
430 | | |
431 | 0 | switch (*opt_code) { |
432 | 0 | case SIEVE_MATCH_OPT_COMPARATOR: |
433 | 0 | if (cmp == NULL) { |
434 | 0 | sieve_runtime_trace_error( |
435 | 0 | renv, "unexpected comparator operand"); |
436 | 0 | if (exec_status != NULL) |
437 | 0 | *exec_status = SIEVE_EXEC_BIN_CORRUPT; |
438 | 0 | return -1; |
439 | 0 | } |
440 | 0 | status = sieve_opr_comparator_read(renv, address, cmp); |
441 | 0 | break; |
442 | 0 | case SIEVE_MATCH_OPT_MATCH_TYPE: |
443 | 0 | if (mtch == NULL) { |
444 | 0 | sieve_runtime_trace_error( |
445 | 0 | renv, "unexpected match-type operand"); |
446 | 0 | if (exec_status != NULL) |
447 | 0 | *exec_status = SIEVE_EXEC_BIN_CORRUPT; |
448 | 0 | return -1; |
449 | 0 | } |
450 | 0 | status = sieve_opr_match_type_read(renv, address, mtch); |
451 | 0 | break; |
452 | 0 | case SIEVE_AM_OPT_ADDRESS_PART: |
453 | 0 | if (addrp == NULL) { |
454 | 0 | sieve_runtime_trace_error( |
455 | 0 | renv, "unexpected address-part operand"); |
456 | 0 | if (exec_status != NULL) |
457 | 0 | *exec_status = SIEVE_EXEC_BIN_CORRUPT; |
458 | 0 | return -1; |
459 | 0 | } |
460 | 0 | status = sieve_opr_address_part_read( |
461 | 0 | renv, address, addrp); |
462 | 0 | break; |
463 | 0 | default: |
464 | 0 | if (final) { |
465 | 0 | sieve_runtime_trace_error( |
466 | 0 | renv, "invalid optional operand"); |
467 | 0 | if (exec_status != NULL) |
468 | 0 | *exec_status = SIEVE_EXEC_BIN_CORRUPT; |
469 | 0 | return -1; |
470 | 0 | } |
471 | 0 | return 1; |
472 | 0 | } |
473 | 0 | } |
474 | | |
475 | 0 | if (exec_status != NULL) |
476 | 0 | *exec_status = status; |
477 | 0 | return -1; |
478 | 0 | } |
479 | | |
480 | | /* |
481 | | * Core address-part modifiers |
482 | | */ |
483 | | |
484 | | static const char * |
485 | | addrp_all_extract_from(const struct sieve_address_part *addrp ATTR_UNUSED, |
486 | | const struct smtp_address *address) |
487 | 0 | { |
488 | 0 | if (address->localpart == NULL) |
489 | 0 | return NULL; |
490 | 0 | return smtp_address_encode(address); |
491 | 0 | } |
492 | | |
493 | | static const char * |
494 | | addrp_domain_extract_from(const struct sieve_address_part *addrp ATTR_UNUSED, |
495 | | const struct smtp_address *address) |
496 | 0 | { |
497 | 0 | return address->domain; |
498 | 0 | } |
499 | | |
500 | | static const char * |
501 | | addrp_localpart_extract_from(const struct sieve_address_part *addrp ATTR_UNUSED, |
502 | | const struct smtp_address *address) |
503 | 0 | { |
504 | 0 | return address->localpart; |
505 | 0 | } |
506 | | |
507 | | const struct sieve_address_part_def all_address_part = { |
508 | | SIEVE_OBJECT("all", &address_part_operand, SIEVE_ADDRESS_PART_ALL), |
509 | | .extract_from = addrp_all_extract_from |
510 | | }; |
511 | | |
512 | | const struct sieve_address_part_def local_address_part = { |
513 | | SIEVE_OBJECT("localpart", &address_part_operand, |
514 | | SIEVE_ADDRESS_PART_LOCAL), |
515 | | .extract_from = addrp_localpart_extract_from |
516 | | }; |
517 | | |
518 | | const struct sieve_address_part_def domain_address_part = { |
519 | | SIEVE_OBJECT("domain", &address_part_operand, |
520 | | SIEVE_ADDRESS_PART_DOMAIN), |
521 | | .extract_from = addrp_domain_extract_from |
522 | | }; |