From f653fac935d599c5453e86c094502f233abe9180 Mon Sep 17 00:00:00 2001 From: Ted Trask Date: Tue, 11 Apr 2017 15:07:33 +0000 Subject: Initial commit Support for expert editing of files and user/role permissions --- Makefile | 43 +++++ README | 1 + config.mk | 10 ++ nsd-controller.lua | 59 +++++++ nsd-editfile-html.lsp | 1 + nsd-editzonefile-html.lsp | 1 + nsd-listfiles-html.lsp | 66 ++++++++ nsd-listpermissions-html.lsp | 75 ++++++++ nsd-listzonefiles-html.lsp | 65 +++++++ nsd-model.lua | 396 +++++++++++++++++++++++++++++++++++++++++++ nsd-status-html.lsp | 1 + nsd.menu | 5 + nsd.roles | 4 + 13 files changed, 727 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 config.mk create mode 100644 nsd-controller.lua create mode 120000 nsd-editfile-html.lsp create mode 120000 nsd-editzonefile-html.lsp create mode 100644 nsd-listfiles-html.lsp create mode 100644 nsd-listpermissions-html.lsp create mode 100644 nsd-listzonefiles-html.lsp create mode 100644 nsd-model.lua create mode 120000 nsd-status-html.lsp create mode 100644 nsd.menu create mode 100644 nsd.roles 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 diff --git a/README b/README new file mode 100644 index 0000000..55e2a08 --- /dev/null +++ b/README @@ -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") +%> + + + + + + + +<% 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) %> + + + + + + + + +<% local filename = cfe({ type="hidden", value="" }) %> +<% local redir = cfe({ type="hidden", value=page_info.orig_action }) %> +<% for i,file in ipairs( view.value ) do %> + + + + + + +<% end %> +
ActionFileSizeLast Modified
+ <% 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 %> + <%= html.html_escape(file.filename) %><%= html.html_escape(file.size or 0) %>b<%= format.formatfilesize(file.size) %><%= format.formattime(file.mtime) %>
+ +<% 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") %> + + + + + + + +<% 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)) %> + + + + + + + +<% 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 %> + + + + + +<% end %> +
ActionUserPermissions
<% htmlviewfunctions.displayitem(cfe({type="link", value={userid=userid, redir=redir}, label="", option="Edit", action="edituserpermissions"}), page_info, -1) %><%= html.html_escape(user.id) %> + <% for y,allowed in pairs(user.allowed) do + print(html.html_escape(allowed), "
") + end %> +
+<% htmlviewfunctions.displaysectionend(header_level2) %> + +<% htmlviewfunctions.displaysectionstart(cfe({label="Role Permissions"}), page_info, header_level2) %> + + + + + + + +<% local rolecfe = cfe({ type="hidden", value="" }) %> +<% for i,role in ipairs(view.value.role) do %> + <% rolecfe.value = role.id %> + + + + + +<% end %> +
ActionRolePermissions
<% htmlviewfunctions.displayitem(cfe({type="link", value={role=rolecfe, redir=redir}, label="", option="Edit", action="editrolepermissions"}), page_info, -1) %><%= html.html_escape(role.id) %> + <% for y,allowed in pairs(role.allowed) do + print(html.html_escape(allowed), "
") + end %> +
+<% 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") +%> + + + + + + + +<% 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)) +%> + + + + + + + + +<% local filename = cfe({ type="hidden", value="" }) %> +<% local redir = cfe({ type="hidden", value=page_info.orig_action }) %> +<% for i,file in ipairs(form.value) do %> + + + + + + +<% end %> +
ActionSizeLast ModifiedFile
+ <% + 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 + %> + <%= html.html_escape(file.size or 0) %>b<%= format.formatfilesize(file.size) %><%= format.formattime(file.mtime) %><%= html.html_escape(string.gsub(file.filename, "^.*/", "")) %>
+<% 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 -- cgit v1.2.3