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