From 64522968bc69d1fa839c64874a543398cf759473 Mon Sep 17 00:00:00 2001 From: Alan Messias Cordeiro Date: Mon, 9 Dec 2013 15:25:50 +0000 Subject: Initial commit --- openldap-controller.lua | 26 ++++ openldap-expert-html.lsp | 1 + openldap-listcerts-html.lsp | 41 ++++++ openldap-logfile-html.lsp | 6 + openldap-model.lua | 51 +++++++ openldap-model.lua.orig | 331 +++++++++++++++++++++++++++++++++++++++++++ openldap-status-html.lsp | 1 + openldap-viewconfig-html.lsp | 77 ++++++++++ openldap.menu | 4 + openldap.roles | 3 + 10 files changed, 541 insertions(+) create mode 100644 openldap-controller.lua create mode 120000 openldap-expert-html.lsp create mode 100644 openldap-listcerts-html.lsp create mode 100644 openldap-logfile-html.lsp create mode 100644 openldap-model.lua create mode 100644 openldap-model.lua.orig create mode 120000 openldap-status-html.lsp create mode 100644 openldap-viewconfig-html.lsp create mode 100644 openldap.menu create mode 100644 openldap.roles 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) %> + +

<%= html.html_escape(view.label) %>

+ +
+ + + + + +<% for i,cert in ipairs(view.value) do %> + + + + +<% end %> +
ActionCertificate
+ <%= 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 %> + <%= html.html_escape(cert) %>
+ +<% if viewlibrary.dispatch_component and viewlibrary.check_permission("uploadcert") then + viewlibrary.dispatch_component("uploadcert") +end %> + +<% if viewlibrary.check_permission("generatedhparams") then %> +

Diffie Hellman Parameters

+
+
"> +
Generate Diffie Hellman parameters
+
+
+
+<% 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, "^.*/", "") %> + +

<%= html.html_escape(format.cap_begin_word(view.value.type)) %> Config

+ +

<%= html.html_escape(format.cap_begin_word(view.value.type)) %> settings

+
+
Mode
+
<%= html.html_escape(view.value.type) %>
+ +
User device
+
<%= html.html_escape(view.value.dev) %>
+ +<% if view.value.type == "server" then %> +
Listens on
+
<%= html.html_escape(view.value["local"]) %>:<%= html.html_escape(view.value.port) %> (<%= html.html_escape(view.value.proto) %>)
+<% end %> + +<% if view.value.type == "client" then %> +
Remote server
+
<% 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) %>)
+<% end %> + +
Logfile
+
<% 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) %>)
+
+ +<% if view.value.type == "server" then %> +

Connected clients status

+
+
Last status was recorded
+
<%= html.html_escape(view.value.client_lastupdate) %> (This was <%= html.html_escape(view.value.client_lastdatechangediff) %> ago)
+ +
Maximum clients
+
<%= html.html_escape(view.value["max-clients"]) %>
+ +
Connected clients
+
<%= html.html_escape(view.value.client_count) %>
+
+<% 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 %> +

Certificate files

+
+<% if (view.value.dh) then %> +
DH
+
<%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/viewcert?cert=" .. view.value.dh, label=view.value.dh } %>
+<% end %> + +<% if (view.value.ca) then %> +
CA Certificate
+
<%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/viewcert?cert=" .. view.value.ca, label=view.value.ca } %>
+<% end %> + +<% if (view.value.cert) then %> +
Certificate
+
<%= html.link{value = page_info.script .. page_info.prefix .. page_info.controller .. "/viewcert?cert=" .. view.value.cert, label=view.value.cert } %>
+<% end %> + +<% if (view.value.key) then %> +
Private Key
+
<%= html.html_escape(view.value.key) %>
+<% end %> + +<% if (view.value.tls) then %> +
TLS Authentication
+
<%= 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 } %>
+<% end %> + +<% if (view.value.crl) then %> +
CRL Verify File
+
<%= 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 } %>
+<% end %> +
+<% 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 -- cgit v1.2.3