diff options
author | Hans Hagen <pragma@wxs.nl> | 2012-05-14 09:19:00 +0200 |
---|---|---|
committer | Hans Hagen <pragma@wxs.nl> | 2012-05-14 09:19:00 +0200 |
commit | 70f57c08e38c62a099bf3e219da08e537ad72ced (patch) | |
tree | a417a8c8dca4d682f206911c24d21f92e3bcd1f3 /tex/context/base/luat-iop.lua | |
parent | af4ff2510c2a18374dec07abe1742e49dd99fc72 (diff) | |
download | context-70f57c08e38c62a099bf3e219da08e537ad72ced.tar.gz |
beta 2012.05.14 09:19
Diffstat (limited to 'tex/context/base/luat-iop.lua')
-rw-r--r-- | tex/context/base/luat-iop.lua | 243 |
1 files changed, 145 insertions, 98 deletions
diff --git a/tex/context/base/luat-iop.lua b/tex/context/base/luat-iop.lua index 091639de2..5512b258e 100644 --- a/tex/context/base/luat-iop.lua +++ b/tex/context/base/luat-iop.lua @@ -11,138 +11,185 @@ if not modules then modules = { } end modules ['luat-iop'] = { -- we can feed back specific patterns and paths into the next -- mechanism -local lower, find, sub = string.lower, string.find, string.sub +-- os.execute os.exec os.spawn io.fopen +-- os.remove lfs.chdir lfs.mkdir +-- io.open zip.open epdf.open mlib.new -local allocate = utilities.storage.allocate +-- cache -local ioinp = io.inp if not ioinp then ioinp = { } io.inp = ioinp end -local ioout = io.out if not ioout then ioout = { } io.out = ioout end +local topattern, find = string.topattern, string.find -ioinp.modes, ioout.modes = allocate(), allocate() +local report_limiter = logs.reporter("system","limiter") -local inp_blocked, inp_permitted = { }, { } -local out_blocked, out_permitted = { }, { } +-- the basic methods -local function i_inhibit(name) inp_blocked [#inp_blocked +1] = name end -local function o_inhibit(name) out_blocked [#out_blocked +1] = name end -local function i_permit (name) inp_permitted[#inp_permitted+1] = name end -local function o_permit (name) out_permitted[#out_permitted+1] = name end - -ioinp.inhibit, ioinp.permit = i_inhibit, o_permit -ioout.inhibit, ioout.permit = o_inhibit, o_permit - -local blockedopeners = { } -- *.open(name,method) - -function io.registeropener(func) - blockedopeners[#blockedopeners+1] = func +local function match(ruleset,name) + local n = #ruleset + if n > 0 then + for i=1,n do + local r = ruleset[i] + if find(name,r[1]) then + return r[2] + end + end + return false + else + -- nothing defined (or any) + return true + end end -local function checked(name,blocked,permitted) - local n = lower(name) - for _,b in next, blocked do - if find(n,b) then - for _,p in next, permitted do - if find(n,p) then - return true - end - end - return false +local function protect(ruleset,proc) + return function(name,...) + if name == "" then + -- report_limiter("no access permitted: <no name>") -- can happen in mplib code + return nil, "no name given" + elseif match(ruleset,name) then + return proc(name,...) + else + report_limiter("no access permitted: %s",name) + return nil, name .. ": no access permitted" end end - return true end -function io.finalizeopeners(func) - if #out_blocked > 0 or #inp_blocked > 0 then - local open = func -- why not directly? - return function(name,method) - if method and find(method,'[wa]') then - if #out_blocked > 0 and not checked(name,out_blocked,out_permitted) then - -- print("writing to " .. name .. " is not permitted") - return nil +function io.limiter(preset) + preset = preset or { } + local ruleset = { } + for i=1,#preset do + local p = preset[i] + local what, spec = p[1] or "", p[2] or "" + if spec == "" then + -- skip 'm + elseif what == "tree" then + resolvers.dowithpath(spec, function(r) + local spec = resolvers.resolve(r) or "" + if spec ~= "" then + ruleset[#ruleset+1] = { topattern(spec,true), true } end - else - if #inp_blocked > 0 and not checked(name,inp_blocked,inp_permitted) then - -- print("reading from " .. name .. " is not permitted") - return nil - end - end - return open(name,method) + end) + elseif what == "permit" then + ruleset[#ruleset+1] = { topattern(spec,true), true } + elseif what == "forbid" then + ruleset[#ruleset+1] = { topattern(spec,true), false } end + end + if #ruleset > 0 then + return { + match = function(name) return match (ruleset,name) end, + protect = function(proc) return protect(ruleset,proc) end, + } else - return func + return { + match = function(name) return true end, + protect = proc, + } end end ---~ io.inp.inhibit('^%.') ---~ io.inp.inhibit('^/etc') ---~ io.inp.inhibit('/windows/') ---~ io.inp.inhibit('/winnt/') ---~ io.inp.permit('c:/windows/wmsetup.log') - ---~ io.open = io.finalizeopeners(io.open) +-- a few handlers ---~ f = io.open('.tex') print(f) ---~ f = io.open('tufte.tex') print(f) ---~ f = io.open('t:/sources/tufte.tex') print(f) ---~ f = io.open('/etc/passwd') print(f) ---~ f = io.open('c:/windows/crap.log') print(f) ---~ f = io.open('c:/windows/wmsetup.log') print(f) +io.i_limiters = { } +io.o_limiters = { } --- restricted - -function ioinp.modes.restricted() - i_inhibit('^%.[%a]') +function io.i_limiter(v) + local i = io.i_limiters[v] + if i then + local i_limiter = io.limiter(i) + function io.i_limiter() + return i_limiter + end + return i_limiter + end end -function ioout.modes.restricted() - o_inhibit('^%.[%a]') +function io.o_limiter(v) + local o = io.o_limiters[v] + if o then + local o_limiter = io.limiter(o) + function io.o_limiter() + return o_limiter + end + return o_limiter + end end --- paranoid +-- the real thing (somewhat fuzzy as we need to know what gets done) -function ioinp.modes.paranoid() - i_inhibit('.*') - i_inhibit('%.%.') - i_permit('^%./') - i_permit('[^/]') - resolvers.dowithpath('TEXMF',i_permit) -end +local i_opener, i_limited = io.open, false +local o_opener, o_limited = io.open, false -function ioout.modes.paranoid() - o_inhibit('.*') - resolvers.dowithpath('TEXMFOUTPUT',o_permit) +local function i_register(v) + if not i_limited then + local i_limiter = io.i_limiter(v) + if i_limiter then + local protect = i_limiter.protect + i_opener = protect(i_opener) + i_limited = true + report_limiter("input mode: %s",v) + end + end end --- handy +local function o_register(v) + if not o_limited then + local o_limiter = io.o_limiter(v) + if o_limiter then + local protect = o_limiter.protect + o_opener = protect(o_opener) + o_limited = true + report_limiter("output mode: %s",v) + end + end +end -function ioinp.modes.handy() - i_inhibit('%.%.') - if os.type == 'windows' then - i_inhibit('/windows/') - i_inhibit('/winnt/') +function io.open(name,method) + if method and find(method,"[wa]") then + return o_opener(name,method) else - i_inhibit('^/etc') + return i_opener(name,method) end end -function ioout.modes.handy() - o_inhibit('.*') - o_permit('%./') - o_permit('^%./') - o_permit('[^/]') +directives.register("system.inputmode", i_register) +directives.register("system.outputmode", o_register) + +local i_limited = false +local o_limited = false + +local function i_register(v) + if not i_limited then + local i_limiter = io.i_limiter(v) + if i_limiter then + local protect = i_limiter.protect + lfs.chdir = protect(lfs.chdir) -- needs checking + i_limited = true + end + end +end + +local function o_register(v) + if not o_limited then + local o_limiter = io.o_limiter(v) + if o_limiter then + local protect = o_limiter.protect + os.remove = protect(os.remove) -- rather okay + lfs.chdir = protect(lfs.chdir) -- needs checking + lfs.mkdir = protect(lfs.mkdir) -- needs checking + o_limited = true + end + end end -local input_mode directives.register("system.inputmode", function(v) input_mode = v end) -local output_mode directives.register("system.outputmode", function(v) output_mode = v end) +directives.register("system.inputmode", i_register) +directives.register("system.outputmode", o_register) + +-- the definitions + +local limiters = resolvers.variable("limiters") -function io.checkopeners() - local inp = input_mode or resolvers.variable("input_mode") -- or ... will become obsolete - local out = output_mode or resolvers.variable("output_mode") -- or ... will become obsolete - inp = inp and ioinp.modes[inp] - out = out and ioinp.modes[out] - if inp then inp() end - if out then out() end +if limiters then + io.i_limiters = limiters.input or { } + io.o_limiters = limiters.output or { } end ---~ io.checkopeners() |