static var_t * exp_not(var_t *v) { var_t *r; // NULL returns NULL if (v == NULL) { return EXP_EMPTY; } if (v->v_data == NULL) { return EXP_EMPTY; } if (var_true(v)) { r = EXP_FALSE; } else { r = EXP_TRUE; } exp_free(v); return r; }
/** * connector() -- make a node for a connector or dictionary word. * * Assumes the current token is a connector or dictionary word. */ static Exp * connector(Dictionary dict) { Exp * n; Dict_node *dn, *dn_head; int i; i = strlen(dict->token) - 1; /* this must be + or - if a connector */ if ((dict->token[i] != '+') && (dict->token[i] != '-')) { /* If we are here, token is a word */ dn_head = abridged_lookup_list(dict, dict->token); dn = dn_head; while ((dn != NULL) && (strcmp(dn->string, dict->token) != 0)) { dn = dn->right; } if (dn == NULL) { free_lookup_list(dn_head); dict_error(dict, "\nPerhaps missing + or - in a connector.\n" "Or perhaps you forgot the suffix on a word.\n" "Or perhaps a word is used before it is defined.\n"); return NULL; } n = make_unary_node(dict, dn->exp); free_lookup_list(dn_head); } else { /* If we are here, token is a connector */ if (!check_connector(dict, dict->token)) { return NULL; } n = Exp_create(dict); n->dir = dict->token[i]; dict->token[i] = '\0'; /* get rid of the + or - */ if (dict->token[0] == '@') { n->u.string = string_set_add(dict->token+1, dict->string_set); n->multi = TRUE; } else { n->u.string = string_set_add(dict->token, dict->string_set); n->multi = FALSE; } n->type = CONNECTOR_type; n->cost = 0.0f; } if (!link_advance(dict)) { exp_free(n); return NULL; } return n; }
static void free_Exp_list(Exp * e) { Exp * e1; for (; e != NULL; e = e1) { e1 = e->next; if (e->type != CONNECTOR_type) { free_Elist(e->u.l); } exp_free(e); } }
var_t * exp_is_null(var_t *v) { var_t *result = &exp_false; if (v == NULL) { result = &exp_true; } else if (v->v_data == NULL) { result = &exp_true; } exp_free(v); return result; }
int exp_is_true(exp_t *exp, var_t *mailspec) { var_t *v; int r; if (exp == NULL) { return 1; } v = exp_eval(exp, mailspec); if (v == NULL) { log_notice("exp_is_true: evaluation failed"); return -1; } r = var_true(v); exp_free(v); return r; }
static var_t * exp_eval_ternary_condition(exp_t *exp, var_t *mailspec) { exp_ternary_condition_t *etc = exp->ex_data; var_t *v = NULL; int result; v = exp_eval(etc->etc_condition, mailspec); if (v == NULL) { log_error("exp_eval_ternary_condition: evaluation failed"); return NULL; } result = var_true(v); exp_free(v); if (result) { return exp_eval(etc->etc_true, mailspec); } return exp_eval(etc->etc_false, mailspec); }
static var_t * exp_bool(var_t *mailspec, int op, exp_t *left_exp, exp_t *right_exp) { int known_value, left_known, right_known, result; int left_true = 0; int right_true = 0; var_t *left = NULL; var_t *right = NULL; if (op != OR && op != AND) { log_error("exp_bool: bad operation"); return NULL; } if (left_exp == NULL || right_exp == NULL) { log_error("exp_bool: operand is NULL"); return NULL; } // Evaluate left operand left = exp_eval(left_exp, mailspec); if (left == NULL) { log_error("exp_bool: exp_eval for lefthand operator failed"); return NULL; } left_known = left->v_data != NULL; if (left_known) { left_true = var_true(left); } // Short-Circuit Operator (like Perl) if (op == OR && left_known && left_true) { return left; } exp_free(left); // AND operation with left value known and false. if (op == AND && left_known && !left_true) { return &exp_false; } // Evaluate right operand right = exp_eval(right_exp, mailspec); if (right == NULL) { log_error("exp_bool: exp_eval for righthand operator failed"); return NULL; } right_known = right->v_data != NULL; if (right_known) { right_true = var_true(right); } // Short-Circuit Operator (like Perl) if (op == OR && !left_true) { return right; } exp_free(right); // Both sides are unknown if (!left_known && !right_known) { return &exp_empty; } // One side is unknown if (!left_known || !right_known) { known_value = left_known ? left_true: right_true; if (op == AND && !known_value) { return &exp_false; } // This case should be handled by the shortcut logic above! if (op == OR && known_value) { log_error("exp_bool: logic error"); return NULL; } return &exp_empty; } // Both sides are known if (op == AND) { result = left_true && right_true; } else { result = left_true || right_true; } if (result) { return &exp_true; } return &exp_false; }
static var_t * exp_eval_function(exp_t *exp, var_t *mailspec) { exp_function_t *ef = exp->ex_data; acl_function_t *af; var_t *args = NULL; ll_t *single = NULL; var_t *v = NULL; af = acl_function_lookup(ef->ef_name); if (af == NULL) { log_error("exp_eval_function: unknown function \"%s\"", ef->ef_name); goto error; } /* * Function has arguments */ if (ef->ef_args) { args = exp_eval(ef->ef_args, mailspec); if (args == NULL) { log_error("exp_eval_function: exp_eval failed"); goto error; } /* * Convert single argument into list. */ if (args->v_type != VT_LIST) { single = ll_create(); if (single == NULL) { log_error("exp_eval_function: ll_create failed"); goto error; } if (LL_INSERT(single, args) == -1) { log_error("exp_eval_function: LL_INSERT failed"); goto error; } } } else { /* * Function has no arguments -> empty list */ single = ll_create(); if (single == NULL) { log_error("exp_eval_function: ll_create failed"); goto error; } } if (af->af_type == AF_SIMPLE) { v = exp_eval_function_simple(ef->ef_name, af, single ? single : args->v_data); } else { v = exp_eval_function_complex(ef->ef_name, af, single ? single : args->v_data); } if (v == NULL) { log_error("exp_eval_function: function \"%s\" failed", ef->ef_name); goto error; } error: if (single) { ll_delete(single, NULL); } if (args) { exp_free(args); } return v; }
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; }