diff options
author | Ted Trask <ttrask01@yahoo.com> | 2017-04-11 15:07:33 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2017-04-11 15:07:33 +0000 |
commit | f653fac935d599c5453e86c094502f233abe9180 (patch) | |
tree | e58db38aef9899d5359b4b69a6419408d95c564c | |
download | acf-nsd-f653fac935d599c5453e86c094502f233abe9180.tar.bz2 acf-nsd-f653fac935d599c5453e86c094502f233abe9180.tar.xz |
Support for expert editing of files and user/role permissions
-rw-r--r-- | Makefile | 43 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | config.mk | 10 | ||||
-rw-r--r-- | nsd-controller.lua | 59 | ||||
l--------- | nsd-editfile-html.lsp | 1 | ||||
l--------- | nsd-editzonefile-html.lsp | 1 | ||||
-rw-r--r-- | nsd-listfiles-html.lsp | 66 | ||||
-rw-r--r-- | nsd-listpermissions-html.lsp | 75 | ||||
-rw-r--r-- | nsd-listzonefiles-html.lsp | 65 | ||||
-rw-r--r-- | nsd-model.lua | 396 | ||||
l--------- | nsd-status-html.lsp | 1 | ||||
-rw-r--r-- | nsd.menu | 5 | ||||
-rw-r--r-- | nsd.roles | 4 |
13 files changed, 727 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..faeb6a1 --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +APP_NAME=nsd +PACKAGE=acf-$(APP_NAME) +VERSION=0.0.1 + +APP_DIST=\ + nsd* \ + +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 @@ -0,0 +1 @@ +ACF module for nsd 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 diff --git a/nsd-controller.lua b/nsd-controller.lua new file mode 100644 index 0000000..846d14c --- /dev/null +++ b/nsd-controller.lua @@ -0,0 +1,59 @@ +local mymodule = {} +validator = require("acf.validator") + +mymodule.default_action = "status" + +function mymodule.status(self) + return self.model.getstatus() +end + +function mymodule.startstop(self) + return self.handle_form(self, self.model.get_startstop, self.model.startstop_service, self.clientdata) +end + +function mymodule.listfiles(self) + return self.model.list_files(self) +end + +function mymodule.editfile(self) + return self.handle_form(self, self.model.get_file, self.model.update_file, self.clientdata, "Save", "Edit File", "File Saved") +end + +function mymodule.createfile(self) + return self.handle_form(self, self.model.get_new_file, self.model.create_file, self.clientdata, "Create", "Create New NSD File", "Freeswitch File Created") +end + +function mymodule.deletefile(self) + return self.handle_form(self, self.model.get_delete_file, self.model.delete_file, self.clientdata, "Delete", "Delete NSD File", "Freeswitch File Deleted") +end + +function mymodule.listzonefiles(self) + return self.model.getzonefilelist(self, self.clientdata, self.sessiondata.userinfo.userid) +end + +function mymodule.editzonefile(self) + config = self.handle_form(self, function() + return self.model.get_zonefile(self, self.clientdata, self.sessiondata.userinfo.userid) + end, function(self, value) + return self.model.set_zonefile(self, value, self.sessiondata.userinfo.userid) + end, self.clientdata, "Save", "Edit Zone File", "Zone File Saved") + + if self.clientdata.linenumber and validator.is_integer(self.clientdata.linenumber) then + config.value.filecontent.linenumber = self.clientdata.linenumber + end + return config +end + +function mymodule.listpermissions(self) + return self.model:getpermissionslist() +end + +function mymodule.edituserpermissions(self) + return self.handle_form(self, self.model.getuserpermissions, self.model.setuserpermissions, self.clientdata, "Save", "Edit User Permissions", "User permissions set") +end + +function mymodule.editrolepermissions(self) + return self.handle_form(self, self.model.getrolepermissions, self.model.setrolepermissions, self.clientdata, "Save", "Edit Role Permissions", "Role permissions set") +end + +return mymodule diff --git a/nsd-editfile-html.lsp b/nsd-editfile-html.lsp new file mode 120000 index 0000000..15b1930 --- /dev/null +++ b/nsd-editfile-html.lsp @@ -0,0 +1 @@ +../filedetails-html.lsp
\ No newline at end of file diff --git a/nsd-editzonefile-html.lsp b/nsd-editzonefile-html.lsp new file mode 120000 index 0000000..15b1930 --- /dev/null +++ b/nsd-editzonefile-html.lsp @@ -0,0 +1 @@ +../filedetails-html.lsp
\ No newline at end of file diff --git a/nsd-listfiles-html.lsp b/nsd-listfiles-html.lsp new file mode 100644 index 0000000..5486a99 --- /dev/null +++ b/nsd-listfiles-html.lsp @@ -0,0 +1,66 @@ +<% local view, viewlibrary, page_info, session = ... +htmlviewfunctions = require("htmlviewfunctions") +html = require("acf.html") +%> + +<script type="text/javascript"> + if (typeof jQuery == 'undefined') { + document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery-latest.js"><\/script>'); + } +</script> + +<script type="text/javascript"> + if (typeof $.tablesorter == 'undefined') { + document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery.tablesorter.js"><\/script>'); + } +</script> + +<script type="text/javascript"> + $(document).ready(function() { + $("#list").tablesorter({headers: {0:{sorter: false}}, widgets: ['zebra']}); + $(".deletefile").click(function(){ return confirm("Are you sure you want to delete this file?")}); + }); +</script> + +<% htmlviewfunctions.displaycommandresults({"editfile", "deletefile"}, session) %> +<% htmlviewfunctions.displaycommandresults({"createfile"}, session, true) %> + +<% if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("status") +end %> + +<% local header_level = htmlviewfunctions.displaysectionstart(cfe({label="Configuration"}), page_info) %> +<table id="list" class="tablesorter"><thead> + <tr> + <th>Action</th> + <th>File</th> + <th>Size</th> + <th>Last Modified</th> + </tr> +</thead><tbody> +<% local filename = cfe({ type="hidden", value="" }) %> +<% local redir = cfe({ type="hidden", value=page_info.orig_action }) %> +<% for i,file in ipairs( view.value ) do %> + <tr> + <td> + <% filename.value = file.filename %> + <% if viewlibrary.check_permission("editfile") then %> + <% htmlviewfunctions.displayitem(cfe({type="link", value={filename=filename, redir=redir}, label="", option="Edit", action="editfile"}), page_info, -1) %> + <% end %> + <% if viewlibrary.check_permission("deletefile") then %> + <% htmlviewfunctions.displayitem(cfe({type="form", value={filename=filename}, label="", option="Delete", action="deletefile", class="deletefile"}), page_info, -1) %> + <% end %> + </td> + <td><%= html.html_escape(file.filename) %></td> + <td><span class="hide"><%= html.html_escape(file.size or 0) %>b</span><%= format.formatfilesize(file.size) %></td> + <td><%= format.formattime(file.mtime) %></td> + </tr> +<% end %> +</tbody></table> + +<% if viewlibrary and viewlibrary.dispatch_component and viewlibrary.check_permission("createfile") then + local createform = viewlibrary.dispatch_component("createfile", nil, true) + createform.action = page_info.script .. page_info.prefix .. page_info.controller .. "/createfile" + htmlviewfunctions.displayitem(createform, page_info, htmlviewfunctions.incrementheader(header_level)) +end %> +<% htmlviewfunctions.displaysectionend(header_level) %> diff --git a/nsd-listpermissions-html.lsp b/nsd-listpermissions-html.lsp new file mode 100644 index 0000000..eb7ecc6 --- /dev/null +++ b/nsd-listpermissions-html.lsp @@ -0,0 +1,75 @@ +<% local view, viewlibrary, page_info, session = ... %> +<% htmlviewfunctions = require("htmlviewfunctions") %> +<% html = require("acf.html") %> + +<script type="text/javascript"> + if (typeof jQuery == 'undefined') { + document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery-latest.js"><\/script>'); + } +</script> + +<script type="text/javascript"> + if (typeof $.tablesorter == 'undefined') { + document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery.tablesorter.js"><\/script>'); + } +</script> + +<script type="text/javascript"> + $(document).ready(function() { + $("#userlist").tablesorter({headers: {0:{sorter: false}}, widgets: ['zebra']}); + $("#rolelist").tablesorter({headers: {0:{sorter: false}}, widgets: ['zebra']}); + }); +</script> + +<% htmlviewfunctions.displaycommandresults({"edituserpermissions", "editrolepermissions"}, session) %> + +<% local header_level = htmlviewfunctions.displaysectionstart(view, page_info) %> +<% local header_level2 = htmlviewfunctions.displaysectionstart(cfe({label="User Permissions"}), page_info, htmlviewfunctions.incrementheader(header_level)) %> +<table id="userlist" class="tablesorter"><thead> + <tr> + <th>Action</th> + <th>User</th> + <th>Permissions</th> + </tr> +</thead><tbody> +<% local userid = cfe({ type="hidden", value="" }) %> +<% local redir = cfe({ type="hidden", value=page_info.orig_action }) %> +<% for i,user in ipairs(view.value.user) do %> + <% userid.value = user.id %> + <tr> + <td><% htmlviewfunctions.displayitem(cfe({type="link", value={userid=userid, redir=redir}, label="", option="Edit", action="edituserpermissions"}), page_info, -1) %></td> + <td><%= html.html_escape(user.id) %></td> + <td> + <% for y,allowed in pairs(user.allowed) do + print(html.html_escape(allowed), "<br/>") + end %> + </td> + </tr> +<% end %> +</tbody></table> +<% htmlviewfunctions.displaysectionend(header_level2) %> + +<% htmlviewfunctions.displaysectionstart(cfe({label="Role Permissions"}), page_info, header_level2) %> +<table id="rolelist" class="tablesorter"><thead> + <tr> + <th>Action</th> + <th>Role</th> + <th>Permissions</th> + </tr> +</thead><tbody> +<% local rolecfe = cfe({ type="hidden", value="" }) %> +<% for i,role in ipairs(view.value.role) do %> + <% rolecfe.value = role.id %> + <tr> + <td><% htmlviewfunctions.displayitem(cfe({type="link", value={role=rolecfe, redir=redir}, label="", option="Edit", action="editrolepermissions"}), page_info, -1) %></td> + <td><%= html.html_escape(role.id) %></td> + <td> + <% for y,allowed in pairs(role.allowed) do + print(html.html_escape(allowed), "<br/>") + end %> + </td> + </tr> +<% end %> +</tbody></table> +<% htmlviewfunctions.displaysectionend(header_level2) %> +<% htmlviewfunctions.displaysectionend(header_level) %> diff --git a/nsd-listzonefiles-html.lsp b/nsd-listzonefiles-html.lsp new file mode 100644 index 0000000..4acc759 --- /dev/null +++ b/nsd-listzonefiles-html.lsp @@ -0,0 +1,65 @@ +<% local form, viewlibrary, page_info, session = ... +htmlviewfunctions = require("htmlviewfunctions") +html = require("acf.html") +%> + +<script type="text/javascript"> + if (typeof jQuery == 'undefined') { + document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery-latest.js"><\/script>'); + } +</script> + +<script type="text/javascript"> + if (typeof $.tablesorter == 'undefined') { + document.write('<script type="text/javascript" src="<%= html.html_escape(page_info.wwwprefix) %>/js/jquery.tablesorter.js"><\/script>'); + } +</script> + +<script type="text/javascript"> + $(document).ready(function() { + $("#list").tablesorter({headers: {0:{sorter: false}}, widgets: ['zebra']}); + }); +</script> + +<% htmlviewfunctions.displaycommandresults({"editzonefile"}, session) %> +<% htmlviewfunctions.displaycommandresults({"startstop"}, session, true) %> + +<% +local header_level = htmlviewfunctions.displaysectionstart(cfe({label="Configuration"}), page_info) +local header_level2 = htmlviewfunctions.displaysectionstart(cfe({label="Edit/View Existing Domains"}), page_info, htmlviewfunctions.incrementheader(header_level)) +%> +<table id="list" class="tablesorter"><thead> + <tr> + <th>Action</th> + <th>Size</th> + <th>Last Modified</th> + <th>File</th> + </tr> +</thead><tbody> +<% local filename = cfe({ type="hidden", value="" }) %> +<% local redir = cfe({ type="hidden", value=page_info.orig_action }) %> +<% for i,file in ipairs(form.value) do %> + <tr> + <td> + <% + filename.value = file.filename + if viewlibrary.check_permission("editzonefile") then + htmlviewfunctions.displayitem(cfe({type="link", value={filename=filename, redir=redir}, label="", option="Expert", action="editzonefile"}), page_info, -1) + end + %> + </td> + <td><span class="hide"><%= html.html_escape(file.size or 0) %>b</span><%= format.formatfilesize(file.size) %></td> + <td><%= format.formattime(file.mtime) %></td> + <td><%= html.html_escape(string.gsub(file.filename, "^.*/", "")) %></td> + </tr> +<% end %> +</tbody></table> +<% if #form.value == 0 then %> + No domains defined +<% end %> +<% htmlviewfunctions.displaysectionend(header_level2) %> +<% htmlviewfunctions.displaysectionend(header_level) %> + +<% if viewlibrary and viewlibrary.dispatch_component and viewlibrary.check_permission("startstop") then + viewlibrary.dispatch_component("startstop") +end %> diff --git a/nsd-model.lua b/nsd-model.lua new file mode 100644 index 0000000..79b5d8d --- /dev/null +++ b/nsd-model.lua @@ -0,0 +1,396 @@ +local mymodule = {} + +-- Load libraries +modelfunctions = require("modelfunctions") +fs = require("acf.fs") +format = require("acf.format") +validator = require("acf.validator") +authenticator = require("authenticator") +roles = require("roles") +posix = require("posix") + +-- Set variables +local allzonefiles = {} +local cachedzonefiles = {} +local cached_user +local packagename = "nsd" +local processname = "nsd" +local configfile = "/etc/nsd/nsd.conf" +local configdir = "/etc/nsd/" +local descr = { + prefix={ + ['.']="Name server for your domain (NS + A + SOA)", + ['&']="Delegate subdomain (NS + A)", + ['=']="Host and reverse record (A + PTR)", + ['+']="Host record (A, no PTR)", + ['@']="Mail exchanger (MX)", + ["'"]="Text record (TXT)", + ['^']="Reverse record (PTR)", + ['C']="Canonical name (CNAME)", + ['Z']="SOA record (SOA)", + [':']="Generic record", + ['%']="Client location", + ['S']="Service location (SRV)", + ['N']="Naming authority pointer (NAPTR)", + }, + fieldlabels={ + ['.']={"Domain", "IP address", "Name server", "Time to live", "Timestamp", "Location", }, + ['&']={"Domain", "IP address", "Name server", "Time to live", "Timestamp", "Location", }, + ['=']={"Host", "IP address", "Time to live", "Timestamp", "Location", }, + ['+']={"Host", "IP address", "Time to live", "Timestamp", "Location", }, + ['@']={"Domain", "IP address", "Mail exchanger", "Distance", "Time to live", "Timestamp", "Location", }, + ['\'']={"Domain", "Text Record", "Time to live", "Timestamp", "Location", }, + ['^']={"PTR", "Domain name", "Time to live", "Timestamp", "Location", }, + ['C']={"Domain", "Canonical name", "Time to live", "Timestamp", "Location", }, + ['Z']={"Domain", "Primary name server", "Contact address", "Serial number", "Refresh time", "Retry time", "Expire time", "Minimum time", "Time to live", "Timestamp", "Location",}, + [':']={"Domain", "Record type", "Record data", "Time to live", "Timestamp", "Location", }, + ['%']={"Location", "IP prefix", }, + ['S']={"Domain Service", "IP address", "Server", "Port", "Priority", "Weight", "Time to live", "Timestamp", }, + ['N']={"Domain", "Order", "Preference", "Flags", "Service", "Regular expression", "Replacement", "Time to live", "Timestamp", }, + }, +} + +-- ################################################################################ +-- LOCAL FUNCTIONS + +-- Function to recursively inserts all file details in a dir into an array +local function recursedir(path, filearray) + filearray = filearray or {} + local k,v + for k,v in pairs(posix.dir(path) or {}) do + -- Ignore files that begins with a '.' + if not string.match(v, "^%.") then + local f = path .. v + local details = posix.stat(f) + -- If subfolder exists, list files in this subfolder + if details.type == "directory" then + recursedir(f.."/", filearray) + elseif details.type == "regular" then + details.filename = f + table.insert(filearray, details) + end + end + end + return filearray +end + +local is_valid_filename = function(filename) + local dirname = posix.dirname(filename or "").."/" + return validator.is_valid_filename(filename) and string.match(dirname, "^"..format.escapemagiccharacters(configdir)) and not string.match(dirname, "%.%.") +end + +local function getallowedlist(self, userid) + local allowedlist = {} + local auth = authenticator.get_subauth(self) + local entry = auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userid) or "" + for x in string.gmatch(entry, "([^,]+),?") do allowedlist[#allowedlist + 1] = x end + + -- also check to see if there are allowed files for this user's roles + local userinfo = authenticator.get_userinfo(self, userid) + -- add in the guest role + userinfo.roles[#userinfo.roles + 1] = roles.guest_role + for i,role in ipairs(userinfo.roles) do + local entry = auth.read_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, role) or "" + for x in string.gmatch(entry, "([^,]+),?") do allowedlist[#allowedlist + 1] = x end + end + return allowedlist +end + +-- Feed the allzonefiles table with list of all zonefiles in the config +local function listzonefiles() + if #allzonefiles > 0 then + return allzonefiles + end + + -- Parse the config + -- TODO - handle include statements + -- TODO - should properly parse the whole file, not just look for lines + local file = io.open(configfile) + local zonesdir + local zonefiles = {} + for line in file:lines() do + if string.find(line, "^%s*zonesdir:") then + zonesdir = string.match(line, "^%s*zonesdir:%s*\"(.*)\"") + elseif string.find(line, "^%s*zonefile:") then + local z = string.match(line, "^%s*zonefile:%s*\"(.*)\"") + zonefiles[#zonefiles+1] = z + end + end + file:close() + if not zonesdir or zonesdir == "" then + zonesdir = configdir + elseif not string.find(zonesdir, "/$") then + zonesdir = zonesdir.."/" + end + for i,z in ipairs(zonefiles) do + allzonefiles[#allzonefiles+1] = zonesdir..z + end + return allzonefiles +end + +-- Feed the cachedzonefiles table with list of all zonefiles that are available and allowed +-- Default to allowing all files if no userid or allowed list +local function searchforzonefiles(self, userid) + if #cachedzonefiles > 0 and cached_user == userid then + return cachedzonefiles + end + + allzonefiles = listzonefiles(configdir) + local allowedlist = getallowedlist(self, userid) + if allowedlist and #allowedlist > 0 then + local reverseallowed = {} + for x,name in ipairs(allowedlist) do reverseallowed[name] = x end + for k,v in pairs(allzonefiles) do + if reverseallowed[v] then + table.insert(cachedzonefiles, v) + end + end + else + cachedzonefiles = allzonefiles + end + + cached_user = userid + table.sort(cachedzonefiles) + return cachedzonefiles +end + +local function is_valid_zonefile(path) + for k,v in pairs(cachedzonefiles) do + if (v == path) then + return true + end + end + return false, "Not a valid filename!" +end + +-- ################################################################################ +-- PUBLIC FUNCTIONS + +function mymodule.get_startstop(self, clientdata) + return modelfunctions.get_startstop(processname) +end + +function mymodule.startstop_service(self, startstop, action) + return modelfunctions.startstop_service(startstop, action) +end + +function mymodule.getstatus() + return modelfunctions.getstatus(processname, packagename, "NSD Status") +end + +function mymodule.list_files(self) + local filearray = recursedir(configdir) + table.sort(filearray, function(a,b) return a.filename < b.filename end) + return cfe({ type="structure", value=filearray, label="List of NSD files" }) +end + +function mymodule.get_file(self, clientdata) + local retval = cfe({ type="group", value={ filename=cfe({}) } }) + self.handle_clientdata(retval, clientdata) + return modelfunctions.getfiledetails(retval.value.filename.value, is_valid_filename) +end + +function mymodule.update_file(self, filedetails) + return modelfunctions.setfiledetails(self, filedetails, is_valid_filename) +end + +function mymodule.get_new_file(self, clientdata) + local retval = cfe({ type="group", value={}, label="NSD File" }) + retval.value.filename = cfe({ label="File Name", descr="Must be in "..configdir }) + self.handle_clientdata(retval, clientdata) + return retval +end + +function mymodule.create_file(self, filedetails) + local success = true + local path = string.match(filedetails.value.filename.value, "^%s*(.*%S)%s*$") or "" + if not string.find(path, "/") then + path = configdir..path + end + + if not is_valid_filename(path) then + success = false + filedetails.value.filename.errtxt = "Invalid filename" + else + if not fs.is_dir(configdir) then fs.create_directory(configdir) end + if posix.stat(path) then + success = false + filedetails.value.filename.errtxt = "Filename already exists" + end + end + + if success then + fs.create_file(path) + else + filedetails.errtxt = "Failed to Create File" + end + + return filedetails +end + +function mymodule.get_delete_file(self, clientdata) + local retval = cfe({ type="group", value={}, label="Delete NSD File" }) + retval.value.filename = cfe({ label="File Name" }) + self.handle_clientdata(retval, clientdata) + return retval +end + +function mymodule.delete_file(self, delfile) + delfile.errtxt = "Failed to delete NSD File - invalid filename" + for i,file in ipairs(mymodule.list_files().value) do + if delfile.value.filename.value == file.filename then + delfile.errtxt = nil + os.remove(delfile.value.filename.value) + break + end + end + + return delfile +end + +function mymodule.getzonefilelist(self, clientdata, userid) + cachedzonefiles = searchforzonefiles(self, userid) + local listed_files = {} + for i,name in pairs(cachedzonefiles) do + local filedetails = posix.stat(name) or {} + filedetails.filename = name + table.insert(listed_files, filedetails) + end + + return cfe({ type="structure", value=listed_files, label="Zone files" }) +end + +function mymodule.get_zonefile(self, clientdata, userid) + cachedzonefiles = searchforzonefiles(self, userid) + local retval = cfe({ type="group", value={ filename=cfe({}) } }) + self.handle_clientdata(retval, clientdata) + return modelfunctions.getfiledetails(retval.value.filename.value, is_valid_zonefile) +end + +function mymodule.set_zonefile (self, filedetails, userid) + cachedzonefiles = searchforzonefiles(self, userid) + return modelfunctions.setfiledetails(self, filedetails, is_valid_zonefile) +end + +function mymodule.getpermissionslist(self) + local auth = authenticator.get_subauth(self) + local users = authenticator.list_users(self) + local userlist = {} + for i,user in ipairs(users) do + local allowedlist = {} + local entry = auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, user) or "" + for x in string.gmatch(entry, "([^,]+),?") do allowedlist[#allowedlist + 1] = x end + userlist[#userlist + 1] = {id=user, allowed=allowedlist} + end + -- Need to check for roles as well as users + local rolelist = {} + local rols = roles.list_all_roles(self) + for i,role in ipairs(rols) do + local allowedlist = {} + local entry = auth.read_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, role) or "" + for x in string.gmatch(entry, "([^,]+),?") do allowedlist[#allowedlist + 1] = x end + rolelist[#rolelist + 1] = {id=role, allowed=allowedlist} + end + table.sort(userlist, function(a,b) return a.id < b.id end) + return cfe({ type="structure", value={user=userlist, role=rolelist}, label="NSD Permissions" }) +end + +local function validateuserpermissions(self, userpermissions) + local success = true + local userinfo = authenticator.get_userinfo(self, userpermissions.value.userid.value) + if not userinfo then + userpermissions.value.userid.errtxt = "Invalid user" + success = false + end + success = modelfunctions.validatemulti(userpermissions.value.allowed) and success + return success, userpermissions +end + +local function validaterolepermissions(self, rolepermissions) + local success = false + rolepermissions.value.role.errtxt = "Invalid role" + local rols = roles.list_all_roles(self) + for i,role in ipairs(rols) do + if rolepermissions.value.role.value == role then + rolepermissions.value.role.errtxt = nil + success = true + break + end + end + success = modelfunctions.validatemulti(rolepermissions.value.allowed) and success + return success, rolepermissions +end + +function mymodule.getuserpermissions(self, clientdata) + local retval = cfe({ type="group", value={}, label="NSD User Permissions" }) + retval.value.userid = cfe({ label="User Name", seq=0 }) + self.handle_clientdata(retval, clientdata) + + local allzonefiles = listzonefiles(configdir) + table.sort(allzonefiles) + retval.value.allowed = cfe({ type="multi", value={}, label="NSD Permissions", option=allzonefiles, descr="If no permissions are defined, then all are allowed", seq=1 }) + if #allzonefiles == 0 then + retval.value.allowed.errtxt = "No zones defined" + end + + local userid = retval.value.userid.value + if userid ~= "" then + retval.value.userid.readonly = true + + local auth = authenticator.get_subauth(self) + local entry = auth.read_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userid) or "" + for x in string.gmatch(entry, "([^,]+),?") do retval.value.allowed.value[#retval.value.allowed.value + 1] = x end + validateuserpermissions(self, retval) + end + return retval +end + +function mymodule.setuserpermissions(self, userpermissions) + local success, userpermissions = validateuserpermissions(self, userpermissions) + + if success then + local auth = authenticator.get_subauth(self) + auth.write_entry(self, authenticator.usertable, self.conf.prefix..self.conf.controller, userpermissions.value.userid.value, table.concat(userpermissions.value.allowed.value, ",")) + else + userpermissions.errtxt = "Failed to set user permissions" + end + return userpermissions +end + +function mymodule.getrolepermissions(self, clientdata) + local retval = cfe({ type="group", value={}, label="NSD Role Permissions" }) + retval.value.role = cfe({ label="Role", seq=0 }) + self.handle_clientdata(retval, clientdata) + + local allzonefiles = listzonefiles(configdir) + table.sort(allzonefiles) + retval.value.allowed = cfe({ type="multi", value={}, label="NSD Permissions", option=allzonefiles, descr="If no permissions are defined, then all are allowed", seq=1 }) + if #allzonefiles == 0 then + retval.value.allowed.errtxt = "No zones defined" + end + + local role = retval.value.role.value + if role ~= "" then + retval.value.role.readonly = true + + local auth = authenticator.get_subauth(self) + local entry = auth.read_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, role) or "" + for x in string.gmatch(entry, "([^,]+),?") do retval.value.allowed.value[#retval.value.allowed.value + 1] = x end + validaterolepermissions(self, retval) + end + return retval +end + +function mymodule.setrolepermissions(self, rolepermissions) + local success, rolepermissions = validaterolepermissions(self, rolepermissions) + + if success then + local auth = authenticator.get_subauth(self) + auth.write_entry(self, authenticator.roletable, self.conf.prefix..self.conf.controller, rolepermissions.value.role.value, table.concat(rolepermissions.value.allowed.value, ",")) + else + rolepermissions.errtxt = "Failed to set role permissions" + end + return rolepermissions +end + +return mymodule diff --git a/nsd-status-html.lsp b/nsd-status-html.lsp new file mode 120000 index 0000000..b2f8480 --- /dev/null +++ b/nsd-status-html.lsp @@ -0,0 +1 @@ +../status-html.lsp
\ No newline at end of file diff --git a/nsd.menu b/nsd.menu new file mode 100644 index 0000000..ced0b2c --- /dev/null +++ b/nsd.menu @@ -0,0 +1,5 @@ +#CAT GROUP/DESC TAB ACTION +Networking 30NSD Status status +Networking 30NSD List_Domains listzonefiles +Networking 30NSD Expert listfiles +Networking 30NSD Permissions listpermissions diff --git a/nsd.roles b/nsd.roles new file mode 100644 index 0000000..17ba60d --- /dev/null +++ b/nsd.roles @@ -0,0 +1,4 @@ +USER=nsd:status,nsd:listzonefiles,nsd:startstop +EDITOR=nsd:editzonefile,nsd:listzonefiles +EXPERT=nsd:listfiles,nsd:editfile,nsd:createfile,nsd:deletefile +ADMIN=nsd:status,nsd:listzonefiles,nsd:startstop,nsd:editzonefile,nsd:listfiles,nsd:editfile,nsd:createfile,nsd:deletefile,nsd:listpermissions,nsd:edituserpermissions,nsd:editrolepermissions |