module(..., package.seeall) -- Load libraries require("posix") require("json") require("modelfunctions") fs = require("acf.fs") -- 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 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() return modelfunctions.getstatus(nil, packagename, "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 = {"awall"} if action == "Verify" then cmd[#cmd+1] = "translate" cmd[#cmd+1] = "-V" elseif action == "Translate" then cmd[#cmd+1] = "translate" else cmd[#cmd+1] = "activate" cmd[#cmd+1] = "-f" end startstop.descr, startstop.errtxt = modelfunctions.run_executable(cmd, true) if not startstop.errtxt and startstop.descr == "" then startstop.descr = "Success" end end return startstop end function list_policies() -- core-router disabled BSN core router local policies = {} local reversepolicies = {} local errtxt local f = modelfunctions.run_executable({"awall", "list"}, true) for l in string.gmatch(f, "[^\n]+") 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 -- 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) enable.descr, enable.errtxt = modelfunctions.run_executable({"awall", "enable", enable.value.name.value}, true) return enable end function disable_policy(self, disable) disable.descr, disable.errtxt = modelfunctions.run_executable({"awall", "disable", disable.value.name.value}, true) return disable end