module(..., package.seeall)
-- Load libraries
require("modelfunctions")
require("fs")
require("format")
-- Set variables
local configfile = "/etc/racoon/racoon.conf"
local configfile2 = "/etc/ipsec.conf"
local processname = "racoon"
local packagename = "ipsec-tools"
local baseurl = "/etc/racoon/"
local path = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin "
local descr = {
state={
['9']="Established",
},
side={
['R']="We are 'Responder'.",
['I']="We 'Initiated' this phase1",
},
exchange={
['M']="Main mode",
['A']="Agressive mode",
['B']="Basic mode",
},
}
-- ################################################################################
-- LOCAL FUNCTIONS
local function ip_xfrm(mode)
local cmd_output_result
local cmd = "/bin/ip xfrm " .. mode .. " 2>/dev/null"
local f = io.popen( cmd )
local cmd_output_result = f:read("*a")
f:close()
return cmd_output_result
end
local function phase2details(dst)
local output = {}
dst = string.match(dst,"^(.*)%.") -- Removes the portnumber
table.insert(output, {label="Outgoing", value=ip_xfrm("state list src ".. dst .. " | grep '^src'")})
table.insert(output, {label="Incoming", value=ip_xfrm("state list dst ".. dst .. " | grep '^src'")})
return output
end
local function racoonctl_table()
local output = {}
local cmd = "/usr/sbin/racoonctl -lll show-sa isakmp 2>/dev/null"
local f = io.popen( cmd )
local value = f:read("*a")
f:close()
for i,line in pairs(format.string_to_table(value,"\n")) do
if not ((string.find(line,"^Source")) or (#line == 0)) then
entry={}
local variable=format.string_to_table(line,"%s+")
entry['Source']=cfe({
label="Source",
value=variable[1],
})
entry['Destination']=cfe({
label="Destination",
value=variable[2],
})
entry['Cookies']=cfe({
label="Cookies",
value=variable[3],
})
entry['St']=cfe({
label="State",
value=variable[4],
descr=descr.state[variable[4]],
})
entry['S']=cfe({
label="Side",
value=variable[5],
descr=descr.side[variable[5]],
})
entry['V']=cfe({
label="Version",
value=variable[6],
})
entry['E']=cfe({
label="Exchange",
value=variable[7],
descr=descr.exchange[variable[7]],
})
entry['Created']=cfe({
label="Created",
value=(variable[8] or "") .. " " .. (variable[9] or ""),
})
local phase2s = phase2details(variable[2])
entry['Phase2']=cfe({
label="Phase2",
value=variable[10],
option=phase2s,
})
entry['Phase2details']=cfe({
label="Phase2details",
value=tostring(string.gsub(phase2s[1]['value'],"\n","
")) .. tostring(string.gsub(phase2s[2]['value'],"\n","
"))
})
output[#output + 1] = entry
end
end
return output
end
-- ################################################################################
-- PUBLIC FUNCTIONS
function startstop_service(action)
return modelfunctions.startstop_service(processname, action)
end
function getstatus()
return modelfunctions.getstatus(processname, packagename, "Racoon Status")
end
function getstatusdetails()
local status = {}
status.show_isakmp = cfe({ type="list", value=racoonctl_table(), label="Tunnels" })
status.ip_xfrm_policy = cfe({ type="longtext", value=ip_xfrm("policy"), label="ip xfrm policy" })
return cfe({ type="group", value=status, label="Racoon Status Details" })
end
function get_racoonfiledetails()
return modelfunctions.getfiledetails(configfile)
end
function update_racoonfiledetails(filedetails)
return modelfunctions.setfiledetails(filedetails, {configfile})
end
function get_ipsecfiledetails()
return modelfunctions.getfiledetails(configfile2)
end
function update_ipsecfiledetails(filedetails)
return modelfunctions.setfiledetails(filedetails, {configfile2})
end
function list_certs()
local list = {}
for file in fs.find(".*%.pem", baseurl) do
list[#list+1] = basename(file)
end
return cfe({ type="list", value=list, label="IPSEC Certificates" })
end
function delete_cert(certname)
local list = list_certs()
local retval = cfe({ label="Delete Certificate result", errtxt="Invalid cert name" })
for i,cert in ipairs(list.value) do
if cert == certname then
os.remove(baseurl..certname)
retval.value = "Certificate deleted"
retval.errtxt = nil
break
end
end
return retval
end
function 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 upload_cert(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 = path .. "openssl pkcs12 -in "..newcert.value.cert.value.." -out "..newcert.value.cert.value.."cert.pem -password pass:"..newcert.value.password.value.." -nokeys -clcerts 2>&1"
local f = io.popen(cmd)
local cmdresult = f:read("*a")
f:close()
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"..cmdresult
success = false
end
-- Now, get the key and the ca certs
if success then
cmd = path .. "openssl pkcs12 -in "..newcert.value.cert.value.." -out "..newcert.value.cert.value.."key.pem -password pass:"..newcert.value.password.value.." -nocerts -nodes 2>&1"
f = io.popen(cmd)
cmdresult = f:read("*a")
f:close()
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"..cmdresult
success = false
end
cmd = path .. "openssl pkcs12 -in "..newcert.value.cert.value.." -out "..newcert.value.cert.value.."ca.pem -password pass:"..newcert.value.password.value.." -nokeys -cacerts 2>&1"
f = io.popen(cmd)
cmdresult = f:read("*a")
f:close()
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"..cmdresult
success = false
end
end
if newcert.value.name.value == "" then
newcert.value.name.errtxt = "Cannot be blank"
success = false
elseif posix.stat(baseurl..newcert.value.name.value.."-cert.pem") or posix.stat(baseurl..newcert.value.name.value.."-key.pem") or posix.stat(baseurl..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(baseurl) then
posix.mkdir(baseurl)
end
-- copy the keys
os.rename(newcert.value.cert.value.."cert.pem", baseurl..newcert.value.name.value.."-cert.pem")
os.rename(newcert.value.cert.value.."key.pem", baseurl..newcert.value.name.value.."-key.pem")
os.rename(newcert.value.cert.value.."ca.pem", baseurl..newcert.value.name.value.."-ca.pem")
posix.chmod(baseurl..newcert.value.name.value.."-key.pem", "rw-------")
else
newcert.errtxt = "Failed to upload certificate"
end
-- Delete the temporary files
cmd = "rm "..newcert.value.cert.value.."*"
f = io.popen(cmd)
f:close()
return newcert
end
view_cert = function(certname)
local list = list_certs()
local cmdresult = "Invalid cert name"
for i,cert in ipairs(list.value) do
if cert == certname then
local cmd = path .. "openssl x509 -in "..baseurl..certname.." -noout -text"
local f = io.popen(cmd)
cmdresult = f:read("*a")
f:close()
end
end
return cfe({ type="table", value={name=certname, value=cmdresult}, label="Certificate" })
end