diff --git a/Nasal/IOrules b/Nasal/IOrules deleted file mode 100644 index ddb01890e..000000000 --- a/Nasal/IOrules +++ /dev/null @@ -1,42 +0,0 @@ -# This file defines which file paths can be opened for reading and/or -# writing using Nasal's io.open() and parsexml() functions, as well as -# the fgcommands load, save, loadxml, and savexml. The evaluation code -# can be found in $FG_ROOT/Nasal/io.nas. -# -# Empty lines and lines starting with '#' are ignored. All other entries -# must be of the form -# -# {READ|WRITE} {ALLOW|DENY} -# -# whereby fields must be separated by exactly one space. The pattern must -# not be quoted and may contain spaces. If a pattern starts with $FG_ROOT/ -# or $FG_HOME/, then these parts are replaced by the respective system -# paths. See $FG_ROOT/Nasal/string.nas for the pattern syntax. -# -# Entries are considered from top down. If no entry matches, then file -# access is denied. A local rules file $FG_HOME/Nasal/IOrules using the -# same syntax takes precedence over this file. The default rules that -# apply if there's no Nasal/IOrules file at all, or there are no rules -# defined in it are equivalent to this: -# -# READ DENY * -# WRITE DENY * -# -# Read and write access to Nasal/IOrules files, however, is *always* -# prohibited and not configurable! - -READ ALLOW $FG_ROOT/* -READ ALLOW $FG_HOME/* -READ ALLOW $FG_AIRCRAFT/* - -WRITE ALLOW /tmp/*.xml -WRITE ALLOW $FG_HOME/*.sav -WRITE ALLOW $FG_HOME/*.log -WRITE ALLOW $FG_HOME/cache/* -WRITE ALLOW $FG_HOME/Export/* -WRITE ALLOW $FG_HOME/state/*.xml -WRITE ALLOW $FG_HOME/aircraft-data/*.xml -WRITE ALLOW $FG_HOME/Wildfire/*.xml -WRITE ALLOW $FG_HOME/runtime-jetways/*.xml -WRITE ALLOW $FG_HOME/Input/Joysticks/*.xml - diff --git a/Nasal/io.nas b/Nasal/io.nas index b27e2aa36..4bf0985b4 100644 --- a/Nasal/io.nas +++ b/Nasal/io.nas @@ -277,150 +277,3 @@ var writexml = func(path, node, indent = "\t", prefix = "___") { die("writexml(): tree has more than one root node"); } - -# Redefine io.open() such that files can only be opened under authorized directories. -# -_setlistener("/sim/signals/nasal-dir-initialized", func { - # read IO rules - var root = string.normpath(getprop("/sim/fg-root")); - var home = string.normpath(getprop("/sim/fg-home")); - var config = "Nasal/IOrules"; - - var rules_file = nil; - var read_rules = []; - var write_rules = []; - - var load_rules = func(path) { - if (stat(path) == nil) - return nil; - printlog("info", "using io.open() rules from ", path); - read_rules = []; - write_rules = []; - var file = open(path, "r"); - for (var no = 1; (var line = readln(file)) != nil; no += 1) { - if (!size(line) or line[0] == `#`) - continue; - - var f = split(" ", line); - if (size(f) < 3 or f[0] != "READ" and f[0] != "WRITE" or f[1] != "DENY" and f[1] != "ALLOW") { - printlog("alert", "ERROR: invalid io.open() rule in ", path, ", line ", no, ": ", line); - read_rules = write_rules = []; - break; - } - var pattern = f[2]; - foreach (var p; subvec(f, 3)) - pattern ~= " " ~ p; - var rules = f[0] == "READ" ? read_rules : write_rules; - var allow = (f[1] == "ALLOW"); - - if (substr(pattern, 0, 13) == "$FG_AIRCRAFT/") { - var p = substr(pattern, 13); - var sim = props.globals.getNode("/sim"); - foreach (var c; sim.getChildren("fg-aircraft")) { - pattern = string.normpath(c.getValue()) ~ "/" ~ p; - append(rules, [pattern, allow]); - printlog("info", "IORules: appending ", pattern); - } - } elsif (substr(pattern, 0, 12) == "$FG_SCENERY/") { - var p = substr(pattern, 12); - var sim = props.globals.getNode("/sim"); - foreach (var c; sim.getChildren("fg-scenery")) { - pattern = string.normpath(c.getValue()) ~ "/" ~ p; - append(rules, [pattern, allow]); - printlog("info", "IORules: appending ", pattern); - } - } else { - if (substr(pattern, 0, 9) == "$FG_ROOT/") - pattern = root ~ "/" ~ substr(pattern, 9); - elsif (substr(pattern, 0, 9) == "$FG_HOME/") - pattern = home ~ "/" ~ substr(pattern, 9); - - append(rules, [pattern, allow]); - printlog("info", "IORules: appending ", pattern); - } - } - close(file); - return path; - } - - # catch exceptions so that a die() doesn't ruin everything - var rules_file = call(func load_rules(home ~ "/" ~ config) - or load_rules(root ~ "/" ~ config), nil, var err = []); - if (size(err)) { - debug.printerror(err); - read_rules = write_rules = []; - } - - read_rules = [["*/" ~ config, 0]] ~ read_rules; - write_rules = [["*/" ~ config, 0]] ~ write_rules; - if (__.log_level <= 3) { - print("IOrules/READ: ", debug.string(read_rules)); - print("IOrules/WRITE: ", debug.string(write_rules)); - } - - # make safe, local copies - var setValue = props._setValue; - var getValue = props._getValue; - var normpath = string.normpath; - var match = string.match; - var caller = caller; - var die = die; - - # validators - var valid = func(path, rules) { - var fpath = normpath(path); - foreach (var d; rules) - if (match(fpath, d[0])) - return d[1] ? fpath : nil; - return nil; - } - - var read_validator = func(n) setValue(n, [valid(getValue(n, []), read_rules) or ""]); - var write_validator = func(n) setValue(n, [valid(getValue(n, []), write_rules) or ""]); - - # validation listeners for load[xml]/save[xml]/parsexml() (see utils.cxx:fgValidatePath) - var n = props.globals.getNode("/sim/paths/validate", 1).removeAllChildren(); - var rval = _setlistener(n.getNode("read", 1)._g, read_validator); - var wval = _setlistener(n.getNode("write", 1)._g, write_validator); - - # wrap removelistener - globals.removelistener = var remove_listener = (func { - var _removelistener = globals.removelistener; - func(n) { - if (n != rval and n != wval) - return _removelistener(n); - - die("removelistener(): removal of protected listener #'" ~ n ~ "' denied (unauthorized access)\n "); - } - })(); - - # wrap io.open() - io.open = var io_open = (func { - var _open = io.open; - func(path, mode = "rb") { - var rules = write_rules; - if (mode == "r" or mode == "rb" or mode == "br") - rules = read_rules; - - if (var vpath = valid(path, rules)) - return _open(vpath, mode); - - die("io.open(): opening file '" ~ path ~ "' denied (unauthorized access)\n "); - } - })(); - - # wrap closure() to prevent tampering with security related functions - var thislistener = caller(0)[1]; - globals.closure = (func { - var _closure = globals.closure; - func(fn, level = 0) { - var thisfunction = caller(0)[1]; - if (fn != thislistener and fn != io_open and fn != thisfunction - and fn != read_validator and fn != write_validator - and fn != remove_listener) - return _closure(fn, level); - - die("closure(): query denied (unauthorized access)\n "); - } - })(); -}); diff --git a/Nasal/string.nas b/Nasal/string.nas index c0a057fc4..8ac44dc51 100644 --- a/Nasal/string.nas +++ b/Nasal/string.nas @@ -76,32 +76,6 @@ var icmp = func(a, b) cmp(lc(a), lc(b)); var imatch = func(a, b) match(lc(a), lc(b)); - - -## -# Functions that are used in the IO security code (io.nas) are defined in a -# closure that holds safe copies of system functions. Later manipulation of -# append(), pop() etc. doesn't affect them. Of course, any security code -# must itself store safe copies of these tamper-proof functions before user -# code can redefine them, and the closure() command must be made inaccessible. -## - -var match = nil; -var normpath = nil; -var join = nil; -var replace = nil; - -(func { - var append = append; - var caller = caller; - var pop = pop; - var setsize = setsize; - var size = size; - var split = split; - var substr = substr; - var subvec = subvec; - - ## # check if string matches shell style pattern # @@ -238,8 +212,6 @@ replace = func(str, old, new) { return join(new, split(old, str)); } -})(); # end tamper-proof environment - ## # Get a function out of a string template for fast insertion of template