static var_t * exp_eval_function_simple(char *name, acl_function_t *af, ll_t *args) { ll_t garbage; ll_entry_t *pos; void **argv = NULL; var_t *v = NULL; int argc; int size; int i; var_t *arg; /* * Initialize garbage */ ll_init(&garbage); /* * Check argc */ argc = args->ll_size; if (argc != af->af_argc) { log_error("exp_eval_function_simple: function \"%s\" requires " "%d arguments", name, af->af_argc); return NULL; } size = (argc + 1) * sizeof (void *); argv = (void **) malloc(size); if (argv == NULL) { log_sys_error("exp_eval_function_simple: malloc"); return NULL; } memset(argv, 0, size); /* * Prepare argv */ pos = LL_START(args); for (i = 0; (arg = ll_next(args, &pos)); ++i) { if (af->af_types[i] == arg->v_type) { argv[i] = arg->v_data; continue; } /* * Type casting required. Don't care about the remains of arg * (freed with args!). */ arg = var_cast_copy(af->af_types[i], arg); if (arg == NULL) { log_error("exp_eval_function_simple: var_cast_copy " "failed"); goto error; } /* * Need to free copy later */ if (LL_INSERT(&garbage, arg) == -1) { log_error("exp_eval_function_simlpe: LL_INSERT " "failed"); var_delete(arg); goto error; } argv[i] = arg->v_data; } v = af->af_callback.fc_simple(argc, argv); error: ll_clear(&garbage, (ll_delete_t) var_delete); if (argv) { free(argv); } return v; }
static var_t * exp_eval_regex(int op, var_t *left, var_t *right) { char *p; int e; char error[1024]; int flags = REG_EXTENDED | REG_NOSUB; int match; regex_t r; var_t *pattern_copy = NULL; var_t *str_copy = NULL; char *pattern; char *str; if (left == NULL || right == NULL) { return EXP_EMPTY; } if (left->v_data == NULL || right->v_data == NULL) { log_debug("exp_eval_regex: empty value"); return EXP_EMPTY; } // Make sure left is a string if (left->v_type != VT_STRING) { str_copy = var_cast_copy(VT_STRING, left); if (str_copy == NULL) { log_error("exp_eval_regex: var_cast_copy failed"); goto error; } str = str_copy->v_data; } else { str = left->v_data; } // Make sure right is a string if (right->v_type != VT_STRING) { pattern_copy = var_cast_copy(VT_STRING, right); if (pattern_copy == NULL) { log_error("exp_eval_regex: var_cast_copy failed"); goto error; } pattern = pattern_copy->v_data; } else { pattern = right->v_data; } // Test if pattern contains upper case chars flags = REG_EXTENDED | REG_NOSUB; for (p = pattern; *p; ++p) { if (isupper((int) *p)) { break; } } // If pattern is all lower perform case insensitiv matching if(*p == 0) { flags |= REG_ICASE; } e = regcomp(&r, pattern, flags); if (e) { regerror(e, &r, error, sizeof error); log_error("exp_eval_regex: regcomp: %s", error); goto error; } // Regexec returns 0 if pattern matched. match = regexec(&r, str, 0, NULL, 0); // free memory regfree(&r); if (str_copy) { var_delete(str_copy); } if (pattern_copy) { var_delete(pattern_copy); } if (op == NR) { match = !match; } if (match) { return EXP_FALSE; } return EXP_TRUE; error: if (str_copy) { var_delete(str_copy); } if (pattern_copy) { var_delete(pattern_copy); } return NULL; }
var_t * exp_eval_operation(exp_t *exp, var_t *mailspec) { var_t *left = NULL, *right = NULL, *copy; exp_operation_t *eo = exp->ex_data; var_t *result = NULL; var_type_t type; /* * Variable assigment */ if (eo->eo_operator == '=') { return exp_assign(eo->eo_operand[0], eo->eo_operand[1], mailspec); } /* * isset operator */ if (eo->eo_operator == IS_SET) { return exp_isset(mailspec, eo->eo_operand[0]); } /* * Do not load unneccessary symbols in boolean operations */ if (eo->eo_operator == AND || eo->eo_operator == OR) { result = exp_bool(mailspec, eo->eo_operator, eo->eo_operand[0], eo->eo_operand[1]); goto exit; } /* * Load left operand */ left = exp_eval(eo->eo_operand[0], mailspec); /* * ! operator */ if (eo->eo_operator == '!') { return exp_not(left); } /* * Hack: IS_NULL operator */ if (eo->eo_operator == IS_NULL) { result = exp_is_null(left); goto exit; } /* * Evaluate right operand */ if (eo->eo_operand[1]) { right = exp_eval(eo->eo_operand[1], mailspec); } switch(eo->eo_operator) { // Comparator case '<': case '>': case LE: case GE: case EQ: case NE: result = exp_compare(eo->eo_operator, left, right); goto exit; // Regex case '~': case NR: result = exp_eval_regex(eo->eo_operator, left, right); goto exit; // In case IN: result = exp_eval_in(left, right); goto exit; // Address prefix operator case '/': if (left == NULL || right == NULL) { break; } if (!(left->v_type == VT_ADDR && right->v_type == VT_INT)) { break; } result = exp_addr_prefix(left, right); goto exit; default: break; } // Math operators need left and right to be set if (left == NULL || right == NULL) { result = EXP_EMPTY; goto exit; } // Make sure we work with the same types if (left->v_type != right->v_type) { /* * The biggest type has precedence (see exp.h) * STRING > FLOAT > INT */ type = VAR_MAX_TYPE(left, right); if (type == left->v_type) { copy = var_cast_copy(type, right); } else { copy = var_cast_copy(type, left); } if (copy == NULL) { log_error("exp_eval_operation: var_cast_copy " "failed"); goto exit; } if (type == left->v_type) { exp_free(right); right = copy; right->v_flags |= VF_EXP_FREE; } else { exp_free(left); left = copy; left->v_flags |= VF_EXP_FREE; } } switch (left->v_type) { case VT_INT: result = exp_math_int(eo->eo_operator, left, right); break; case VT_FLOAT: result = exp_math_float(eo->eo_operator, left, right); break; case VT_STRING: result = exp_math_string(eo->eo_operator, left, right); break; default: log_error("exp_eval_operation: bad type"); goto exit; } exit: if (left) { exp_free(left); } if (right) { exp_free(right); } return result; }
acl_action_type_t msgmod(milter_stage_t stage, char *stagename, var_t *mailspec, void *data, int depth) { msgmod_t *mm = data; void *ctx; acl_action_type_t action = ACL_ERROR; var_t **args = NULL; int argc; int size; var_t *v, *copy; int i; exp_t *exp; ll_t *ll; ll_entry_t *pos; /* * Get milter ctx pointer */ ctx = vtable_get(mailspec, "milter_ctx"); if (ctx == NULL) { log_error("msgmod: ctx not set"); goto error; } /* * Evaluate arguments */ argc = mm->mm_args->ll_size; size = (argc + 1) * sizeof (var_t *); args = (var_t **) malloc(size); if (args == NULL) { log_sys_error("msgmod: malloc"); goto error; } memset(args, 0, size); ll = mm->mm_args; pos = LL_START(ll); for (i = 0; i < argc; ++i) { exp = ll_next(ll, &pos); if (exp == NULL) { log_die(EX_SOFTWARE, "msgmod: empty argument"); } v = exp_eval(exp, mailspec); if (v == NULL) { log_error("msgmod: exp_eval failed"); goto error; } // Cast all aruments to VT_STRING if (v->v_type != VT_STRING) { copy = var_cast_copy(VT_STRING, v); if (copy == NULL) { log_error("msgmod: var_cast_copy failed"); goto error; } exp_free(v); /* * args are freed using exp_free. Set VF_EXP_FREE to * free copy. */ copy->v_flags |= VF_EXP_FREE; v = copy; } args[i] = v; } if (mm->mm_callback(ctx, argc, args)) { log_error("msgmod: mm_callback failed"); goto error; } action = ACL_NONE; error: /* * Free args */ for (i = 0; args[i]; ++i) { exp_free(args[i]); } if (args) { free(args); } return action; }