Compare commits

...

2 Commits

Author SHA1 Message Date
Izaya 4c462a5d4e add access control support to MTFS 2020-10-17 18:50:30 +11:00
Izaya 2363890151 added basic ACLs for the RPC library 2020-10-17 18:49:00 +11:00
4 changed files with 57 additions and 5 deletions

View File

@ -5,13 +5,28 @@ local rpc = require "rpc"
local tA, tO = shell.parse(...)
if #tA < 1 then
print("Usage: exportfs <directory> [-d] [--rw] [--name=<name>]")
print("Usage: exportfs <directory> [-d] [--rw] [--name=<name>] [--allow=hostname[,hostname,...]] [--deny=hostname[,hostname,...]]")
return
end
local allow, deny = {}, {}
for host in (tO.allow or ""):gmatch("[^,]+") do
allow[#allow+1] = host
end
for host in (tO.deny or ""):gmatch("[^,]+") do
deny[#deny+1] = host
end
local px = fsproxy.new(tA[1], not tO.rw)
local name = tO.name or tA[1]
for l,m in pairs(px) do
m = not tO.d and m or nil
rpc.register("fs_"..name.."_"..l,m)
for k,v in pairs(allow) do
rpc.allow("fs_"..name.."_"..l,v)
end
for k,v in pairs(deny) do
rpc.deny("fs_"..name.."_"..l,v)
end
end
print(string.format("%s (%s)", name, (tO.rw and "rw") or "ro"))

View File

@ -57,7 +57,10 @@ if px.dirstat then -- use single call for file info
return gce(path, 4) or olm(path)
end
end
local iro = px.isReadOnly()
local iro,e = px.isReadOnly()
if not iro then
error(e)
end
function px.isReadOnly()
return iro
end

View File

@ -6,6 +6,7 @@ local rpcf = {}
local rpcrunning = false
local rpc = {}
rpc.port = 111
function rpc.call(hostname,fn,...)
if hostname == "localhost" then
return rpcf[fn](...)
@ -39,19 +40,37 @@ function rpc.proxy(hostname,filter)
return rt
end
local function setacl(self, fname, host)
self[fname] = self[fname] or {}
self[fname][host] = true
end
rpc.allow = setmetatable({},{__call=setacl})
rpc.deny = setmetatable({},{__call=setacl})
local function isPermitted(host,fn)
if rpc.allow[fn] then
return rpc.allow[fn][host] or false
end
if rpc.deny[fn] and rpc.deny[fn][host] then
return false
end
return true
end
function rpc.register(name,fn)
if not rpcrunning then
event.listen("net_msg",function(_, from, port, data)
if port == rpc.port then
local rpcrq = serial.unserialize(data)
local rpcn, rpcid = table.remove(rpcrq,1), table.remove(rpcrq,1)
if rpcf[rpcn] then
if rpcf[rpcn] and isPermitted(from,rpcn) then
local rt = {pcall(rpcf[rpcn],table.unpack(rpcrq))}
if rt[1] == true then
table.remove(rt,1)
end
minitel.send(from,port,serial.serialize({rpcid,table.unpack(rt)}))
else
minitel.send(from,port,serial.serialize({rpcid,false,"function unavailable"}))
end
end
end)
@ -67,5 +86,4 @@ function rpc.register(name,fn)
rpcf[name] = fn
end
return rpc

View File

@ -1,5 +1,5 @@
# RPC
Minitel Remote Procedure Call Library
Minitel Remote Procedure Call Library for OpenOS
## API
In all instances, if *hostname* is replaced with *localhost*, an attempt will be made to call the registered procedure on the local machine.
@ -13,7 +13,23 @@ Return a table containing the functions on *hostname* matching *filter*, which i
### rpc.register(*name*, *function*)
Registers *function* as the RPC call for *name* on the current host.
### rpc.allow(*fname*, *hostname*)
Adds *hostname* to the list of remote hosts allowed to execute the function *fname*.
## Access control
Access control is implemented by way of an "allow" list and a "deny" list. Any function lacking both lists will default to the function being available to all hosts.
Any entries in the 'allow' list for a function will disable access for any but those in the allow list.
Entries in the 'deny' list will result in the hosts in said list being denied, but other hosts are allowed. This will not override the 'allow' list.
## Variables
### rpc.port = 111
Port to use for RPC calls and registration.
### rpc.allow = {}
Table containing the allow lists of exported functions. Contents subject to change.
### rpc.deny = {}
Table containing the deny lists of exported functions. Contents subject to change.