aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/certmanager.lua2
-rw-r--r--core/configmanager.lua45
-rw-r--r--core/moduleapi.lua3
-rw-r--r--plugins/mod_admin_telnet.lua88
-rw-r--r--plugins/mod_s2s/mod_s2s.lua12
-rw-r--r--plugins/mod_storage_sql.lua2
-rw-r--r--plugins/mod_storage_sql2.lua2
-rwxr-xr-xprosodyctl122
-rw-r--r--tools/jabberd14sql2prosody.lua2
-rw-r--r--util-src/pposix.c12
-rw-r--r--util/dataforms.lua9
-rw-r--r--util/indexedbheap.lua18
-rw-r--r--util/paths.lua38
-rw-r--r--util/x509.lua23
14 files changed, 260 insertions, 118 deletions
diff --git a/core/certmanager.lua b/core/certmanager.lua
index 74da771e..d6a59b9f 100644
--- a/core/certmanager.lua
+++ b/core/certmanager.lua
@@ -19,7 +19,7 @@ local t_concat = table.concat;
local t_insert = table.insert;
local prosody = prosody;
-local resolve_path = configmanager.resolve_relative_path;
+local resolve_path = require"util.paths".resolve_relative_path;
local config_path = prosody.paths.config;
local luasec_has_noticket, luasec_has_verifyext, luasec_has_no_compression;
diff --git a/core/configmanager.lua b/core/configmanager.lua
index d92120d0..1f7342b2 100644
--- a/core/configmanager.lua
+++ b/core/configmanager.lua
@@ -14,11 +14,15 @@ local format, math_max = string.format, math.max;
local fire_event = prosody and prosody.events.fire_event or function () end;
local envload = require"util.envload".envload;
-local lfs = require "lfs";
+local deps = require"util.dependencies";
+local resolve_relative_path = require"util.paths".resolve_relative_path;
+local glob_to_pattern = require"util.paths".glob_to_pattern;
local path_sep = package.config:sub(1,1);
module "configmanager"
+_M.resolve_relative_path = resolve_relative_path; -- COMPAT
+
local parsers = {};
local config_mt = { __index = function (t, k) return rawget(t, "*"); end};
@@ -66,41 +70,6 @@ function _M.set(host, key, value, _oldvalue)
return set(config, host, key, value);
end
--- Helper function to resolve relative paths (needed by config)
-do
- function resolve_relative_path(parent_path, path)
- if path then
- -- Some normalization
- parent_path = parent_path:gsub("%"..path_sep.."+$", "");
- path = path:gsub("^%.%"..path_sep.."+", "");
-
- local is_relative;
- if path_sep == "/" and path:sub(1,1) ~= "/" then
- is_relative = true;
- elseif path_sep == "\\" and (path:sub(1,1) ~= "/" and (path:sub(2,3) ~= ":\\" and path:sub(2,3) ~= ":/")) then
- is_relative = true;
- end
- if is_relative then
- return parent_path..path_sep..path;
- end
- end
- return path;
- end
-end
-
--- Helper function to convert a glob to a Lua pattern
-local function glob_to_pattern(glob)
- return "^"..glob:gsub("[%p*?]", function (c)
- if c == "*" then
- return ".*";
- elseif c == "?" then
- return ".";
- else
- return "%"..c;
- end
- end).."$";
-end
-
function load(filename, format)
format = format or filename:match("%w+$");
@@ -214,6 +183,10 @@ do
function env.Include(file)
if file:match("[*?]") then
+ local lfs = deps.softreq "lfs";
+ if not lfs then
+ error(format("Error expanding wildcard pattern in Include %q - LuaFileSystem not available", file));
+ end
local path_pos, glob = file:match("()([^"..path_sep.."]+)$");
local path = file:sub(1, math_max(path_pos-2,0));
local config_path = config_file:gsub("[^"..path_sep.."]+$", "");
diff --git a/core/moduleapi.lua b/core/moduleapi.lua
index 5a24f69c..30d28418 100644
--- a/core/moduleapi.lua
+++ b/core/moduleapi.lua
@@ -13,6 +13,7 @@ local set = require "util.set";
local logger = require "util.logger";
local pluginloader = require "util.pluginloader";
local timer = require "util.timer";
+local resolve_relative_path = require"util.paths".resolve_relative_path;
local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat;
local error, setmetatable, type = error, setmetatable, type;
@@ -380,7 +381,7 @@ function api:get_directory()
end
function api:load_resource(path, mode)
- path = config.resolve_relative_path(self:get_directory(), path);
+ path = resolve_relative_path(self:get_directory(), path);
return io.open(path, mode);
end
diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua
index 71dfa300..9761d2f3 100644
--- a/plugins/mod_admin_telnet.lua
+++ b/plugins/mod_admin_telnet.lua
@@ -154,6 +154,14 @@ function console_listener.onincoming(conn, data)
session.partial_data = data:match("[^\n]+$");
end
+function console_listener.onreadtimeout(conn)
+ local session = sessions[conn];
+ if session then
+ session.send("\0");
+ return true;
+ end
+end
+
function console_listener.ondisconnect(conn, err)
local session = sessions[conn];
if session then
@@ -212,9 +220,11 @@ function commands.help(session, data)
print [[c2s:show(jid) - Show all client sessions with the specified JID (or all if no JID given)]]
print [[c2s:show_insecure() - Show all unencrypted client connections]]
print [[c2s:show_secure() - Show all encrypted client connections]]
+ print [[c2s:show_tls() - Show TLS cipher info for encrypted sessions]]
print [[c2s:close(jid) - Close all sessions for the specified JID]]
elseif section == "s2s" then
print [[s2s:show(domain) - Show all s2s connections for the given domain (or all if no domain given)]]
+ print [[s2s:show_tls(domain) - Show TLS cipher info for encrypted sessions]]
print [[s2s:close(from, to) - Close a connection from one domain to another]]
print [[s2s:closeall(host) - Close all the incoming/outgoing s2s sessions to specified host]]
elseif section == "module" then
@@ -471,22 +481,28 @@ function def_env.config:reload()
return ok, (ok and "Config reloaded (you may need to reload modules to take effect)") or tostring(err);
end
-def_env.hosts = {};
-function def_env.hosts:list()
- for host, host_session in pairs(hosts) do
- self.session.print(host);
+local function common_info(session, line)
+ if session.id then
+ line[#line+1] = "["..session.id.."]"
+ else
+ line[#line+1] = "["..session.type..(tostring(session):match("%x*$")).."]"
end
- return true, "Done";
-end
-
-function def_env.hosts:add(name)
end
local function session_flags(session, line)
line = line or {};
+ common_info(session, line);
+ if session.type == "c2s" then
+ local status, priority = "unavailable", tostring(session.priority or "-");
+ if session.presence then
+ status = session.presence:get_child_text("show") or "available";
+ end
+ line[#line+1] = status.."("..priority..")";
+ end
if session.cert_identity_status == "valid" then
- line[#line+1] = "(secure)";
- elseif session.secure then
+ line[#line+1] = "(authenticated)";
+ end
+ if session.secure then
line[#line+1] = "(encrypted)";
end
if session.compressed then
@@ -501,6 +517,23 @@ local function session_flags(session, line)
return table.concat(line, " ");
end
+local function tls_info(session, line)
+ line = line or {};
+ common_info(session, line);
+ if session.secure then
+ local sock = session.conn and session.conn.socket and session.conn:socket();
+ if sock and sock.info then
+ local info = sock:info();
+ line[#line+1] = ("(%s with %s)"):format(info.protocol, info.cipher);
+ else
+ line[#line+1] = "(cipher info unavailable)";
+ end
+ else
+ line[#line+1] = "(insecure)";
+ end
+ return table.concat(line, " ");
+end
+
def_env.c2s = {};
local function show_c2s(callback)
@@ -524,8 +557,9 @@ function def_env.c2s:count(match_jid)
return true, "Total: "..count.." clients";
end
-function def_env.c2s:show(match_jid)
+function def_env.c2s:show(match_jid, annotate)
local print, count = self.session.print, 0;
+ annotate = annotate or session_flags;
local curr_host;
show_c2s(function (jid, session)
if curr_host ~= session.host then
@@ -534,11 +568,7 @@ function def_env.c2s:show(match_jid)
end
if (not match_jid) or jid:match(match_jid) then
count = count + 1;
- local status, priority = "unavailable", tostring(session.priority or "-");
- if session.presence then
- status = session.presence:get_child_text("show") or "available";
- end
- print(session_flags(session, { " "..jid.." - "..status.."("..priority..")" }));
+ print(annotate(session, { " ", jid }));
end
end);
return true, "Total: "..count.." clients";
@@ -566,6 +596,10 @@ function def_env.c2s:show_secure(match_jid)
return true, "Total: "..count.." secure client connections";
end
+function def_env.c2s:show_tls(match_jid)
+ return self:show(match_jid, tls_info);
+end
+
function def_env.c2s:close(match_jid)
local count = 0;
show_c2s(function (jid, session)
@@ -579,8 +613,9 @@ end
def_env.s2s = {};
-function def_env.s2s:show(match_jid)
+function def_env.s2s:show(match_jid, annotate)
local print = self.session.print;
+ annotate = annotate or session_flags;
local count_in, count_out = 0,0;
local s2s_list = { };
@@ -598,8 +633,7 @@ function def_env.s2s:show(match_jid)
remotehost, localhost = session.from_host or "?", session.to_host or "?";
end
local sess_lines = { l = localhost, r = remotehost,
- session_flags(session, { "", direction, remotehost or "?",
- "["..session.type..tostring(session):match("[a-f0-9]*$").."]" })};
+ annotate(session, { "", direction, remotehost or "?" })};
if (not match_jid) or remotehost:match(match_jid) or localhost:match(match_jid) then
table.insert(s2s_list, sess_lines);
@@ -654,6 +688,10 @@ function def_env.s2s:show(match_jid)
return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections";
end
+function def_env.s2s:show_tls(match_jid)
+ return self:show(match_jid, tls_info);
+end
+
local function print_subject(print, subject)
for _, entry in ipairs(subject) do
print(
@@ -823,9 +861,19 @@ end
function def_env.host:list()
local print = self.session.print;
local i = 0;
+ local type;
for host in values(array.collect(keys(prosody.hosts)):sort()) do
i = i + 1;
- print(host);
+ type = hosts[host].type;
+ if type == "local" then
+ print(host);
+ else
+ type = module:context(host):get_option_string("component_module", type);
+ if type ~= "component" then
+ type = type .. " component";
+ end
+ print(("%s (%s)"):format(host, type));
+ end
end
return true, i.." hosts";
end
diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua
index 73d95970..263f24c0 100644
--- a/plugins/mod_s2s/mod_s2s.lua
+++ b/plugins/mod_s2s/mod_s2s.lua
@@ -150,6 +150,13 @@ function module.add_host(module)
module:hook("route/remote", route_to_new_session, -10);
module:hook("s2s-authenticated", make_authenticated, -1);
module:hook("s2s-read-timeout", keepalive, -1);
+ module:hook_stanza("http://etherx.jabber.org/streams", "features", function (session, stanza)
+ if session.type == "s2sout" then
+ -- Stream is authenticated and we are seem to be done with feature negotiation,
+ -- so the stream is ready for stanzas. RFC 6120 Section 4.3
+ mark_connected(session);
+ end
+ end, -1);
end
-- Stream is authorised, and ready for normal stanzas
@@ -219,7 +226,10 @@ function make_authenticated(event)
end
session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host);
- mark_connected(session);
+ if (session.type == "s2sout" and session.external_auth ~= "succeeded") or session.type == "s2sin" then
+ -- Stream either used dialback for authentication or is an incoming stream.
+ mark_connected(session);
+ end
return true;
end
diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua
index 1f453d42..7b810ab8 100644
--- a/plugins/mod_storage_sql.lua
+++ b/plugins/mod_storage_sql.lua
@@ -49,7 +49,7 @@ local function db2uri(params)
end
-local resolve_relative_path = require "core.configmanager".resolve_relative_path;
+local resolve_relative_path = require "util.paths".resolve_relative_path;
local function test_connection()
if not connection then return nil; end
diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua
index 7414e5ed..249c72a7 100644
--- a/plugins/mod_storage_sql2.lua
+++ b/plugins/mod_storage_sql2.lua
@@ -2,7 +2,7 @@
local json = require "util.json";
local xml_parse = require "util.xml".parse;
local uuid = require "util.uuid";
-local resolve_relative_path = require "core.configmanager".resolve_relative_path;
+local resolve_relative_path = require "util.paths".resolve_relative_path;
local stanza_mt = require"util.stanza".stanza_mt;
local getmetatable = getmetatable;
diff --git a/prosodyctl b/prosodyctl
index 00aeac40..d9ae9b73 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -797,8 +797,28 @@ function commands.check(arg)
local array, set = require "util.array", require "util.set";
local it = require "util.iterators";
local ok = true;
+ local function disabled_hosts(host, conf) return host ~= "*" and conf.enabled ~= false; end
+ local function enabled_hosts() return it.filter(disabled_hosts, pairs(config.getconfig())); end
+ if not what or what == "disabled" then
+ local disabled_hosts = set.new();
+ for host, host_options in it.filter("*", pairs(config.getconfig())) do
+ if host_options.enabled == false then
+ disabled_hosts:add(host);
+ end
+ end
+ if not disabled_hosts:empty() then
+ local msg = "Checks will be skipped for these disabled hosts: %s";
+ if what then msg = "These hosts are disabled: %s"; end
+ show_warning(msg, tostring(disabled_hosts));
+ if what then return 0; end
+ print""
+ end
+ end
if not what or what == "config" then
print("Checking config...");
+ local deprecated = set.new({
+ "bosh_ports", "disallow_s2s", "no_daemonize", "anonymous_login",
+ });
local known_global_options = set.new({
"pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize",
"umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings"
@@ -811,9 +831,27 @@ function commands.check(arg)
print(" No global options defined. Perhaps you have put a host definition at the top")
print(" of the config file? They should be at the bottom, see http://prosody.im/doc/configure#overview");
end
+ if it.count(enabled_hosts()) == 0 then
+ ok = false;
+ print("");
+ if it.count(it.filter("*", pairs(config))) == 0 then
+ print(" No hosts are defined, please add at least one VirtualHost section")
+ elseif config["*"]["enabled"] == false then
+ print(" No hosts are enabled. Remove enabled = false from the global section or put enabled = true under at least one VirtualHost section")
+ else
+ print(" All hosts are disabled. Remove enabled = false from at least one VirtualHost section")
+ end
+ end
-- Check for global options under hosts
local global_options = set.new(it.to_array(it.keys(config["*"])));
- for host, options in it.filter("*", pairs(config)) do
+ local deprecated_global_options = set.intersection(global_options, deprecated);
+ if not deprecated_global_options:empty() then
+ print("");
+ print(" You have some deprecated options in the global section:");
+ print(" "..tostring(deprecated_global_options))
+ ok = false;
+ end
+ for host, options in enabled_hosts() do
local host_options = set.new(it.to_array(it.keys(options)));
local misplaced_options = set.intersection(host_options, known_global_options);
for name in pairs(options) do
@@ -898,7 +936,7 @@ function commands.check(arg)
local v6_supported = not not socket.tcp6;
- for host, host_options in it.filter("*", pairs(config.getconfig())) do
+ for host, host_options in enabled_hosts() do
local all_targets_ok, some_targets_ok = true, false;
local is_component = not not host_options.component_module;
@@ -1047,54 +1085,52 @@ function commands.check(arg)
print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking");
cert_ok = false
else
- for host in pairs(hosts) do
- if host ~= "*" then -- Should check global certs too.
- print("Checking certificate for "..host);
- -- First, let's find out what certificate this host uses.
- local ssl_config = config.rawget(host, "ssl");
- if not ssl_config then
- local base_host = host:match("%.(.*)");
- ssl_config = config.get(base_host, "ssl");
- end
- if not ssl_config then
- print(" No 'ssl' option defined for "..host)
- cert_ok = false
- elseif not ssl_config.certificate then
- print(" No 'certificate' set in ssl option for "..host)
+ for host in enabled_hosts() do
+ print("Checking certificate for "..host);
+ -- First, let's find out what certificate this host uses.
+ local ssl_config = config.rawget(host, "ssl");
+ if not ssl_config then
+ local base_host = host:match("%.(.*)");
+ ssl_config = config.get(base_host, "ssl");
+ end
+ if not ssl_config then
+ print(" No 'ssl' option defined for "..host)
+ cert_ok = false
+ elseif not ssl_config.certificate then
+ print(" No 'certificate' set in ssl option for "..host)
+ cert_ok = false
+ elseif not ssl_config.key then
+ print(" No 'key' set in ssl option for "..host)
+ cert_ok = false
+ else
+ local key, err = io.open(ssl_config.key); -- Permissions check only
+ if not key then
+ print(" Could not open "..ssl_config.key..": "..err);
cert_ok = false
- elseif not ssl_config.key then
- print(" No 'key' set in ssl option for "..host)
+ else
+ key:close();
+ end
+ local cert_fh, err = io.open(ssl_config.certificate); -- Load the file.
+ if not cert_fh then
+ print(" Could not open "..ssl_config.certificate..": "..err);
cert_ok = false
else
- local key, err = io.open(ssl_config.key); -- Permissions check only
- if not key then
- print(" Could not open "..ssl_config.key..": "..err);
+ print(" Certificate: "..ssl_config.certificate)
+ local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close();
+ if not cert:validat(os.time()) then
+ print(" Certificate has expired.")
cert_ok = false
- else
- key:close();
end
- local cert_fh, err = io.open(ssl_config.certificate); -- Load the file.
- if not cert_fh then
- print(" Could not open "..ssl_config.certificate..": "..err);
- cert_ok = false
- else
- print(" Certificate: "..ssl_config.certificate)
- local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close();
- if not cert:validat(os.time()) then
- print(" Certificate has expired.")
- cert_ok = false
- end
- if config.get(host, "component_module") == nil
+ if config.get(host, "component_module") == nil
and not x509_verify_identity(host, "_xmpp-client", cert) then
- print(" Not vaild for client connections to "..host..".")
- cert_ok = false
- end
- if (not (config.get(name, "anonymous_login")
- or config.get(name, "authentication") == "anonymous"))
+ print(" Not vaild for client connections to "..host..".")
+ cert_ok = false
+ end
+ if (not (config.get(host, "anonymous_login")
+ or config.get(host, "authentication") == "anonymous"))
and not x509_verify_identity(host, "_xmpp-client", cert) then
- print(" Not vaild for server-to-server connections to "..host..".")
- cert_ok = false
- end
+ print(" Not vaild for server-to-server connections to "..host..".")
+ cert_ok = false
end
end
end
diff --git a/tools/jabberd14sql2prosody.lua b/tools/jabberd14sql2prosody.lua
index 03376b30..e43dc296 100644
--- a/tools/jabberd14sql2prosody.lua
+++ b/tools/jabberd14sql2prosody.lua
@@ -428,7 +428,7 @@ end
end
-- import modules
-package.path = package.path.."..\?.lua;";
+package.path = package.path..";../?.lua;";
local my_name = arg[0];
if my_name:match("[/\\]") then
diff --git a/util-src/pposix.c b/util-src/pposix.c
index 73e0d6e3..9b3e97eb 100644
--- a/util-src/pposix.c
+++ b/util-src/pposix.c
@@ -674,6 +674,7 @@ int lc_meminfo(lua_State* L)
#if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
int lc_fallocate(lua_State* L)
{
+ int ret;
off_t offset, len;
FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
if (f == NULL)
@@ -683,11 +684,15 @@ int lc_fallocate(lua_State* L)
len = luaL_checkinteger(L, 3);
#if defined(__linux__) && defined(_GNU_SOURCE)
- if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0)
+ errno = 0;
+ ret = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len);
+ if(ret == 0)
{
lua_pushboolean(L, 1);
return 1;
}
+ /* Some old versions of Linux apparently use the return value instead of errno */
+ if(errno == 0) errno = ret;
if(errno != ENOSYS && errno != EOPNOTSUPP)
{
@@ -701,7 +706,8 @@ int lc_fallocate(lua_State* L)
#warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
#endif
- if(posix_fallocate(fileno(f), offset, len) == 0)
+ ret = posix_fallocate(fileno(f), offset, len);
+ if(ret == 0)
{
lua_pushboolean(L, 1);
return 1;
@@ -709,7 +715,7 @@ int lc_fallocate(lua_State* L)
else
{
lua_pushnil(L);
- lua_pushstring(L, strerror(errno));
+ lua_pushstring(L, strerror(ret));
/* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
* this assumes that offset == length of the file */
ftruncate(fileno(f), offset);
diff --git a/util/dataforms.lua b/util/dataforms.lua
index b38d0e27..c352858c 100644
--- a/util/dataforms.lua
+++ b/util/dataforms.lua
@@ -94,6 +94,15 @@ function form_t.form(layout, data, formtype)
end
end
+ local media = field.media;
+ if media then
+ form:tag("media", { xmlns = "urn:xmpp:media-element", height = media.height, width = media.width });
+ for _, val in ipairs(media) do
+ form:tag("uri", { type = val.type }):text(val.uri):up()
+ end
+ form:up();
+ end
+
if field.required then
form:tag("required"):up();
end
diff --git a/util/indexedbheap.lua b/util/indexedbheap.lua
index 3cb03037..c60861e8 100644
--- a/util/indexedbheap.lua
+++ b/util/indexedbheap.lua
@@ -113,23 +113,27 @@ function indexed_heap:reprioritize(id, priority)
k = _percolate_down(self.priorities, k, self.ids, self.index);
end
function indexed_heap:remove_index(k)
- local size = #self.priorities;
-
local result = self.priorities[k];
+ if result == nil then return; end
+
local result_sync = self.ids[k];
local item = self.items[result_sync];
- if result == nil then return; end
- self.index[result_sync] = nil;
- self.items[result_sync] = nil;
+ local size = #self.priorities;
self.priorities[k] = self.priorities[size];
self.ids[k] = self.ids[size];
self.index[self.ids[k]] = k;
+
t_remove(self.priorities);
t_remove(self.ids);
- k = _percolate_up(self.priorities, k, self.ids, self.index);
- k = _percolate_down(self.priorities, k, self.ids, self.index);
+ self.index[result_sync] = nil;
+ self.items[result_sync] = nil;
+
+ if size > k then
+ k = _percolate_up(self.priorities, k, self.ids, self.index);
+ k = _percolate_down(self.priorities, k, self.ids, self.index);
+ end
return result, item, result_sync;
end
diff --git a/util/paths.lua b/util/paths.lua
new file mode 100644
index 00000000..3e5744df
--- /dev/null
+++ b/util/paths.lua
@@ -0,0 +1,38 @@
+local path_sep = package.config:sub(1,1);
+
+local path_util = {}
+
+-- Helper function to resolve relative paths (needed by config)
+function path_util.resolve_relative_path(parent_path, path)
+ if path then
+ -- Some normalization
+ parent_path = parent_path:gsub("%"..path_sep.."+$", "");
+ path = path:gsub("^%.%"..path_sep.."+", "");
+
+ local is_relative;
+ if path_sep == "/" and path:sub(1,1) ~= "/" then
+ is_relative = true;
+ elseif path_sep == "\\" and (path:sub(1,1) ~= "/" and (path:sub(2,3) ~= ":\\" and path:sub(2,3) ~= ":/")) then
+ is_relative = true;
+ end
+ if is_relative then
+ return parent_path..path_sep..path;
+ end
+ end
+ return path;
+end
+
+-- Helper function to convert a glob to a Lua pattern
+function path_util.glob_to_pattern(glob)
+ return "^"..glob:gsub("[%p*?]", function (c)
+ if c == "*" then
+ return ".*";
+ elseif c == "?" then
+ return ".";
+ else
+ return "%"..c;
+ end
+ end).."$";
+end
+
+return path_util;
diff --git a/util/x509.lua b/util/x509.lua
index 857f02a4..5e1b49e5 100644
--- a/util/x509.lua
+++ b/util/x509.lua
@@ -20,11 +20,9 @@
local nameprep = require "util.encodings".stringprep.nameprep;
local idna_to_ascii = require "util.encodings".idna.to_ascii;
+local base64 = require "util.encodings".base64;
local log = require "util.logger".init("x509");
-local pairs, ipairs = pairs, ipairs;
local s_format = string.format;
-local t_insert = table.insert;
-local t_concat = table.concat;
module "x509"
@@ -214,4 +212,23 @@ function verify_identity(host, service, cert)
return false
end
+local pat = "%-%-%-%-%-BEGIN ([A-Z ]+)%-%-%-%-%-\r?\n"..
+"([0-9A-Za-z+/=\r\n]*)\r?\n%-%-%-%-%-END %1%-%-%-%-%-";
+
+function pem2der(pem)
+ local typ, data = pem:match(pat);
+ if typ and data then
+ return base64.decode(data), typ;
+ end
+end
+
+local wrap = ('.'):rep(64);
+local envelope = "-----BEGIN %s-----\n%s\n-----END %s-----\n"
+
+function der2pem(data, typ)
+ typ = typ and typ:upper() or "CERTIFICATE";
+ data = base64.encode(data);
+ return s_format(envelope, typ, data:gsub(wrap, '%0\n', (#data-1)/64), typ);
+end
+
return _M;