summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Trask <ttrask01@yahoo.com>2012-11-06 23:02:06 +0000
committerTed Trask <ttrask01@yahoo.com>2012-11-06 23:02:06 +0000
commit7e68058a731feeb17dd6a609acb26bb68ba06ff8 (patch)
tree2a97796627bdb7906e00e146ffa5d42feeaa6a6b
downloadacf-awall-7e68058a731feeb17dd6a609acb26bb68ba06ff8.tar.bz2
acf-awall-7e68058a731feeb17dd6a609acb26bb68ba06ff8.tar.xz
First cut at awall ACFv0.0.1
-rw-r--r--Makefile44
-rw-r--r--README1
-rw-r--r--awall-controller.lua39
l---------awall-editpolicy-html.lsp1
-rw-r--r--awall-listpolicies-html.lsp51
-rw-r--r--awall-model.lua275
l---------awall-status-html.lsp1
l---------awall-viewpolicy-html.lsp1
-rw-r--r--awall.menu4
-rw-r--r--awall.roles3
-rw-r--r--config.mk10
11 files changed, 430 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..aee4a0a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,44 @@
+APP_NAME=awall
+PACKAGE=acf-$(APP_NAME)
+VERSION=0.0.1
+
+APP_DIST=\
+ awall* \
+
+
+EXTRA_DIST=README Makefile config.mk
+
+DISTFILES=$(APP_DIST) $(EXTRA_DIST)
+
+TAR=tar
+
+P=$(PACKAGE)-$(VERSION)
+tarball=$(P).tar.bz2
+install_dir=$(DESTDIR)/$(appdir)/$(APP_NAME)
+
+all:
+clean:
+ rm -rf $(tarball) $(P)
+
+dist: $(tarball)
+
+install:
+ mkdir -p "$(install_dir)"
+ cp -a $(APP_DIST) "$(install_dir)"
+
+$(tarball): $(DISTFILES)
+ rm -rf $(P)
+ mkdir -p $(P)
+ cp -a $(DISTFILES) $(P)
+ $(TAR) -jcf $@ $(P)
+ rm -rf $(P)
+
+# target that creates a tar package, unpacks is and install from package
+dist-install: $(tarball)
+ $(TAR) -jxf $(tarball)
+ $(MAKE) -C $(P) install DESTDIR=$(DESTDIR)
+ rm -rf $(P)
+
+include config.mk
+
+.PHONY: all clean dist install dist-install
diff --git a/README b/README
new file mode 100644
index 0000000..fda56b1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+ACF for ppp
diff --git a/awall-controller.lua b/awall-controller.lua
new file mode 100644
index 0000000..9fa56a1
--- /dev/null
+++ b/awall-controller.lua
@@ -0,0 +1,39 @@
+module(..., package.seeall)
+
+default_action = "status"
+
+function status(self)
+ return self.model.getstatus()
+end
+
+function startstop(self)
+ return self.handle_form(self, self.model.get_startstop, self.model.startstop_service, self.clientdata)
+end
+
+function listpolicies(self)
+ return self.model.list_policies()
+end
+
+function viewpolicy(self)
+ return self.model.read_policyfile(self, clientdata)
+end
+
+function createpolicy(self)
+ return self.handle_form(self, self.model.get_newpolicy, self.model.create_policy, self.clientdata, "Create", "Create New Policy File", "Policy File Created")
+end
+
+function deletepolicy(self)
+ return self.handle_form(self, self.model.get_delete_policy, self.model.delete_policy, self.clientdata, "Delete", "Delete Policy File", "Policy File Deleted")
+end
+
+function editpolicy(self)
+ return self.handle_form(self, self.model.get_policyfile, self.model.update_policyfile, self.clientdata, "Save", "Edit Policy", "Policy File Saved")
+end
+
+function enablepolicy(self)
+ return self.handle_form(self, self.model.get_enablepolicy, self.model.enable_policy, self.clientdata, "Enable", "Enable Policy", "Policy Enabled")
+end
+
+function disablepolicy(self)
+ return self.handle_form(self, self.model.get_enablepolicy, self.model.disable_policy, self.clientdata, "Disable", "Disable Policy", "Policy Disabled")
+end
diff --git a/awall-editpolicy-html.lsp b/awall-editpolicy-html.lsp
new file mode 120000
index 0000000..15b1930
--- /dev/null
+++ b/awall-editpolicy-html.lsp
@@ -0,0 +1 @@
+../filedetails-html.lsp \ No newline at end of file
diff --git a/awall-listpolicies-html.lsp b/awall-listpolicies-html.lsp
new file mode 100644
index 0000000..1d807e9
--- /dev/null
+++ b/awall-listpolicies-html.lsp
@@ -0,0 +1,51 @@
+<% local form, viewlibrary, page_info, session = ...
+require("htmlviewfunctions")
+html = require("acf.html")
+%>
+
+<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery-latest.js"></script>
+<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery.tablesorter.js"></script>
+<script type="text/javascript">
+ $(document).ready(function() {
+ $(".deletepolicy").click(function(){ return confirm("Are you sure you want to delete this policy?")});
+ });
+</script>
+
+<% htmlviewfunctions.displaycommandresults({"deletepolicy", "editpolicy", "viewpolicy", "enablepolicy", "disablepolicy", "startstop"}, session) %>
+<% htmlviewfunctions.displaycommandresults({"createpolicy"}, session, true) %>
+
+<h1>Policies</h1>
+<DL>
+<% if form.errtxt then %><P CLASS='error'><%= string.gsub(html.html_escape(form.errtxt), "\n", "<BR>") %></P><% end %>
+<TABLE>
+ <TR style="background:#eee;font-weight:bold;">
+ <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD>
+ <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Status</TD>
+ <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Name</TD>
+ <TD style="white-space:nowrap;text-align:left;" class="header">Description</TD>
+ </TR>
+<% for i,pol in ipairs(form.value) do %>
+ <TR>
+ <TD style="padding-right:20px;white-space:nowrap;">
+ <%
+ if viewlibrary.check_permission("deletepolicy") and pol.editable and pol.status ~= "enabled" and pol.status ~= "required" then io.write(html.link{value = "deletepolicy?submit=true&filename=" .. pol.filename, label="Delete ", class="deletepolicy" }) end
+ if viewlibrary.check_permission("editpolicy") and pol.editable then io.write(html.link{value = "editpolicy?filename=" .. pol.filename.."&redir="..page_info.orig_action, label="Edit " }) end
+ if viewlibrary.check_permission("viewpolicy") and not pol.editable and pol.filename then io.write(html.link{value = "viewpolicy?filename=" .. pol.filename.."&redir="..page_info.orig_action, label="View " }) end
+ if viewlibrary.check_permission("enablepolicy") and (pol.status == "disabled" or pol.status == "required") then io.write(html.link{value = "enablepolicy?submit=true&name=" .. pol.name, label="Enable " }) end
+ if viewlibrary.check_permission("disablepolicy") and pol.status == "enabled" then io.write(html.link{value = "disablepolicy?submit=true&name=" .. pol.name, label="Disable " }) end
+ %>
+ </TD>
+ <TD style="white-space:nowrap;" width="90%"><%= html.html_escape(string.gsub(pol.status or "", "^%l", string.upper)) %></TD>
+ <TD style="white-space:nowrap;" width="90%"><%= html.html_escape(pol.name) %></TD>
+ <TD style="white-space:nowrap;" width="90%"><%= html.html_escape(pol.description) %></TD>
+ </TR>
+<% end %>
+</TABLE></DL>
+
+<% if viewlibrary and viewlibrary.dispatch_component and viewlibrary.check_permission("createpolicy") then
+ viewlibrary.dispatch_component("createpolicy")
+end %>
+
+<% if viewlibrary and viewlibrary.dispatch_component and viewlibrary.check_permission("startstop") then
+ viewlibrary.dispatch_component("startstop")
+end %>
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
diff --git a/awall-status-html.lsp b/awall-status-html.lsp
new file mode 120000
index 0000000..b2f8480
--- /dev/null
+++ b/awall-status-html.lsp
@@ -0,0 +1 @@
+../status-html.lsp \ No newline at end of file
diff --git a/awall-viewpolicy-html.lsp b/awall-viewpolicy-html.lsp
new file mode 120000
index 0000000..15b1930
--- /dev/null
+++ b/awall-viewpolicy-html.lsp
@@ -0,0 +1 @@
+../filedetails-html.lsp \ No newline at end of file
diff --git a/awall.menu b/awall.menu
new file mode 100644
index 0000000..dc4ccb3
--- /dev/null
+++ b/awall.menu
@@ -0,0 +1,4 @@
+#CAT GROUP/DESC TAB ACTION
+Networking 25Alpine_Wall Status status
+Networking 25Alpine_Wall Policies listpolicies
+Networking 25Alpine_Wall Expert expert
diff --git a/awall.roles b/awall.roles
new file mode 100644
index 0000000..c6ee6a0
--- /dev/null
+++ b/awall.roles
@@ -0,0 +1,3 @@
+USER=awall:status,awall:startstop
+EXPERT=awall:listpolicies,awall:createpolicy,awall:deletepolicy,awall:editpolicy,awall:viewpolicy,awall:enablepolicy,awall:disablepolicy
+ADMIN=awall:status,awall:startstop,awall:listpolicies,awall:createpolicy,awall:deletepolicy,awall:editpolicy,awall:viewpolicy,awall:enablepolicy,awall:disablepolicy
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..45f4d21
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,10 @@
+prefix=/usr
+datadir=${prefix}/share
+sysconfdir=${prefix}/etc
+localstatedir=${prefix}/var
+acfdir=${datadir}/acf
+wwwdir=${acfdir}/www
+cgibindir=${acfdir}/cgi-bin
+appdir=${acfdir}/app
+acflibdir=${acfdir}/lib
+sessionsdir=${localstatedir}/lib/acf/sessions