static void dump_rules(ruletree_object_offset_t offs, int indent) { ruletree_fsrule_t *rule = offset_to_ruletree_fsrule_ptr(offs); const char *rule_list_link_label = "??"; if (rule_dumped[offs]) { print_indent(indent + 1); printf("[ => @ %u]\n", offs); return; } rule_dumped[offs] = 1; print_indent(indent); printf("{ Rule[%u]:\n", (unsigned)offs); if (rule->rtree_fsr_name_offs) { print_indent(indent+1); printf("name = '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_name_offs, NULL)); } if (rule->rtree_fsr_selector_type) { print_indent(indent+1); printf("IF: "); switch (rule->rtree_fsr_selector_type) { case SB2_RULETREE_FSRULE_SELECTOR_PREFIX: printf("prefix '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_selector_offs, NULL)); break; case SB2_RULETREE_FSRULE_SELECTOR_DIR: printf("dir '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_selector_offs, NULL)); break; case SB2_RULETREE_FSRULE_SELECTOR_PATH: printf("path '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_selector_offs, NULL)); break; default: printf("ERROR: Unknown selector type %d\n", rule->rtree_fsr_selector_type); break; } } if (rule->rtree_fsr_condition_type) { const char *condstr = offset_to_ruletree_string_ptr(rule->rtree_fsr_condition_offs, NULL); print_indent(indent+1); printf("CONDITIONAL: "); switch (rule->rtree_fsr_condition_type) { case SB2_RULETREE_FSRULE_CONDITION_IF_ACTIVE_EXEC_POLICY_IS: printf("if_active_exec_policy_is '%s'\n", condstr); break; case SB2_RULETREE_FSRULE_CONDITION_IF_REDIRECT_IGNORE_IS_ACTIVE: printf("if_redirect_ignore_is_active '%s'\n", condstr); break; case SB2_RULETREE_FSRULE_CONDITION_IF_REDIRECT_FORCE_IS_ACTIVE: printf("if_redirect_force_is_active '%s'\n", condstr); break; case SB2_RULETREE_FSRULE_CONDITION_IF_ENV_VAR_IS_NOT_EMPTY: printf("if_env_var_is_not_empty '%s'\n", condstr); break; case SB2_RULETREE_FSRULE_CONDITION_IF_ENV_VAR_IS_EMPTY: printf("if_env_var_is_empty '%s'\n", condstr); break; default: printf("ERROR: Unknown condition type %d\n", rule->rtree_fsr_condition_type); break; } } if (rule->rtree_fsr_func_class) { print_indent(indent+1); printf("IF_CLASS: 0x%X ( ", rule->rtree_fsr_func_class); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_OPEN) printf("open "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_STAT) printf("stat "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_EXEC) printf("exec "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_SOCKADDR) printf("sockaddr "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_FTSOPEN) printf("ftsopen "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_GLOB) printf("glob "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_GETCWD) printf("getcwd "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_REALPATH) printf("realpath "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_L10N) printf("l10n "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_MKNOD) printf("mknod "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_RENAME) printf("rename "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_SYMLINK) printf("symlink "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_CREAT) printf("creat "); if (rule->rtree_fsr_func_class & SB2_INTERFACE_CLASS_PROC_FS_OP) printf("proc_fs_op "); printf(")\n"); } if (rule->rtree_fsr_binary_name) { const char *bin_name = offset_to_ruletree_string_ptr(rule->rtree_fsr_binary_name, NULL); print_indent(indent+1); printf("BINARY_NAME: '%s'\n", bin_name); } if (rule->rtree_fsr_exec_policy_name) { const char *ep_name = offset_to_ruletree_string_ptr(rule->rtree_fsr_exec_policy_name, NULL); print_indent(indent+1); printf("EXEC_POLICY_NAME: '%s'\n", ep_name); } print_indent(indent+1); printf("ACTION: "); switch (rule->rtree_fsr_action_type) { case SB2_RULETREE_FSRULE_ACTION_FALLBACK_TO_OLD_MAPPING_ENGINE: printf("FALLBACK_TO_OLD_MAPPING_ENGINE\n"); break; case SB2_RULETREE_FSRULE_ACTION_PROCFS: printf("sb2_procfs_mapper\n"); break; case SB2_RULETREE_FSRULE_ACTION_UNION_DIR: printf("union_dir => rule->rtree_fsr_rule_list_link\n"); rule_list_link_label = "union_dir"; break; case SB2_RULETREE_FSRULE_ACTION_USE_ORIG_PATH: printf("use_orig_path\n"); break; case SB2_RULETREE_FSRULE_ACTION_FORCE_ORIG_PATH: printf("force_orig_path\n"); break; case SB2_RULETREE_FSRULE_ACTION_REPLACE_BY: printf("replace_by '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; case SB2_RULETREE_FSRULE_ACTION_SET_PATH: printf("set_path '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; case SB2_RULETREE_FSRULE_ACTION_MAP_TO: printf("map_to '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; case SB2_RULETREE_FSRULE_ACTION_REPLACE_BY_VALUE_OF_ENV_VAR: printf("replace_by_value_of_env_var '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; case SB2_RULETREE_FSRULE_ACTION_MAP_TO_VALUE_OF_ENV_VAR: printf("map_to_value_of_env_var '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; case SB2_RULETREE_FSRULE_ACTION_CONDITIONAL_ACTIONS: printf("actions => %d\n", rule->rtree_fsr_rule_list_link); rule_list_link_label = "actions"; break; case SB2_RULETREE_FSRULE_ACTION_SUBTREE: printf("subtree => %d\n", rule->rtree_fsr_rule_list_link); rule_list_link_label = "rules"; break; case SB2_RULETREE_FSRULE_ACTION_IF_EXISTS_THEN_MAP_TO: printf("if_exists_then_map_to '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; case SB2_RULETREE_FSRULE_ACTION_IF_EXISTS_THEN_REPLACE_BY: printf("if_exists_then_replace_by '%s'\n", offset_to_ruletree_string_ptr(rule->rtree_fsr_action_offs, NULL)); break; default: printf("ERROR: Unknown action type %d\n", rule->rtree_fsr_action_type); break; } if (rule->rtree_fsr_rule_list_link) { print_indent(indent+1); printf("%s = {\n", rule_list_link_label); dump_objectlist(rule->rtree_fsr_rule_list_link, indent + 2); print_indent(indent+1); printf("}\n"); } print_indent(indent); printf("}\n"); }
static char *ruletree_execute_conditional_actions( const path_mapping_context_t *ctx, int result_log_level, const char *abs_clean_virtual_path, int *flagsp, const char **exec_policy_name_ptr, const char **errormsgp, ruletree_fsrule_t *rule_selector) { uint32_t actions_list_size; uint32_t i; ruletree_object_offset_t action_list_offs = rule_selector->rtree_fsr_rule_list_link; /* FIXME: these are not yet used. */ (void)ctx; (void)result_log_level; (void)exec_policy_name_ptr; LB_LOG(LB_LOGLEVEL_NOISE, "ruletree_execute_conditional_actions for (%s)", abs_clean_virtual_path); actions_list_size = ruletree_objectlist_get_list_size(action_list_offs); if (actions_list_size == 0) { LB_LOG(LB_LOGLEVEL_DEBUG, "ruletree_execute_conditional_actions: action list not found or empty."); *errormsgp = "action list not found or empty."; return (NULL); } for (i = 0; i < actions_list_size; i++) { ruletree_fsrule_t *action_cand_p; ruletree_object_offset_t action_offs; action_offs = ruletree_objectlist_get_item(action_list_offs, i); if (!action_offs) continue; /* "rule_selector" is the rule which matched, and * brought us here (so it contains "dir","prefix" * or "path"). * Each member in the "actions" array is a * candidate for the rule which will be applied, * i.e. a suitable member from that array gives * instructions about what to do next */ action_cand_p = offset_to_ruletree_fsrule_ptr(action_offs); if (action_cand_p) { char *mapping_result; if (action_cand_p->rtree_fsr_condition_type != 0) { const char *cond_str; const char *evp; cond_str = offset_to_ruletree_string_ptr(action_cand_p->rtree_fsr_condition_offs, NULL); LB_LOG(LB_LOGLEVEL_NOISE, "Condition test '%s'", cond_str); switch (action_cand_p->rtree_fsr_condition_type) { case LB_RULETREE_FSRULE_CONDITION_IF_ENV_VAR_IS_NOT_EMPTY: if (!cond_str) continue; /* continue if no env.var.name */ evp = getenv(cond_str); if (!evp || !*evp) continue; /* continue if empty */ LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: env.var was not empty"); break; /* else test passed. */ case LB_RULETREE_FSRULE_CONDITION_IF_ENV_VAR_IS_EMPTY: if (!cond_str) continue; /* continue if no env.var.name */ evp = getenv(cond_str); if (evp && *evp) continue; /* continue if not empty */ LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: env.var was empty"); break; /* else test passed. */ case LB_RULETREE_FSRULE_CONDITION_IF_ACTIVE_EXEC_POLICY_IS: if (!cond_str || !ldbox_active_exec_policy_name || strcmp(cond_str, ldbox_active_exec_policy_name)) { /* exec policy name did not match */ continue; } LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: exec policy name matched"); break; case LB_RULETREE_FSRULE_CONDITION_IF_REDIRECT_IGNORE_IS_ACTIVE: if (!cond_str) continue; /* continue if no path */ if (test_if_str_in_colon_separated_list_from_env( cond_str, "LDBOX_REDIRECT_IGNORE")) { LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: redirect-ignore is active (%s)", cond_str); } else { LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: redirect-ignore is NOT active (%s)", cond_str); continue; } break; case LB_RULETREE_FSRULE_CONDITION_IF_REDIRECT_FORCE_IS_ACTIVE: if (!cond_str) continue; /* continue if no path */ if (test_if_str_in_colon_separated_list_from_env( cond_str, "LDBOX_REDIRECT_FORCE")) { LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: redirect-force is active (%s)", cond_str); } else { LB_LOG(LB_LOGLEVEL_NOISE, "Condition test: redirect-force is NOT active (%s)", cond_str); continue; } break; case LB_RULETREE_FSRULE_CONDITION_IF_EXISTS_IN: if (if_exists_in(action_cand_p, abs_clean_virtual_path)) { /* found, jump to the new rule tree branch */ ruletree_object_offset_t then_actions_offset = action_cand_p->rtree_fsr_rule_list_link; if (!then_actions_offset) { LB_LOG(LB_LOGLEVEL_DEBUG, "if_exists_in: no then_actions found"); /* continue with normal rule tree */ continue; } else { LB_LOG(LB_LOGLEVEL_DEBUG, "if_exists_in: then_actions found (%d)", then_actions_offset); ruletree_fsrule_t new_rules = *rule_selector; new_rules.rtree_fsr_rule_list_link = then_actions_offset; return ruletree_execute_conditional_actions(ctx, result_log_level, abs_clean_virtual_path, flagsp, exec_policy_name_ptr, errormsgp, &new_rules); } } /* not found, continue with normal rule tree */ continue; break; default: LB_LOG(LB_LOGLEVEL_ERROR, "ruletree_execute_conditional_actions: " " unknown condition %d @%d", action_cand_p->rtree_fsr_condition_type, action_offs); goto unimplemented_action_error; } } switch (action_cand_p->rtree_fsr_action_type) { case LB_RULETREE_FSRULE_ACTION_IF_EXISTS_THEN_MAP_TO: if (if_exists_then_map_to(action_cand_p, abs_clean_virtual_path, &mapping_result)) { return(mapping_result); } break; case LB_RULETREE_FSRULE_ACTION_IF_EXISTS_THEN_REPLACE_BY: if (if_exists_then_replace_by(action_cand_p, rule_selector, abs_clean_virtual_path, &mapping_result)) { return(mapping_result); } break; case LB_RULETREE_FSRULE_ACTION_USE_ORIG_PATH: case LB_RULETREE_FSRULE_ACTION_FORCE_ORIG_PATH: case LB_RULETREE_FSRULE_ACTION_FORCE_ORIG_PATH_UNLESS_CHROOT: case LB_RULETREE_FSRULE_ACTION_MAP_TO: case LB_RULETREE_FSRULE_ACTION_REPLACE_BY: case LB_RULETREE_FSRULE_ACTION_SET_PATH: case LB_RULETREE_FSRULE_ACTION_MAP_TO_VALUE_OF_ENV_VAR: case LB_RULETREE_FSRULE_ACTION_REPLACE_BY_VALUE_OF_ENV_VAR: case LB_RULETREE_FSRULE_ACTION_PROCFS: case LB_RULETREE_FSRULE_ACTION_UNION_DIR: return(execute_std_action(rule_selector, action_cand_p, abs_clean_virtual_path, flagsp)); default: /* FIXME */ goto unimplemented_action_error; } } } /* end of list is most probably a fatal error in the rule file. */ LB_LOG(LB_LOGLEVEL_ERROR, "ruletree_execute_conditional_actions: End of conditional action list, " "probably caused by an error in the rule file."); /* FIXME. This should probably return the original path (compare with * Lua code) */ *errormsgp = "End of conditional action list"; return (NULL); unimplemented_action_error: LB_LOG(LB_LOGLEVEL_ERROR, "Internal error: ruletree_execute_conditional_actions: Encountered " "an unknown conditional action."); *errormsgp = "unknown conditional action (internal error)"; return (NULL); }
char *ruletree_translate_path( const path_mapping_context_t *ctx, int result_log_level, const char *abs_clean_virtual_path, int *flagsp, const char **exec_policy_name_ptr, const char **errormsgp) { char *host_path = NULL; ruletree_fsrule_t *rule; PROCESSCLOCK(clk1) START_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, "ruletree_translate_path"); *errormsgp = NULL; if (!ctx->pmc_ruletree_offset) { /* This might happen during initialization phase, * when rule tree is not yet available */ LB_LOG(LB_LOGLEVEL_DEBUG, "ruletree_translate_path: No rule tree"); *errormsgp = "No rule tree"; return(NULL); } rule = offset_to_ruletree_fsrule_ptr(ctx->pmc_ruletree_offset); LB_LOG(LB_LOGLEVEL_DEBUG, "ruletree_translate_path(%s)", abs_clean_virtual_path); /* execute rule */ /* FIXME: should care about the R/O flag... */ if (flagsp) *flagsp = rule->rtree_fsr_flags; if (exec_policy_name_ptr) { if (rule->rtree_fsr_exec_policy_name) { *exec_policy_name_ptr = offset_to_ruletree_string_ptr(rule->rtree_fsr_exec_policy_name, NULL); } else { *exec_policy_name_ptr = NULL; } } switch (rule->rtree_fsr_action_type) { case LB_RULETREE_FSRULE_ACTION_FALLBACK_TO_OLD_MAPPING_ENGINE: LB_LOG(LB_LOGLEVEL_WARNING, "ruletree_translate_path: Forced fallback. This should never happen nowadays."); host_path = NULL; break; case LB_RULETREE_FSRULE_ACTION_USE_ORIG_PATH: case LB_RULETREE_FSRULE_ACTION_FORCE_ORIG_PATH: case LB_RULETREE_FSRULE_ACTION_FORCE_ORIG_PATH_UNLESS_CHROOT: case LB_RULETREE_FSRULE_ACTION_MAP_TO: case LB_RULETREE_FSRULE_ACTION_REPLACE_BY: case LB_RULETREE_FSRULE_ACTION_SET_PATH: case LB_RULETREE_FSRULE_ACTION_MAP_TO_VALUE_OF_ENV_VAR: case LB_RULETREE_FSRULE_ACTION_REPLACE_BY_VALUE_OF_ENV_VAR: case LB_RULETREE_FSRULE_ACTION_PROCFS: case LB_RULETREE_FSRULE_ACTION_UNION_DIR: host_path = execute_std_action(rule, rule, abs_clean_virtual_path, flagsp); break; case LB_RULETREE_FSRULE_ACTION_CONDITIONAL_ACTIONS: host_path = ruletree_execute_conditional_actions( ctx, result_log_level, abs_clean_virtual_path, flagsp, exec_policy_name_ptr, errormsgp, rule); break; default: LB_LOG(LB_LOGLEVEL_ERROR, "ruletree_translate_path: Unknown action code %d", rule->rtree_fsr_action_type); host_path = NULL; break; } if (host_path) { if (*host_path != '/') { LB_LOG(LB_LOGLEVEL_ERROR, "Mapping failed: Result is not absolute ('%s'->'%s')", abs_clean_virtual_path, host_path); host_path = NULL; } else { char *new_host_path = clean_and_log_fs_mapping_result(ctx, abs_clean_virtual_path, result_log_level, host_path, *flagsp); if (new_host_path == NULL) { LB_LOG(result_log_level, "Mapping failed ('%s')", abs_clean_virtual_path); *errormsgp = "Mapping failed"; } free(host_path); host_path = new_host_path; } } else { LB_LOG(result_log_level, "Mapping failed: Fallback to Lua mapping ('%s')", abs_clean_virtual_path); *errormsgp = "No result from C mapping"; } STOP_AND_REPORT_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, host_path); return(host_path); }
static ruletree_object_offset_t ruletree_find_rule( const path_mapping_context_t *ctx, ruletree_object_offset_t rule_list_offs, const char *virtual_path, size_t virtual_path_len, int *min_path_lenp, uint32_t fn_class, ruletree_fsrule_t **rule_p) { uint32_t rule_list_size; uint32_t i; PROCESSCLOCK(clk1) START_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, "ruletree_find_rule"); LB_LOG(LB_LOGLEVEL_NOISE, "ruletree_find_rule for (%s)", virtual_path); rule_list_size = ruletree_objectlist_get_list_size(rule_list_offs); if (min_path_lenp) *min_path_lenp = 0; if (rule_p) *rule_p = NULL; if (rule_list_size == 0) return(0); for (i = 0; i < rule_list_size; i++) { ruletree_fsrule_t *rp; ruletree_object_offset_t rule_offs; rule_offs = ruletree_objectlist_get_item(rule_list_offs, i); if (!rule_offs) continue; rp = offset_to_ruletree_fsrule_ptr(rule_offs); if (rp) { int min_path_len; if (rp->rtree_fsr_condition_type != 0) { LB_LOG(LB_LOGLEVEL_DEBUG, "ruletree_find_rule: can't handle rules with conditions, fail. @%d", rule_offs); return(0); } if (rp->rtree_fsr_selector_type == 0) { LB_LOG(LB_LOGLEVEL_NOISE, "ruletree_find_rule skipping defunct rule @%d", rule_offs); continue; } min_path_len = ruletree_test_path_match(virtual_path, virtual_path_len, rp); if (min_path_len >= 0) { LB_LOG(LB_LOGLEVEL_NOISE, "ruletree_find_rule found rule @ %d", rule_offs); if (rp->rtree_fsr_func_class) { if ((rp->rtree_fsr_func_class & fn_class) == 0) { /* Function class does not match.. */ continue; } } if (rp->rtree_fsr_binary_name) { const char *bin_name_in_rule = offset_to_ruletree_string_ptr(rp->rtree_fsr_binary_name, NULL); if (strcmp(ctx->pmc_binary_name, bin_name_in_rule)) { /* binary name does not match, not this rule... */ continue; } } if (min_path_lenp) *min_path_lenp = min_path_len; if (rp->rtree_fsr_action_type == LB_RULETREE_FSRULE_ACTION_SUBTREE) { /* if rule can be found from the subtree, return it, * otherwise continue looping here */ if (rp->rtree_fsr_rule_list_link) { ruletree_object_offset_t subtree_offs; LB_LOG(LB_LOGLEVEL_NOISE, "ruletree_find_rule: continue @ %d", rp->rtree_fsr_rule_list_link); subtree_offs = ruletree_find_rule(ctx, rp->rtree_fsr_rule_list_link, virtual_path, virtual_path_len, min_path_lenp, fn_class, rule_p); if (subtree_offs) { STOP_AND_REPORT_PROCESSCLOCK( LB_LOGLEVEL_INFO, &clk1, "found/subtree"); return(subtree_offs); } } else { LB_LOG(LB_LOGLEVEL_NOISE, "ruletree_find_rule: no link"); } continue; } /* found it! */ if (rule_p) *rule_p = rp; STOP_AND_REPORT_PROCESSCLOCK( LB_LOGLEVEL_INFO, &clk1, "found"); return(rule_offs); } } } STOP_AND_REPORT_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, "not found"); return (0); /* failed to find it */ }