diff options
author | Alan Messias Cordeiro <alancordeiro@gmail.com> | 2013-12-09 15:25:50 +0000 |
---|---|---|
committer | Alan Messias Cordeiro <alancordeiro@gmail.com> | 2013-12-09 15:25:50 +0000 |
commit | 64522968bc69d1fa839c64874a543398cf759473 (patch) | |
tree | e5b5c3ae9dd0b5e741b3a673d4cffc63e0ea287d | |
download | acf-openldap-0.1.tar.bz2 acf-openldap-0.1.tar.xz |
Initial commitv0.1
-rw-r--r-- | openldap-controller.lua | 26 | ||||
l--------- | openldap-expert-html.lsp | 1 | ||||
-rw-r--r-- | openldap-listcerts-html.lsp | 41 | ||||
-rw-r--r-- | openldap-logfile-html.lsp | 6 | ||||
-rw-r--r-- | openldap-model.lua | 51 | ||||
-rw-r--r-- | openldap-model.lua.orig | 331 | ||||
l--------- | openldap-status-html.lsp | 1 | ||||
-rw-r--r-- | openldap-viewconfig-html.lsp | 77 | ||||
-rw-r--r-- | openldap.menu | 4 | ||||
-rw-r--r-- | openldap.roles | 3 |
10 files changed, 541 insertions, 0 deletions
diff --git a/openldap-controller.lua b/openldap-controller.lua new file mode 100644 index 0000000..4ba9a0c --- /dev/null +++ b/openldap-controller.lua @@ -0,0 +1,26 @@ +local mymodule = {} + +mymodule.mvc = {} +mymodule.mvc.on_load = function(self, parent) + self.model.set_processname("slapd") +end + +mymodule.default_action = "status" + +mymodule.status = function(self) + return self.model.getstatus() +end + +mymodule.startstop = function(self) + return self.handle_form(self, self.model.get_startstop, self.model.startstop_service, self.clientdata) +end + +mymodule.expert = function(self) + return self.handle_form(self, self.model.get_filecontent, self.model.update_filecontent, self.clientdata, "Save", "Edit Config File", "Config File Saved") +end + +mymodule.viewconfig = function(self) + return self.model.get_config() +end + +return mymodule diff --git a/openldap-expert-html.lsp b/openldap-expert-html.lsp new file mode 120000 index 0000000..207f324 --- /dev/null +++ b/openldap-expert-html.lsp @@ -0,0 +1 @@ +../expert-html.lsp
\ No newline at end of file diff --git a/openldap-listcerts-html.lsp b/openldap-listcerts-html.lsp new file mode 100644 index 0000000..e0043c0 --- /dev/null +++ b/openldap-listcerts-html.lsp @@ -0,0 +1,41 @@ +<% local view, viewlibrary, page_info, session = ... %> +<% htmlviewfunctions = require("htmlviewfunctions") %> +<% html = require("acf.html") %> + +<% htmlviewfunctions.displaycommandresults({"deletecert", "generatedhparams"}, session) %> +<% htmlviewfunctions.displaycommandresults({"uploadcert"}, session, true) %> + +<H1><%= html.html_escape(view.label) %></H1> + +<DL> +<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="white-space:nowrap;text-align:left;" class="header">Certificate</TD> + </TR> +<% for i,cert in ipairs(view.value) do %> + <TR> + <TD style="padding-right:20px;white-space:nowrap;"> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/deletecert?submit=true&cert="..cert.."&redir="..page_info.orig_action, label="Delete "} %> + <% if not string.find(cert, "%-key") then %> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/viewcert?cert="..cert.."&redir="..page_info.orig_action, label="View "} %> + <% end %> + </TD> + <TD style="white-space:nowrap;"><%= html.html_escape(cert) %></TD> + </TR> +<% end %> +</TABLE></DL> + +<% if viewlibrary.dispatch_component and viewlibrary.check_permission("uploadcert") then + viewlibrary.dispatch_component("uploadcert") +end %> + +<% if viewlibrary.check_permission("generatedhparams") then %> +<H1>Diffie Hellman Parameters</H1> +<DL> +<form action="<%= html.html_escape(page_info.script .. page_info.prefix .. page_info.controller .. "/generatedhparams") %>"> +<DT>Generate Diffie Hellman parameters</DT> +<DD><input class="submit" type="submit" name="submit" value="Generate"></DD> +</form> +</DL> +<% end %> diff --git a/openldap-logfile-html.lsp b/openldap-logfile-html.lsp new file mode 100644 index 0000000..d320dd1 --- /dev/null +++ b/openldap-logfile-html.lsp @@ -0,0 +1,6 @@ +<% local data, viewlibrary = ... +%> + +<% if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("alpine-baselayout/logfiles/view", {filename="/var/log/messages", grep="slapd"}) +end %> diff --git a/openldap-model.lua b/openldap-model.lua new file mode 100644 index 0000000..112dedb --- /dev/null +++ b/openldap-model.lua @@ -0,0 +1,51 @@ +local mymodule = {} + +modelfunctions = require("modelfunctions") +posix = require("posix") +format = require("acf.format") +fs = require("acf.fs") +processinfo = require("acf.processinfo") +validator = require("acf.validator") +date = require("acf.date") + +local processname = "slapd" +local packagename = "openldap" +local configfile = "/etc/openldap/slapd.conf" + +function mymodule.set_processname(p) + processname = p + configfile = "/etc/openldap/"..processname..".conf" +end + +local function log_content( f ) + return fs.read_file(f) or "" +end + +function mymodule.getstatus() + return modelfunctions.getstatus(processname, packagename, "OpenLDAP Status") +end + +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.get_logfile(f) + local config = log_content(configfile) + return cfe({ value=config.log or "", label="Log file" }) +end + +function mymodule.get_filecontent() + + return modelfunctions.getfiledetails(configfile) +end + +function mymodule.update_filecontent(self, filedetails) + + return modelfunctions.setfiledetails(self, filedetails, {configfile}) +end + +return mymodule diff --git a/openldap-model.lua.orig b/openldap-model.lua.orig new file mode 100644 index 0000000..1b0d830 --- /dev/null +++ b/openldap-model.lua.orig @@ -0,0 +1,331 @@ +local mymodule = {} + +modelfunctions = require("modelfunctions") +posix = require("posix") +format = require("acf.format") +fs = require("acf.fs") +processinfo = require("acf.processinfo") +validator = require("acf.validator") +date = require("acf.date") + +local processname = "slapd" +local packagename = "openldap" +local configfile = "/etc/openldap/slapd.conf" +local baseurl = "/etc/openldap/" + +function mymodule.set_processname(p) + processname = p + configfile = "/etc/openldap/"..processname..".conf" +end + +-- ################################################################################ +-- LOCAL FUNCTIONS + +local function config_content( f ) + local config = {} + local lines = format.parse_linesandwords(fs.read_file(f) or "", "[#;]") + -- there can be multiple entries + for i,linetable in ipairs(lines) do + if config[linetable[1]] then + config[linetable[1]] = config[linetable[1]] .. "\n" .. (table.concat(linetable, " ", 2) or "") + else + config[linetable[1]] = table.concat(linetable, " ", 2) or "" + end + end + + config.name = f + if config.remote then + config.remoteport = string.match ( config.remote, "^%S+%s+(%S*)" ) + end + if not ( config.log ) then + config.log = config["log-append"] + end + if not ( config["max-clients"] ) then + config["max-clients"] = "Unlimited" + end + if not ( config["local"] ) then + config["local"] = "0.0.0.0" + end + return config +end + +local function check_valid_config (config) + config.errtxt = nil + if not (config.client) or not (config.ca) or not (config.cert) or not (config.key) or not (config.dev) or not (config.proto) or not (config.remote) then + config.errtxt = "" + if not (config.ca) then + config.errtxt = config.errtxt .. "Check CA; " + end + if not (config.cert) then + config.errtxt = config.errtxt .. "Check CERT; " + end + if not (config.key) then + config.errtxt = config.errtxt .. "Check KEY; " + end + if not (config.dev) then + config.errtxt = config.errtxt .. "Check DEV; " + end + if not (config.proto) then + config.errtxt = config.errtxt .. "Check PROTO; " + end + if (config.client) or not (config.ca) or not (config.cert) or not (config.key) or not (config.dev) or not (config.proto) or not (config.port) then + config.type = nil + else + config.type = "server" + config.errtxt = nil + end + else + config.type = "client" + config.errtxt = nil + end + if not (config.type) then config.type = "unknown" end + return config.type, config.errtxt +end + +local function clientlist( statusfile ) + local clientlist = {} + local routinglist = {} + local datechange = {} + local list = {} + if (statusfile) then + local f = fs.read_file_as_array( statusfile ) + local clientlst = false + local routinglst = false + if ( f ) then + for k,v in ipairs(f) do + local col = format.string_to_table(v, ",") + if ( col[1] == "ROUTING TABLE" ) or ( col[1] == "GLOBAL STATS" ) then + clientlst = false + routinglst = false + end + if ( clientlst ) then + table.insert(clientlist, { CN=col[1], + REALADDR=col[2], + BYTESRCV=col[3], + BYTESSND=col[4], + CONN=col[5] } ) + end + if ( routinglst ) then + table.insert(routinglist, { VIRTADDR=col[1], + CN=col[2], + REALADDR=col[3], + LAST=col[4] } ) + if (col[4]) then + local month,day,hour,min,sec,year = string.match(col[4],"^%S+%s+(%S+)%s+(%S+)%s+(%d%d):(%d%d):(%d%d)%s+(%S+)") + table.insert(datechange, { year=year, + month=date.abr_month_num(month), + day=day, + hour=hour, + min=min, + sec=sec } ) + end + end + if ( col[1] == "Virtual Address" ) then + routinglst = true + end + if ( col[1] == "Common Name" ) then + clientlst = true + end + + end + end + end + -- JOIN 'CLIENT_LIST' and 'ROUTING_LIST' TABLES INTO ONE TABLE AND LATER ON PRESENT THIS TABLE + for k,v in ipairs(clientlist) do + for kk,vv in ipairs(routinglist) do + if ( v.CN == vv.CN ) then + table.insert(list, { CN=v.CN, REALADDR=v.REALADDR, BYTESRCV=v.BYTESRCV, BYTESSND=v.BYTESSND, VIRTADDR=vv.VIRTADDR, CONN=v.CONN, LAST = LAST } ) + end + end + end + local lastdatechangetxt, lastdatechangediff + if ((#clientlist > 0) and (#datechange > 0)) then + local lastdatechange = date.date_to_seconds(datechange) + lastdatechangetxt = os.date("%c", lastdatechange[#lastdatechange]) + lastdatechangediff = os.time() - os.date(lastdatechange[#lastdatechange]) + if (lastdatechangediff > 60) then + lastdatechangediff = math.modf(lastdatechangediff / 60) .. " min" + else + lastdatechangediff = lastdatechangediff .. " sec" + end + end + return list, #clientlist, lastdatechangetxt, lastdatechangediff +end + +-- ################################################################################ +-- PUBLIC FUNCTIONS + +function mymodule.getstatus() + return modelfunctions.getstatus(processname, packagename, "OpenLDAP Status") +end + +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.getclientinfo() + local config = config_content(configfile) + return cfe({ type="structure", value=clientlist(config.status), label="Client info" }) +end + +function mymodule.get_config() + local config = config_content(configfile) + check_valid_config(config) + if config.type == "server" then + local clientlist, client_count, client_lastupdate, client_lastdatechangediff = clientlist(config.status) + config["client_lastupdate"] = client_lastupdate or "?" + config["client_lastdatechangediff"] = client_lastdatechangediff or "? min" + config["client_count"] = client_count or 0 + end + return cfe({ type="structure", value=config, label="OpenVPN Config" }) +end + +function mymodule.get_logfile(f) + local config = config_content(configfile) + return cfe({ value=config.log or "", label="Log file" }) +end + +function mymodule.get_filecontent() + --FIXME validate + return modelfunctions.getfiledetails(configfile) +end + +function mymodule.update_filecontent(self, filedetails) + --FIXME validate + return modelfunctions.setfiledetails(self, filedetails, {configfile}) +end + +function mymodule.list_certs() + local list = {} + for file in fs.find(".*%.pem", certurl) do + list[#list+1] = file + end + return cfe({ type="list", value=list, label="OpenVPN Certificates" }) +end + +function mymodule.get_delete_cert(self, clientdata) + local retval = {} + retval.cert = cfe({ value=clientdata.cert or "", label="Certificate Local Name" }) + return cfe({ type="group", value=retval, label="Delete Certificate" }) +end + +function mymodule.delete_cert(self, delcert) + local list = mymodule.list_certs() + delcert.value.cert.errtxt = "Invalid cert name" + delcert.errtxt = "Failed to delete certificate" + for i,cert in ipairs(list.value) do + if cert == delcert.value.cert.value then + os.remove(cert) + delcert.value.cert.errtxt = nil + delcert.errtxt = nil + break + end + end + return delcert +end + +function mymodule.new_upload_cert() + local value = {} + value.cert = cfe({ type="raw", value=0, label="Certificate", descr='File must be a password protected ".pfx" file' }) + value.password = cfe({ label="Certificate Password" }) + value.name = cfe({ label="Certificate Local Name" }) + return cfe({ type="group", value=value }) +end + +function mymodule.upload_cert(self, newcert) + local success = true + -- Trying to upload a cert/key + -- The way haserl works, cert contains the temporary file name + -- First, get the cert + local cmd, f, cmdresult, errtxt + if validator.is_valid_filename(newcert.value.cert.value, "/tmp/") and fs.is_file(newcert.value.cert.value) then + cmdresult, errtxt = modelfunctions.run_executable({"openssl", "pkcs12", "-in", newcert.value.cert.value, "-out", newcert.value.cert.value.."cert.pem", "-password", "pass:"..newcert.value.password.value, "-nokeys", "-clcerts"}, true) + local filestats = posix.stat(newcert.value.cert.value.."cert.pem") + if not filestats or filestats.size == 0 then + newcert.value.cert.errtxt = "Could not open certificate\n"..(errtxt or cmdresult) + success = false + end + else + newcert.value.cert.errtxt = "Invalid certificate" + success = false + end + + -- Now, get the key and the ca certs + if success then + cmdresult, errtxt = modelfunctions.run_executable({"openssl", "pkcs12", "-in", newcert.value.cert.value, "-out", newcert.value.cert.value.."key.pem", "-password", "pass:"..newcert.value.password.value, "-nocerts", "-nodes"}, true) + filestats = posix.stat(newcert.value.cert.value.."key.pem") + if not filestats or filestats.size == 0 then + newcert.value.cert.errtxt = "Could not find key\n"..(errtxt or cmdresult) + success = false + end + + cmdresult, errtxt = modelfunctions.run_executable({"openssl", "pkcs12", "-in", newcert.value.cert.value, "-out", newcert.value.cert.value.."ca.pem", "-password", "pass:"..newcert.value.password.value, "-nokeys", "-cacerts"}, true) + filestats = posix.stat(newcert.value.cert.value.."ca.pem") + if not filestats or filestats.size == 0 then + newcert.value.cert.errtxt = "Could not find CA certs\n"..(errtxt or cmdresult) + success = false + end + end + + if newcert.value.name.value == "" then + newcert.value.name.errtxt = "Cannot be blank" + success = false + elseif posix.stat(certurl..newcert.value.name.value.."-cert.pem") or posix.stat(certurl..newcert.value.name.value.."-key.pem") or posix.stat(certurl..newcert.value.name.value.."-ca.pem") then + newcert.value.name.errtxt = "Certificate of this name already exists" + success = false + end + + if success then + if not posix.stat(certurl) then + fs.create_directory(certurl) + end + -- copy the keys + fs.move_file(newcert.value.cert.value.."cert.pem", certurl..newcert.value.name.value.."-cert.pem") + fs.move_file(newcert.value.cert.value.."key.pem", certurl..newcert.value.name.value.."-key.pem") + fs.move_file(newcert.value.cert.value.."ca.pem", certurl..newcert.value.name.value.."-ca.pem") + posix.chmod(certurl..newcert.value.name.value.."-key.pem", "rw-------") + else + newcert.errtxt = "Failed to upload certificate" + end + + -- Delete the temporary files + if validator.is_valid_filename(newcert.value.cert.value, "/tmp/") and fs.is_file(newcert.value.cert.value) then + os.remove(newcert.value.cert.value.."cert.pem") + os.remove(newcert.value.cert.value.."key.pem") + os.remove(newcert.value.cert.value.."ca.pem") + end + + return newcert +end + +mymodule.view_cert = function(certname) + local cmdresult = "Invalid cert name" + local errtxt + if not string.find(certname, "/") then + certname = certurl..certname + end + if validator.is_valid_filename(certname, certurl) or validator.is_valid_filename(certname, baseurl) then + cmdresult, errtxt = modelfunctions.run_executable({"openssl", "x509", "-in", certname, "-noout", "-text"}) + cmdresult = cmdresult .. "Content:\n" .. (fs.read_file(certname) or "") + end + return cfe({ type="table", value={name=certname, value=cmdresult}, label="Certificate", errtxt=errtxt }) +end + +mymodule.get_generate_dh_params = function(self, clientdata) + local retval = {} + return cfe({ type="group", value=retval, label="Generate Diffie Hellman parameters" }) +end + +mymodule.generate_dh_params = function(self, gen) + if not posix.stat(certurl) then + fs.create_directory(certurl) + end + gen.descr, gen.errtxt = modelfunctions.run_executable({"openssl", "dhparam", "-out", certurl.."dh1024.pem", "1024"}, true) + return gen +end + +return mymodule diff --git a/openldap-status-html.lsp b/openldap-status-html.lsp new file mode 120000 index 0000000..b2f8480 --- /dev/null +++ b/openldap-status-html.lsp @@ -0,0 +1 @@ +../status-html.lsp
\ No newline at end of file diff --git a/openldap-viewconfig-html.lsp b/openldap-viewconfig-html.lsp new file mode 100644 index 0000000..5b76598 --- /dev/null +++ b/openldap-viewconfig-html.lsp @@ -0,0 +1,77 @@ +<% local view, viewlibrary, page_info, session = ... %> +<% format = require("acf.format") %> +<% html = require("acf.html") %> +<% local shortname = string.gsub(view.value.name, "^.*/", "") %> + +<h1><%= html.html_escape(format.cap_begin_word(view.value.type)) %> Config</h1> + +<h2><%= html.html_escape(format.cap_begin_word(view.value.type)) %> settings</h2> +<dl> +<dt>Mode</dt> +<dd><%= html.html_escape(view.value.type) %></dd> + +<dt>User device</dt> +<dd><%= html.html_escape(view.value.dev) %></dd> + +<% if view.value.type == "server" then %> +<dt>Listens on</dt> +<dd><%= html.html_escape(view.value["local"]) %>:<%= html.html_escape(view.value.port) %> (<%= html.html_escape(view.value.proto) %>)</dd> +<% end %> + +<% if view.value.type == "client" then %> +<dt>Remote server</dt> +<dd><% if string.find(view.value.remote, "%s") then io.write(html.html_escape(string.gsub(view.value.remote, "%s+", ":"))) else io.write(html.html_escape(view.value.remote .. (view.value.rport or view.value.port or "1194"))) end %> (<%= html.html_escape(view.value.proto) %>)</dd> +<% end %> + +<dt>Logfile</dt> +<dd><% if ( view.value.log ) then %><%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/logfile?name=" .. view.value.name, label=view.value.log } %><% else %>Syslog<% end %> (Verbosity level: <%= html.html_escape(view.value.verb) %>)</dd> +</dl> + +<% if view.value.type == "server" then %> +<h3>Connected clients status</h3> +<dl> +<dt>Last status was recorded</dt> +<dd><%= html.html_escape(view.value.client_lastupdate) %> (This was <b><%= html.html_escape(view.value.client_lastdatechangediff) %></b> ago)</dd> + +<dt>Maximum clients</dt> +<dd><%= html.html_escape(view.value["max-clients"]) %></dd> + +<dt>Connected clients</dt> +<dd><%= html.html_escape(view.value.client_count) %></dd> +</dl> +<% end %> + +<% if view.value.dh or view.value.ca or view.value.cert or view.value.key or view.value.tls or view.value.crl then %> +<h2>Certificate files</h2> +<dl> +<% if (view.value.dh) then %> +<dt>DH</dt> +<dd><%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/viewcert?cert=" .. view.value.dh, label=view.value.dh } %></dd> +<% end %> + +<% if (view.value.ca) then %> +<dt>CA Certificate</dt> +<dd><%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/viewcert?cert=" .. view.value.ca, label=view.value.ca } %></dd> +<% end %> + +<% if (view.value.cert) then %> +<dt>Certificate</dt> +<dd><%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/viewcert?cert=" .. view.value.cert, label=view.value.cert } %></dd> +<% end %> + +<% if (view.value.key) then %> +<dt>Private Key</dt> +<dd><%= html.html_escape(view.value.key) %></dd> +<% end %> + +<% if (view.value.tls) then %> +<dt>TLS Authentication</dt> +<dd><%= html.html_escape(view.value.tls) %><% -- html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/pem_info?name=" .. view.value.tls , label=view.value.tls } %></dd> +<% end %> + +<% if (view.value.crl) then %> +<dt>CRL Verify File</dt> +<dd><%= html.html_escape(view.value.crl) %><% -- html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/pem_info?name=" .. view.value.crl , label=view.value.crl } %></dd> +<% end %> +</dl> +<% end %> diff --git a/openldap.menu b/openldap.menu new file mode 100644 index 0000000..4ebd263 --- /dev/null +++ b/openldap.menu @@ -0,0 +1,4 @@ +#CAT GROUP/DESC TAB ACTION +Networking 65OpenLDAP Status status +Networking 65OpenLDAP Expert expert +Networking 65OpenLDAP Log_File logfile diff --git a/openldap.roles b/openldap.roles new file mode 100644 index 0000000..6d275ce --- /dev/null +++ b/openldap.roles @@ -0,0 +1,3 @@ +USER=openldap:status,openldap:logfile,openldap:viewconfig,openldap:startstop +EXPERT=openldap:expert,openldap:listcerts,openldap:deletecert,openldap:uploadcert,openldap:viewcert,openldap:generatedhparams +ADMIN=openldap:status,openldap:logfile,openldap:viewconfig,openldap:startstop,openldap:expert,openldap:listcerts,openldap:deletecert,openldap:uploadcert,openldap:viewcert,openldap:generatedhparams |