summaryrefslogtreecommitdiffstats
path: root/awall-model.lua
diff options
context:
space:
mode:
Diffstat (limited to 'awall-model.lua')
-rw-r--r--awall-model.lua275
1 files changed, 275 insertions, 0 deletions
diff --git a/awall-model.lua b/awall-model.lua
new file mode 100644
index 0000000..7e79813
--- /dev/null
+++ b/awall-model.lua
@@ -0,0 +1,275 @@
+module(..., package.seeall)
+
+-- Load libraries
+require("posix")
+require("json")
+require("modelfunctions")
+processinfo = require("acf.processinfo")
+fs = require("acf.fs")
+--validator = require("acf.validator")
+
+-- Set variables
+local packagename = "awall"
+
+local etcpath = "/etc/awall/"
+local etcoptionalpath = "/etc/awall/optional/"
+local usrpath = "/usr/share/awall/mandatory/"
+local usroptionalpath = "/usr/share/awall/optional/"
+
+local path = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin "
+
+-- ################################################################################
+-- LOCAL FUNCTIONS
+
+local findfiles = function(where)
+ local files = {}
+ for d in posix.files(where) do
+ if string.find(d, "%.json$") then
+ if fs.is_file(where .. d) and string.find(d, "%.json$") then
+ files[#files+1] = where..d
+ elseif fs.is_link(where .. d) then
+ -- awall will use links, but we want to drop the links from /etc/awall/ to one of the optional dirs
+ -- because those are the ones handled by enable/disable
+ local link = posix.dirname(posix.readlink(where..d) or "").."/"
+logevent("link = "..link)
+ if where == etcpath and (string.find(link, "^"..etcoptionalpath.."$") or string.find(link, "^"..usroptionalpath.."$")) then
+ -- do nothing
+ else
+ files[#files+1] = where..d
+ end
+
+ end
+ end
+ end
+ return files
+end
+
+local validatefiledetails = function(filedetails)
+ local success = true
+ local res, err = pcall(function()
+ local jsonoutput, count = json.decode(filedetails.value.filecontent.value)
+ end)
+ if not res and err then
+ success = false
+ end
+
+ if not success then
+ filedetails.value.filecontent.errtxt = "Invalid json code\n"..(err or "")
+ end
+ return success, filedetails
+end
+
+local validateeditablefile = function(filename)
+ -- get/setfiledetails only work for files (not links), this prevents editing/deleting the enable links
+ local dir = posix.dirname(filename or "").."/"
+ if fs.is_file(filename) and string.find(filename, "%.json$") and (dir==etcpath or dir==etcoptionalpath) then
+ return true
+ else
+ return false
+ end
+end
+
+-- ################################################################################
+-- PUBLIC FUNCTIONS
+
+function getstatus()
+ local status = {}
+
+ local value, errtxt = processinfo.package_version(packagename)
+ status.version = cfe({
+ label="Program version",
+ value=value,
+ errtxt=errtxt,
+ name=packagename
+ })
+
+ return cfe({ type="group", value=status, label="AWall Status" })
+end
+
+function get_startstop(self, clientdata)
+ local actions = {"Verify", "Translate", "Activate"}
+ return cfe({ type="group", label="Management", value={}, option=actions })
+end
+
+function startstop_service(self, startstop, action)
+ if not action then
+ startstop.errtxt = "Invalid Action"
+ else
+ local cmd
+ if action == "Verify" then
+ cmd = path.."awall translate -V 2>&1"
+ elseif action == "Translate" then
+ cmd = path.."awall translate 2>&1"
+ else
+ cmd = path.."awall activate -f 2>&1"
+ end
+ local f = io.popen(cmd)
+ startstop.descr = f:read("*a")
+ f:close()
+ end
+ return startstop
+end
+
+function list_policies()
+ -- core-router disabled BSN core router
+ local policies = {}
+ local reversepolicies = {}
+ local errtxt
+ local cmd = path.."awall list 2>&1"
+ local f = io.popen(cmd)
+ for l in f:lines() do
+ local a,b,c = string.match(l, "(%S+)%s+(%S+)%s*(.*)")
+ if a and a == "/usr/bin/lua:" then
+ errtxt = b.." "..c
+ break
+ end
+ if a then
+ policies[#policies+1] = {name=a, status=b, description=c}
+ reversepolicies[a] = #policies
+ end
+ end
+ f:close()
+ -- Since awall seems to crash (and not give results) when there is any error
+ -- Let's show the actual files too
+ local addfiles = function(files, editable, mandatory)
+ for i,d in ipairs(files) do
+ local name = string.match(d, "([^/]*)%.json$")
+ if reversepolicies[name] then
+ policies[reversepolicies[name]].filename = d
+ policies[reversepolicies[name]].editable = editable
+ if mandatory then policies[reversepolicies[name]].status = "mandatory" end
+ else
+ policies[#policies+1] = {name=name, filename=d, editable=editable}
+ if mandatory then policies[#policies].status = "mandatory" end
+ reversepolicies[name] = #policies
+ end
+ end
+ end
+
+ local files = findfiles(usroptionalpath)
+ addfiles(files, false, false)
+ files = findfiles(etcoptionalpath)
+ addfiles(files, true, false)
+ files = findfiles(usrpath)
+ addfiles(files, false, true)
+ files = findfiles(etcpath)
+ addfiles(files, true, true)
+
+ table.sort(policies, function(a,b) return a.name < b.name end)
+
+ return cfe({ type="list", value=policies, label="Policies", errtxt=errtxt })
+end
+
+function get_newpolicy()
+ local newpolicy = {}
+ newpolicy.name = cfe({ label="Name", seq=1 })
+ newpolicy.optional = cfe({ type="boolean", label="Optional", seq=2 })
+ return cfe({ type="group", value=newpolicy, label="New Policy" })
+end
+
+function create_policy(self, newpolicy)
+ local success = true
+ local name = newpolicy.value.name.value
+
+ if name == "" then
+ newpolicy.value.name.errtxt = "Invalid name"
+ success = false
+ else
+ local policies = list_policies()
+ for i,pol in ipairs(policies.value) do
+ if pol.name == newpolicy.value.name.value then
+ newpolicy.value.name.errtxt = "Name already exists"
+ success = false
+ break
+ end
+ end
+ end
+
+ if success then
+ local path
+ if newpolicy.value.optional.value then
+ path = etcoptionalpath
+ else
+ path = etcpath
+ end
+ path = path..name..".json"
+ if posix.stat(path) then
+ newpolicy.value.name.errtxt = path.." already exists"
+ success = false
+ else
+ fs.write_file(path, "{}")
+ end
+ end
+
+ if not success then
+ newpolicy.errtxt = "Failed to create policy file"
+ end
+
+ return newpolicy
+end
+
+function get_delete_policy(self, clientdata)
+ retval = {}
+ retval.filename = cfe({ value=clientdata.filename or "", label="File Name" })
+ return cfe({ type="group", value=retval, label="Delete Policy File" })
+end
+
+function delete_policy(self, delpolicy)
+ if validateeditablefile(delpolicy.value.filename.value) then
+ os.remove(delpolicy.value.filename.value)
+ else
+ delpolicy.errtxt = "Failed to delete policy"
+ delpolicy.value.filename.errtxt="Policy not found"
+ end
+
+ return delpolicy
+end
+
+function read_policyfile(self, clientdata)
+ -- Can read from all 4 locations
+ return modelfunctions.getfiledetails(clientdata.filename, function(filename)
+ local dir = posix.dirname(filename or "").."/"
+ if string.find(filename, "%.json$") and (dir==etcpath or dir==etcoptionalpath or dir==usrpath or dir==usroptionalpath) then
+ return true
+ else
+ return false
+ end
+ end)
+end
+
+function get_policyfile(self, clientdata)
+ -- Can only get (for editing) from /etc/ locations
+ return modelfunctions.getfiledetails(clientdata.filename, validateeditablefile)
+end
+
+function update_policyfile(self, filedetails)
+ return modelfunctions.setfiledetails(self, filedetails, validateeditablefile, validatefiledetails)
+end
+
+function get_enablepolicy(self, clientdata)
+ local policy = {}
+ policy.name = cfe({ value=clientdata.name or "", label="Name", seq=1 })
+ return cfe({ type="group", value=policy, label="Policy" })
+end
+
+function enable_policy(self, enable)
+ local cmd = path.."awall enable "..format.escapespecialcharacters(enable.value.name.value).." 2>&1"
+ local f = io.popen(cmd)
+ local result = f:read("*a")
+ f:close()
+ if result ~= "" then
+ enable.errtxt = result
+ end
+ return enable
+end
+
+function disable_policy(self, disable)
+ local cmd = path.."awall disable "..format.escapespecialcharacters(disable.value.name.value).." 2>&1"
+ local f = io.popen(cmd)
+ local result = f:read("*a")
+ f:close()
+ if result ~= "" then
+ disable.errtxt = result
+ end
+ return disable
+end