/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file */ #include "lib.h" #include "compat.h" #include "mempool.h" #include "hash.h" #include "array.h" #include "str-sanitize.h" #include "sieve-extensions.h" #include "sieve-code.h" #include "sieve-address.h" #include "sieve-commands.h" #include "sieve-binary.h" #include "sieve-comparators.h" #include "sieve-match-types.h" #include "sieve-validator.h" #include "sieve-generator.h" #include "sieve-interpreter.h" #include "sieve-dump.h" #include "sieve-match.h" #include "sieve-address-parts.h" #include /* * Default address parts */ const struct sieve_address_part_def *sieve_core_address_parts[] = { &all_address_part, &local_address_part, &domain_address_part }; const unsigned int sieve_core_address_parts_count = N_ELEMENTS(sieve_core_address_parts); /* * Address-part 'extension' */ static bool addrp_validator_load (const struct sieve_extension *ext, struct sieve_validator *valdtr); const struct sieve_extension_def address_part_extension = { .name = "@address-parts", .validator_load = addrp_validator_load }; /* * Validator context: * name-based address-part registry. */ static struct sieve_validator_object_registry *_get_object_registry (struct sieve_validator *valdtr) { struct sieve_instance *svinst; const struct sieve_extension *adrp_ext; svinst = sieve_validator_svinst(valdtr); adrp_ext = sieve_get_address_part_extension(svinst); return sieve_validator_object_registry_get(valdtr, adrp_ext); } void sieve_address_part_register (struct sieve_validator *valdtr, const struct sieve_extension *ext, const struct sieve_address_part_def *addrp_def) { struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); sieve_validator_object_registry_add(regs, ext, &addrp_def->obj_def); } static bool sieve_address_part_exists (struct sieve_validator *valdtr, const char *identifier) { struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); return sieve_validator_object_registry_find(regs, identifier, NULL); } static const struct sieve_address_part *sieve_address_part_create_instance (struct sieve_validator *valdtr, struct sieve_command *cmd, const char *identifier) { struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); struct sieve_object object; struct sieve_address_part *addrp; if ( !sieve_validator_object_registry_find(regs, identifier, &object) ) return NULL; addrp = p_new(sieve_command_pool(cmd), struct sieve_address_part, 1); addrp->object = object; addrp->def = (const struct sieve_address_part_def *) object.def; return addrp; } static bool addrp_validator_load (const struct sieve_extension *ext, struct sieve_validator *valdtr) { struct sieve_validator_object_registry *regs = sieve_validator_object_registry_init(valdtr, ext); unsigned int i; /* Register core address-parts */ for ( i = 0; i < sieve_core_address_parts_count; i++ ) { sieve_validator_object_registry_add (regs, NULL, &(sieve_core_address_parts[i]->obj_def)); } return TRUE; } void sieve_address_parts_link_tags (struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg, int id_code) { struct sieve_instance *svinst; const struct sieve_extension *adrp_ext; svinst = sieve_validator_svinst(valdtr); adrp_ext = sieve_get_address_part_extension(svinst); sieve_validator_register_tag (valdtr, cmd_reg, adrp_ext, &address_part_tag, id_code); } /* * Address-part tagged argument */ /* Forward declarations */ static bool tag_address_part_is_instance_of (struct sieve_validator *valdtr, struct sieve_command *cmd, const struct sieve_extension *ext, const char *identifier, void **data); static bool tag_address_part_validate (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, struct sieve_command *cmd); static bool tag_address_part_generate (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, struct sieve_command *cmd); /* Argument object */ const struct sieve_argument_def address_part_tag = { .identifier = "ADDRESS-PART", .is_instance_of = tag_address_part_is_instance_of, .validate = tag_address_part_validate, .generate = tag_address_part_generate }; /* Argument implementation */ static bool tag_address_part_is_instance_of (struct sieve_validator *valdtr, struct sieve_command *cmd, const struct sieve_extension *ext ATTR_UNUSED, const char *identifier, void **data) { const struct sieve_address_part *addrp; if ( data == NULL ) return sieve_address_part_exists(valdtr, identifier); if ( (addrp=sieve_address_part_create_instance (valdtr, cmd, identifier)) == NULL ) return FALSE; *data = (void *) addrp; return TRUE; } static bool tag_address_part_validate (struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg, struct sieve_command *cmd ATTR_UNUSED) { /* NOTE: Currenly trivial, but might need to allow for further validation for * future extensions. */ /* Syntax: * ":localpart" / ":domain" / ":all" (subject to extension) */ /* Skip tag */ *arg = sieve_ast_argument_next(*arg); return TRUE; } static bool tag_address_part_generate (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, struct sieve_command *cmd ATTR_UNUSED) { struct sieve_address_part *addrp = (struct sieve_address_part *) arg->argument->data; sieve_opr_address_part_emit(cgenv->sblock, addrp); return TRUE; } /* * Address-part operand */ const struct sieve_operand_class sieve_address_part_operand_class = { "address part" }; static const struct sieve_extension_objects core_address_parts = SIEVE_EXT_DEFINE_MATCH_TYPES(sieve_core_address_parts); const struct sieve_operand_def address_part_operand = { .name = "address-part", .code = SIEVE_OPERAND_ADDRESS_PART, .class = &sieve_address_part_operand_class, .interface = &core_address_parts }; /* * Address-part string list */ static int sieve_address_part_stringlist_next_item (struct sieve_stringlist *_strlist, string_t **str_r); static void sieve_address_part_stringlist_reset (struct sieve_stringlist *_strlist); static int sieve_address_part_stringlist_get_length (struct sieve_stringlist *_strlist); static void sieve_address_part_stringlist_set_trace (struct sieve_stringlist *_strlist, bool trace); struct sieve_address_part_stringlist { struct sieve_stringlist strlist; const struct sieve_address_part *addrp; struct sieve_address_list *addresses; }; struct sieve_stringlist *sieve_address_part_stringlist_create (const struct sieve_runtime_env *renv, const struct sieve_address_part *addrp, struct sieve_address_list *addresses) { struct sieve_address_part_stringlist *strlist; strlist = t_new(struct sieve_address_part_stringlist, 1); strlist->strlist.runenv = renv; strlist->strlist.next_item = sieve_address_part_stringlist_next_item; strlist->strlist.reset = sieve_address_part_stringlist_reset; strlist->strlist.get_length = sieve_address_part_stringlist_get_length; strlist->strlist.set_trace = sieve_address_part_stringlist_set_trace; strlist->addrp = addrp; strlist->addresses = addresses; return &strlist->strlist; } static int sieve_address_part_stringlist_next_item (struct sieve_stringlist *_strlist, string_t **str_r) { struct sieve_address_part_stringlist *strlist = (struct sieve_address_part_stringlist *)_strlist; struct smtp_address item; string_t *item_unparsed; int ret; *str_r = NULL; while ( *str_r == NULL ) { if ( (ret=sieve_address_list_next_item (strlist->addresses, &item, &item_unparsed)) <= 0 ) return ret; if ( item.localpart == NULL ) { if ( item_unparsed != NULL ) { if ( _strlist->trace ) { sieve_runtime_trace(_strlist->runenv, 0, "extracting `%s' part from non-address value `%s'", sieve_address_part_name(strlist->addrp), str_sanitize(str_c(item_unparsed), 80)); } if ( str_len(item_unparsed) == 0 || sieve_address_part_is(strlist->addrp, all_address_part) ) *str_r = item_unparsed; } } else { const struct sieve_address_part *addrp = strlist->addrp; const char *part = NULL; if ( _strlist->trace ) { sieve_runtime_trace(_strlist->runenv, 0, "extracting `%s' part from address %s", sieve_address_part_name(strlist->addrp), smtp_address_encode_path(&item)); } if ( addrp->def != NULL && addrp->def->extract_from != NULL ) part = addrp->def->extract_from(addrp, &item); if ( part != NULL ) *str_r = t_str_new_const(part, strlen(part)); } } return 1; } static void sieve_address_part_stringlist_reset (struct sieve_stringlist *_strlist) { struct sieve_address_part_stringlist *strlist = (struct sieve_address_part_stringlist *)_strlist; sieve_address_list_reset(strlist->addresses); } static int sieve_address_part_stringlist_get_length (struct sieve_stringlist *_strlist) { struct sieve_address_part_stringlist *strlist = (struct sieve_address_part_stringlist *)_strlist; return sieve_address_list_get_length(strlist->addresses); } static void sieve_address_part_stringlist_set_trace (struct sieve_stringlist *_strlist, bool trace) { struct sieve_address_part_stringlist *strlist = (struct sieve_address_part_stringlist *)_strlist; sieve_address_list_set_trace(strlist->addresses, trace); } /* * Default ADDRESS-PART, MATCH-TYPE, COMPARATOR access */ int sieve_addrmatch_opr_optional_dump (const struct sieve_dumptime_env *denv, sieve_size_t *address, signed int *opt_code) { signed int _opt_code = 0; bool final = FALSE, opok = TRUE; if ( opt_code == NULL ) { opt_code = &_opt_code; final = TRUE; } while ( opok ) { int opt; if ( (opt=sieve_opr_optional_dump(denv, address, opt_code)) <= 0 ) return opt; switch ( *opt_code ) { case SIEVE_MATCH_OPT_COMPARATOR: opok = sieve_opr_comparator_dump(denv, address); break; case SIEVE_MATCH_OPT_MATCH_TYPE: opok = sieve_opr_match_type_dump(denv, address); break; case SIEVE_AM_OPT_ADDRESS_PART: opok = sieve_opr_address_part_dump(denv, address); break; default: return ( final ? -1 : 1 ); } } return -1; } int sieve_addrmatch_opr_optional_read (const struct sieve_runtime_env *renv, sieve_size_t *address, signed int *opt_code, int *exec_status, struct sieve_address_part *addrp, struct sieve_match_type *mtch, struct sieve_comparator *cmp) { signed int _opt_code = 0; bool final = FALSE; int status = SIEVE_EXEC_OK; if ( opt_code == NULL ) { opt_code = &_opt_code; final = TRUE; } if ( exec_status != NULL ) *exec_status = SIEVE_EXEC_OK; while ( status == SIEVE_EXEC_OK ) { int opt; if ( (opt=sieve_opr_optional_read(renv, address, opt_code)) <= 0 ){ if ( opt < 0 && exec_status != NULL ) *exec_status = SIEVE_EXEC_BIN_CORRUPT; return opt; } switch ( *opt_code ) { case SIEVE_MATCH_OPT_COMPARATOR: if (cmp == NULL) { sieve_runtime_trace_error(renv, "unexpected comparator operand"); if ( exec_status != NULL ) *exec_status = SIEVE_EXEC_BIN_CORRUPT; return -1; } status = sieve_opr_comparator_read(renv, address, cmp); break; case SIEVE_MATCH_OPT_MATCH_TYPE: if (mtch == NULL) { sieve_runtime_trace_error(renv, "unexpected match-type operand"); if ( exec_status != NULL ) *exec_status = SIEVE_EXEC_BIN_CORRUPT; return -1; } status = sieve_opr_match_type_read(renv, address, mtch); break; case SIEVE_AM_OPT_ADDRESS_PART: if (addrp == NULL) { sieve_runtime_trace_error(renv, "unexpected address-part operand"); if ( exec_status != NULL ) *exec_status = SIEVE_EXEC_BIN_CORRUPT; return -1; } status = sieve_opr_address_part_read(renv, address, addrp); break; default: if ( final ) { sieve_runtime_trace_error(renv, "invalid optional operand"); if ( exec_status != NULL ) *exec_status = SIEVE_EXEC_BIN_CORRUPT; return -1; } return 1; } } if ( exec_status != NULL ) *exec_status = status; return -1; } /* * Core address-part modifiers */ static const char *addrp_all_extract_from (const struct sieve_address_part *addrp ATTR_UNUSED, const struct smtp_address *address) { if ( address->localpart == NULL ) return NULL; return smtp_address_encode(address); } static const char *addrp_domain_extract_from (const struct sieve_address_part *addrp ATTR_UNUSED, const struct smtp_address *address) { return address->domain; } static const char *addrp_localpart_extract_from (const struct sieve_address_part *addrp ATTR_UNUSED, const struct smtp_address *address) { return address->localpart; } const struct sieve_address_part_def all_address_part = { SIEVE_OBJECT("all", &address_part_operand, SIEVE_ADDRESS_PART_ALL), .extract_from = addrp_all_extract_from }; const struct sieve_address_part_def local_address_part = { SIEVE_OBJECT("localpart", &address_part_operand, SIEVE_ADDRESS_PART_LOCAL), .extract_from = addrp_localpart_extract_from }; const struct sieve_address_part_def domain_address_part = { SIEVE_OBJECT("domain", &address_part_operand, SIEVE_ADDRESS_PART_DOMAIN), .extract_from = addrp_domain_extract_from };