aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mod_bosh.lua37
-rw-r--r--plugins/mod_compression.lua122
-rw-r--r--plugins/mod_console.lua29
-rw-r--r--plugins/mod_disco.lua45
-rw-r--r--plugins/mod_httpserver.lua42
-rw-r--r--plugins/mod_legacyauth.lua17
-rw-r--r--plugins/mod_muc.lua3
-rw-r--r--plugins/mod_pep.lua2
-rw-r--r--plugins/mod_posix.lua40
-rw-r--r--plugins/mod_register.lua11
-rw-r--r--plugins/mod_roster.lua2
-rw-r--r--plugins/mod_saslauth.lua64
-rw-r--r--plugins/mod_selftests.lua5
-rw-r--r--plugins/mod_tls.lua7
-rw-r--r--plugins/mod_version.lua24
-rw-r--r--plugins/mod_watchregistrations.lua8
-rw-r--r--plugins/mod_welcome.lua4
-rw-r--r--plugins/mod_xmlrpc.lua30
18 files changed, 371 insertions, 121 deletions
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua
index 743ebdef..e310be28 100644
--- a/plugins/mod_bosh.lua
+++ b/plugins/mod_bosh.lua
@@ -6,7 +6,6 @@
-- COPYING file in the source package for more information.
--
-
module.host = "*" -- Global module
local hosts = _G.hosts;
@@ -22,17 +21,18 @@ local core_process_stanza = core_process_stanza;
local st = require "util.stanza";
local logger = require "util.logger";
local log = logger.init("mod_bosh");
-local stream_callbacks = { stream_tag = "http://jabber.org/protocol/httpbind|body" };
-local config = require "core.configmanager";
+
local xmlns_bosh = "http://jabber.org/protocol/httpbind"; -- (hard-coded into a literal in session.send)
+local stream_callbacks = { stream_tag = "http://jabber.org/protocol/httpbind|body", default_ns = xmlns_bosh };
-local BOSH_DEFAULT_HOLD = tonumber(config.get("*", "core", "bosh_default_hold")) or 1;
-local BOSH_DEFAULT_INACTIVITY = tonumber(config.get("*", "core", "bosh_max_inactivity")) or 60;
-local BOSH_DEFAULT_POLLING = tonumber(config.get("*", "core", "bosh_max_polling")) or 5;
-local BOSH_DEFAULT_REQUESTS = tonumber(config.get("*", "core", "bosh_max_requests")) or 2;
-local BOSH_DEFAULT_MAXPAUSE = tonumber(config.get("*", "core", "bosh_max_pause")) or 300;
+local BOSH_DEFAULT_HOLD = tonumber(module:get_option("bosh_default_hold")) or 1;
+local BOSH_DEFAULT_INACTIVITY = tonumber(module:get_option("bosh_max_inactivity")) or 60;
+local BOSH_DEFAULT_POLLING = tonumber(module:get_option("bosh_max_polling")) or 5;
+local BOSH_DEFAULT_REQUESTS = tonumber(module:get_option("bosh_max_requests")) or 2;
+local BOSH_DEFAULT_MAXPAUSE = tonumber(module:get_option("bosh_max_pause")) or 300;
local default_headers = { ["Content-Type"] = "text/xml; charset=utf-8" };
+local session_close_reply = { headers = default_headers, body = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate" }), attr = {} };
local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat;
local os_time = os.time;
@@ -112,11 +112,9 @@ end
local function bosh_reset_stream(session) session.notopen = true; end
-local session_close_reply = { headers = default_headers, body = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate" }), attr = {} };
local function bosh_close_stream(session, reason)
(session.log or log)("info", "BOSH client disconnected");
session_close_reply.attr.condition = reason;
- local session_close_reply = tostring(session_close_reply);
for _, held_request in ipairs(session.requests) do
held_request:send(session_close_reply);
held_request:destroy();
@@ -144,7 +142,7 @@ function stream_callbacks.streamopened(request, attr)
-- New session
sid = new_uuid();
- local session = { type = "c2s_unauthed", conn = {}, sid = sid, rid = attr.rid, host = attr.to, bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid,
+ local session = { type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid), host = attr.to, bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid,
bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY,
requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, close = bosh_close_stream,
dispatch_stanza = core_process_stanza, log = logger.init("bosh"..sid), secure = request.secure };
@@ -209,6 +207,21 @@ function stream_callbacks.streamopened(request, attr)
return;
end
+ if session.rid then
+ local rid = tonumber(attr.rid);
+ local diff = rid - session.rid;
+ if diff > 1 then
+ session.log("warn", "rid too large (means a request was lost). Last rid: %d New rid: %s", session.rid, attr.rid);
+ elseif diff <= 0 then
+ -- Repeated, ignore
+ session.log("debug", "rid repeated (on request %s), ignoring: %d", request.id, session.rid);
+ request.notopen = nil;
+ t_insert(session.requests, request);
+ return;
+ end
+ session.rid = rid;
+ end
+
if attr.type == "terminate" then
-- Client wants to end this session
session:close();
@@ -275,7 +288,7 @@ function on_timer()
end
end
-local ports = config.get(module.host, "core", "bosh_ports") or { 5280 };
+local ports = module:get_option("bosh_ports") or { 5280 };
httpserver.new_from_config(ports, "http-bind", handle_request);
server.addtimer(on_timer);
diff --git a/plugins/mod_compression.lua b/plugins/mod_compression.lua
new file mode 100644
index 00000000..f1cae737
--- /dev/null
+++ b/plugins/mod_compression.lua
@@ -0,0 +1,122 @@
+-- Prosody IM
+-- Copyright (C) 2009 Tobias Markmann
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+local st = require "util.stanza";
+local zlib = require "zlib";
+local pcall = pcall;
+
+local xmlns_compression_feature = "http://jabber.org/features/compress"
+local xmlns_compression_protocol = "http://jabber.org/protocol/compress"
+local compression_stream_feature = st.stanza("compression", {xmlns=xmlns_compression_feature}):tag("method"):text("zlib"):up();
+
+local compression_level = module:get_option("compression_level");
+
+-- if not defined assume admin wants best compression
+if compression_level == nil then compression_level = 9 end;
+
+compression_level = tonumber(compression_level);
+if not compression_level or compression_level < 1 or compression_level > 9 then
+ module:log("warn", "Invalid compression level in config: %s", tostring(compression_level));
+ module:log("warn", "Module loading aborted. Compression won't be available.");
+ return;
+end
+
+module:add_event_hook("stream-features",
+ function (session, features)
+ if not session.compressed then
+ -- FIXME only advertise compression support when TLS layer has no compression enabled
+ features:add_child(compression_stream_feature);
+ end
+ end
+);
+
+-- TODO Support compression on S2S level too.
+module:add_handler({"c2s_unauthed", "c2s"}, "compress", xmlns_compression_protocol,
+ function(session, stanza)
+ -- fail if we are already compressed
+ if session.compressed then
+ local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
+ session.send(error_st);
+ session:log("warn", "Tried to establish another compression layer.");
+ end
+
+ -- checking if the compression method is supported
+ local method = stanza:child_with_name("method")[1];
+ if method == "zlib" then
+ session.log("info", method.." compression selected.");
+ session.send(st.stanza("compressed", {xmlns=xmlns_compression_protocol}));
+ session:reset_stream();
+
+ -- create deflate and inflate streams
+ local status, deflate_stream = pcall(zlib.deflate, compression_level);
+ if status == false then
+ local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
+ session.send(error_st);
+ session:log("error", "Failed to create zlib.deflate filter.");
+ module:log("error", deflate_stream);
+ return
+ end
+
+ local status, inflate_stream = pcall(zlib.inflate);
+ if status == false then
+ local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
+ session.send(error_st);
+ session:log("error", "Failed to create zlib.deflate filter.");
+ module:log("error", inflate_stream);
+ return
+ end
+
+ -- setup compression for session.w
+ local old_send = session.send;
+
+ session.send = function(t)
+ local status, compressed, eof = pcall(deflate_stream, tostring(t), 'sync');
+ if status == false then
+ session:close({
+ condition = "undefined-condition";
+ text = compressed;
+ extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
+ });
+ module:log("warn", compressed);
+ return;
+ end
+ old_send(compressed);
+ end;
+
+ -- setup decompression for session.data
+ local function setup_decompression(session)
+ local old_data = session.data
+ session.data = function(conn, data)
+ local status, decompressed, eof = pcall(inflate_stream, data);
+ if status == false then
+ session:close({
+ condition = "undefined-condition";
+ text = decompressed;
+ extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
+ });
+ module:log("warn", decompressed);
+ return;
+ end
+ old_data(conn, decompressed);
+ end;
+ end
+ setup_decompression(session);
+
+ local session_reset_stream = session.reset_stream;
+ session.reset_stream = function(session)
+ session_reset_stream(session);
+ setup_decompression(session);
+ return true;
+ end;
+ session.compressed = true;
+ else
+ session.log("info", method.." compression selected. But we don't support it.");
+ local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
+ session.send(error_st);
+ end
+ end
+);
diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua
index a3ed9499..367c46b8 100644
--- a/plugins/mod_console.lua
+++ b/plugins/mod_console.lua
@@ -70,6 +70,9 @@ function console_listener.listener(conn, data)
if data:match("^>") then
data = data:gsub("^>", "");
useglobalenv = true;
+ elseif data == "\004" then
+ commands["bye"](session, data);
+ return;
else
local command = data:lower();
command = data:match("^%w+") or data:match("%p");
@@ -205,7 +208,8 @@ end
-- Anything in def_env will be accessible within the session as a global variable
def_env.server = {};
-function def_env.server:reload()
+
+function def_env.server:insane_reload()
prosody.unlock_globals();
dofile "prosody"
prosody = _G.prosody;
@@ -230,6 +234,11 @@ function def_env.server:uptime()
minutes, (minutes ~= 1 and "s") or "", os.date("%c", prosody.start_time));
end
+function def_env.server:shutdown(reason)
+ prosody.shutdown(reason);
+ return true, "Shutdown initiated";
+end
+
def_env.module = {};
local function get_hosts_set(hosts, module)
@@ -333,6 +342,11 @@ function def_env.config:get(host, section, key)
return true, tostring(config_get(host, section, key));
end
+function def_env.config:reload()
+ local ok, err = prosody.reload_config();
+ 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
@@ -359,10 +373,19 @@ end
function def_env.c2s:show(match_jid)
local print, count = self.session.print, 0;
- show_c2s(function (jid)
+ show_c2s(function (jid, session)
if (not match_jid) or jid:match(match_jid) then
count = count + 1;
- print(jid);
+ local status, priority = "unavailable", tostring(session.priority or "-");
+ if session.presence then
+ status = session.presence:child_with_name("show");
+ if status then
+ status = status:get_text() or "[invalid!]";
+ else
+ status = "available";
+ end
+ end
+ print(jid.." - "..status.."("..priority..")");
end
end);
return true, "Total: "..count.." clients";
diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua
index 00ea01d8..06b29f0e 100644
--- a/plugins/mod_disco.lua
+++ b/plugins/mod_disco.lua
@@ -6,16 +6,47 @@
-- COPYING file in the source package for more information.
--
+local componentmanager_get_children = require "core.componentmanager".get_children;
+local st = require "util.stanza"
-
-local discomanager_handle = require "core.discomanager".handle;
-
+module:add_identity("server", "im", "Prosody"); -- FIXME should be in the non-existing mod_router
module:add_feature("http://jabber.org/protocol/disco#info");
module:add_feature("http://jabber.org/protocol/disco#items");
-module:add_iq_handler({"c2s", "s2sin"}, "http://jabber.org/protocol/disco#info", function (session, stanza)
- session.send(discomanager_handle(stanza));
+module:hook("iq/host/http://jabber.org/protocol/disco#info:query", function(event)
+ local origin, stanza = event.origin, event.stanza;
+ if stanza.attr.type ~= "get" then return; end
+ local node = stanza.tags[1].attr.node;
+ if node and node ~= "" then return; end -- TODO fire event?
+
+ local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#info");
+ local done = {};
+ for _,identity in ipairs(module:get_host_items("identity")) do
+ local identity_s = identity.category.."\0"..identity.type;
+ if not done[identity_s] then
+ reply:tag("identity", identity):up();
+ done[identity_s] = true;
+ end
+ end
+ for _,feature in ipairs(module:get_host_items("feature")) do
+ if not done[feature] then
+ reply:tag("feature", {var=feature}):up();
+ done[feature] = true;
+ end
+ end
+ origin.send(reply);
+ return true;
end);
-module:add_iq_handler({"c2s", "s2sin"}, "http://jabber.org/protocol/disco#items", function (session, stanza)
- session.send(discomanager_handle(stanza));
+module:hook("iq/host/http://jabber.org/protocol/disco#items:query", function(event)
+ local origin, stanza = event.origin, event.stanza;
+ if stanza.attr.type ~= "get" then return; end
+ local node = stanza.tags[1].attr.node;
+ if node and node ~= "" then return; end -- TODO fire event?
+
+ local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#items");
+ for jid in pairs(componentmanager_get_children(module.host)) do
+ reply:tag("item", {jid = jid}):up();
+ end
+ origin.send(reply);
+ return true;
end);
diff --git a/plugins/mod_httpserver.lua b/plugins/mod_httpserver.lua
index a8639281..f1f2150d 100644
--- a/plugins/mod_httpserver.lua
+++ b/plugins/mod_httpserver.lua
@@ -14,18 +14,48 @@ local t_concat = table.concat;
local http_base = "www_files";
+local response_400 = { status = "400 Bad Request", body = "<h1>Bad Request</h1>Sorry, we didn't understand your request :(" };
local response_404 = { status = "404 Not Found", body = "<h1>Page Not Found</h1>Sorry, we couldn't find what you were looking for :(" };
-local http_path = { http_base };
-local function handle_request(method, body, request)
- local path = request.url.path:gsub("%.%.%/", ""):gsub("^/[^/]+", "");
- http_path[2] = path;
- local f, err = open(t_concat(http_path), "r");
+local function preprocess_path(path)
+ if path:sub(1,1) ~= "/" then
+ path = "/"..path;
+ end
+ local level = 0;
+ for component in path:gmatch("([^/]+)/") do
+ if component == ".." then
+ level = level - 1;
+ elseif component ~= "." then
+ level = level + 1;
+ end
+ if level < 0 then
+ return nil;
+ end
+ end
+ return path;
+end
+
+function serve_file(path)
+ local f, err = open(http_base..path, "r");
if not f then return response_404; end
local data = f:read("*a");
f:close();
return data;
end
+local function handle_file_request(method, body, request)
+ local path = preprocess_path(request.url.path);
+ if not path then return response_400; end
+ path = path:gsub("^/[^/]+", ""); -- Strip /files/
+ return serve_file(path);
+end
+
+local function handle_default_request(method, body, request)
+ local path = preprocess_path(request.url.path);
+ if not path then return response_400; end
+ return serve_file(path);
+end
+
local ports = config.get(module.host, "core", "http_ports") or { 5280 };
-httpserver.new_from_config(ports, "files", handle_request);
+httpserver.set_default_handler(handle_default_request);
+httpserver.new_from_config(ports, "files", handle_file_request);
diff --git a/plugins/mod_legacyauth.lua b/plugins/mod_legacyauth.lua
index de94411e..9a9c3902 100644
--- a/plugins/mod_legacyauth.lua
+++ b/plugins/mod_legacyauth.lua
@@ -11,8 +11,7 @@
local st = require "util.stanza";
local t_concat = table.concat;
-local config = require "core.configmanager";
-local secure_auth_only = config.get(module:get_host(), "core", "require_encryption");
+local secure_auth_only = module:get_option("require_encryption");
local sessionmanager = require "core.sessionmanager";
local usermanager = require "core.usermanager";
@@ -43,11 +42,9 @@ module:add_iq_handler("c2s_unauthed", "jabber:iq:auth",
:tag("username"):up()
:tag("password"):up()
:tag("resource"):up());
- return true;
else
username, password, resource = t_concat(username), t_concat(password), t_concat(resource);
local reply = st.reply(stanza);
- require "core.usermanager"
if usermanager.validate_credentials(session.host, username, password) then
-- Authentication successful!
local success, err = sessionmanager.make_authenticated(session, username);
@@ -56,19 +53,13 @@ module:add_iq_handler("c2s_unauthed", "jabber:iq:auth",
success, err_type, err, err_msg = sessionmanager.bind_resource(session, resource);
if not success then
session.send(st.error_reply(stanza, err_type, err, err_msg));
- return true;
+ return true; -- FIXME need to unauthenticate here
end
end
session.send(st.reply(stanza));
- return true;
else
- local reply = st.reply(stanza);
- reply.attr.type = "error";
- reply:tag("error", { code = "401", type = "auth" })
- :tag("not-authorized", { xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas" });
- session.send(reply);
- return true;
+ session.send(st.error_reply(stanza, "auth", "not-authorized"));
end
end
-
+ return true;
end);
diff --git a/plugins/mod_muc.lua b/plugins/mod_muc.lua
index e99ef83c..b38468ea 100644
--- a/plugins/mod_muc.lua
+++ b/plugins/mod_muc.lua
@@ -76,6 +76,8 @@ component = register_component(muc_host, function(origin, stanza)
handle_to_domain(origin, stanza);
end);
+prosody.hosts[module:get_host()].muc = { rooms = rooms };
+
module.unload = function()
deregister_component(muc_host);
end
@@ -84,4 +86,5 @@ module.save = function()
end
module.restore = function(data)
rooms = data.rooms or {};
+ prosody.hosts[module:get_host()].muc = { rooms = rooms };
end
diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua
index e07759f0..842f1fce 100644
--- a/plugins/mod_pep.lua
+++ b/plugins/mod_pep.lua
@@ -25,7 +25,7 @@ local data = {};
local recipients = {};
local hash_map = {};
-module:add_identity("pubsub", "pep");
+module:add_identity("pubsub", "pep", "Prosody");
module:add_feature("http://jabber.org/protocol/pubsub#publish");
local function publish(session, node, item)
diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua
index 0f46888d..5f7dfc5b 100644
--- a/plugins/mod_posix.lua
+++ b/plugins/mod_posix.lua
@@ -17,19 +17,45 @@ if type(signal) == "string" then
module:log("warn", "Couldn't load signal library, won't respond to SIGTERM");
end
-local config_get = require "core.configmanager".get;
local logger_set = require "util.logger".setwriter;
local prosody = _G.prosody;
module.host = "*"; -- we're a global module
+-- Allow switching away from root, some people like strange ports.
+module:add_event_hook("server-started", function ()
+ local uid = module:get_option("setuid");
+ local gid = module:get_option("setgid");
+ if gid then
+ local success, msg = pposix.setgid(gid);
+ if success then
+ module:log("debug", "Changed group to "..gid.." successfully.");
+ else
+ module:log("error", "Failed to change group to "..gid..". Error: "..msg);
+ prosody.shutdown("Failed to change group to "..gid);
+ end
+ end
+ if uid then
+ local success, msg = pposix.setuid(uid);
+ if success then
+ module:log("debug", "Changed user to "..uid.." successfully.");
+ else
+ module:log("error", "Failed to change user to "..uid..". Error: "..msg);
+ prosody.shutdown("Failed to change user to "..uid);
+ end
+ end
+ end);
+
-- Don't even think about it!
module:add_event_hook("server-starting", function ()
- if pposix.getuid() == 0 and not config_get("*", "core", "run_as_root") then
- module:log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!");
- module:log("error", "For more information on running Prosody as root, see http://prosody.im/doc/root");
- prosody.shutdown("Refusing to run as root");
+ local suid = module:get_option("setuid");
+ if not suid or suid == 0 or suid == "root" then
+ if pposix.getuid() == 0 and not module:get_option("run_as_root") then
+ module:log("error", "Danger, Will Robinson! Prosody doesn't need to be run as root, so don't do it!");
+ module:log("error", "For more information on running Prosody as root, see http://prosody.im/doc/root");
+ prosody.shutdown("Refusing to run as root");
+ end
end
end);
@@ -46,7 +72,7 @@ local function write_pidfile()
if pidfile_written then
remove_pidfile();
end
- local pidfile = config_get("*", "core", "pidfile");
+ local pidfile = module:get_option("pidfile");
if pidfile then
local pf, err = io.open(pidfile, "w+");
if not pf then
@@ -76,7 +102,7 @@ function syslog_sink_maker(config)
end
require "core.loggingmanager".register_sink_type("syslog", syslog_sink_maker);
-if not config_get("*", "core", "no_daemonize") then
+if not module:get_option("no_daemonize") then
local function daemonize_server()
local ok, ret = pposix.daemonize();
if not ok then
diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua
index 383ab811..0cb8d771 100644
--- a/plugins/mod_register.lua
+++ b/plugins/mod_register.lua
@@ -9,7 +9,6 @@
local hosts = _G.hosts;
local st = require "util.stanza";
-local config = require "core.configmanager";
local datamanager = require "util.datamanager";
local usermanager_user_exists = require "core.usermanager".user_exists;
local usermanager_create_user = require "core.usermanager".create_user;
@@ -90,16 +89,16 @@ module:add_iq_handler("c2s", "jabber:iq:register", function (session, stanza)
end);
local recent_ips = {};
-local min_seconds_between_registrations = config.get(module.host, "core", "min_seconds_between_registrations");
-local whitelist_only = config.get(module.host, "core", "whitelist_registration_only");
-local whitelisted_ips = config.get(module.host, "core", "registration_whitelist") or { "127.0.0.1" };
-local blacklisted_ips = config.get(module.host, "core", "registration_blacklist") or {};
+local min_seconds_between_registrations = module:get_option("min_seconds_between_registrations");
+local whitelist_only = module:get_option("whitelist_registration_only");
+local whitelisted_ips = module:get_option("registration_whitelist") or { "127.0.0.1" };
+local blacklisted_ips = module:get_option("registration_blacklist") or {};
for _, ip in ipairs(whitelisted_ips) do whitelisted_ips[ip] = true; end
for _, ip in ipairs(blacklisted_ips) do blacklisted_ips[ip] = true; end
module:add_iq_handler("c2s_unauthed", "jabber:iq:register", function (session, stanza)
- if config.get(module.host, "core", "allow_registration") == false then
+ if module:get_option("allow_registration") == false then
session.send(st.error_reply(stanza, "cancel", "service-unavailable"));
elseif stanza.tags[1].name == "query" then
local query = stanza.tags[1];
diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua
index 8f25ed64..7ca22aa1 100644
--- a/plugins/mod_roster.lua
+++ b/plugins/mod_roster.lua
@@ -24,7 +24,7 @@ module:add_feature("jabber:iq:roster");
local rosterver_stream_feature = st.stanza("ver", {xmlns="urn:xmpp:features:rosterver"}):tag("optional"):up();
module:add_event_hook("stream-features",
- function (session, features)
+ function (session, features)
if session.username then
features:add_child(rosterver_stream_feature);
end
diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua
index 32269221..da66717c 100644
--- a/plugins/mod_saslauth.lua
+++ b/plugins/mod_saslauth.lua
@@ -12,9 +12,13 @@ local st = require "util.stanza";
local sm_bind_resource = require "core.sessionmanager".bind_resource;
local sm_make_authenticated = require "core.sessionmanager".make_authenticated;
local base64 = require "util.encodings".base64;
+
local nodeprep = require "util.encodings".stringprep.nodeprep;
local datamanager_load = require "util.datamanager".load;
local usermanager_validate_credentials = require "core.usermanager".validate_credentials;
+local usermanager_get_supported_methods = require "core.usermanager".get_supported_methods;
+local usermanager_user_exists = require "core.usermanager".user_exists;
+local usermanager_get_password = require "core.usermanager".get_password;
local t_concat, t_insert = table.concat, table.insert;
local tostring = tostring;
local jid_split = require "util.jid".split
@@ -57,29 +61,39 @@ local function handle_status(session, status)
session.sasl_handler = nil;
session:reset_stream();
return;
- end
+ end
sm_make_authenticated(session, session.sasl_handler.username);
session.sasl_handler = nil;
session:reset_stream();
end
end
-local function password_callback(node, hostname, realm, mechanism, decoder)
- local func = function(x) return x; end;
- local node = nodeprep(node);
- if not node then
- return func, nil;
- end
- local password = (datamanager_load(node, hostname, "accounts") or {}).password; -- FIXME handle hashed passwords
- if password then
- if mechanism == "PLAIN" then
- return func, password;
- elseif mechanism == "DIGEST-MD5" then
- if decoder then node, realm, password = decoder(node), decoder(realm), decoder(password); end
+local function credentials_callback(mechanism, ...)
+ if mechanism == "PLAIN" then
+ local username, hostname, password = ...;
+ username = nodeprep(username);
+ if not username then
+ return false;
+ end
+ local response = usermanager_validate_credentials(hostname, username, password, mechanism);
+ if response == nil then
+ return false;
+ else
+ return response;
+ end
+ elseif mechanism == "DIGEST-MD5" then
+ function func(x) return x; end
+ local node, domain, realm, decoder = ...;
+ local password = usermanager_get_password(node, domain);
+ if password then
+ if decoder then
+ node, realm, password = decoder(node), decoder(realm), decoder(password);
+ end
return func, md5(node..":"..realm..":"..password);
+ else
+ return func, nil;
end
end
- return func, nil;
end
local function sasl_handler(session, stanza)
@@ -92,7 +106,7 @@ local function sasl_handler(session, stanza)
elseif stanza.attr.mechanism == "ANONYMOUS" then
return session.send(build_reply("failure", "mechanism-too-weak"));
end
- session.sasl_handler = new_sasl(stanza.attr.mechanism, session.host, password_callback);
+ session.sasl_handler = new_sasl(stanza.attr.mechanism, session.host, credentials_callback);
if not session.sasl_handler then
return session.send(build_reply("failure", "invalid-mechanism"));
end
@@ -111,7 +125,7 @@ local function sasl_handler(session, stanza)
end
local status, ret, err_msg = session.sasl_handler:feed(text);
handle_status(session, status);
- local s = build_reply(status, ret, err_msg);
+ local s = build_reply(status, ret, err_msg);
log("debug", "sasl reply: %s", tostring(s));
session.send(s);
end
@@ -123,8 +137,8 @@ module:add_handler("c2s_unauthed", "response", xmlns_sasl, sasl_handler);
local mechanisms_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-sasl' };
local bind_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-bind' };
local xmpp_session_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-session' };
-module:add_event_hook("stream-features",
- function (session, features)
+module:add_event_hook("stream-features",
+ function (session, features)
if not session.username then
if secure_auth_only and not session.secure then
return;
@@ -134,8 +148,10 @@ module:add_event_hook("stream-features",
if config.get(session.host or "*", "core", "anonymous_login") then
features:tag("mechanism"):text("ANONYMOUS"):up();
else
- features:tag("mechanism"):text("DIGEST-MD5"):up();
- features:tag("mechanism"):text("PLAIN"):up();
+ mechanisms = usermanager_get_supported_methods(session.host or "*");
+ for k, v in pairs(mechanisms) do
+ features:tag("mechanism"):text(k):up();
+ end
end
features:up();
else
@@ -143,8 +159,8 @@ module:add_event_hook("stream-features",
features:tag("session", xmpp_session_attr):up();
end
end);
-
-module:add_iq_handler("c2s", "urn:ietf:params:xml:ns:xmpp-bind",
+
+module:add_iq_handler("c2s", "urn:ietf:params:xml:ns:xmpp-bind",
function (session, stanza)
log("debug", "Client requesting a resource bind");
local resource;
@@ -166,8 +182,8 @@ module:add_iq_handler("c2s", "urn:ietf:params:xml:ns:xmpp-bind",
:tag("jid"):text(session.full_jid));
end
end);
-
-module:add_iq_handler("c2s", "urn:ietf:params:xml:ns:xmpp-session",
+
+module:add_iq_handler("c2s", "urn:ietf:params:xml:ns:xmpp-session",
function (session, stanza)
log("debug", "Client requesting a session");
session.send(st.reply(stanza));
diff --git a/plugins/mod_selftests.lua b/plugins/mod_selftests.lua
index 6a26dfc3..1f413634 100644
--- a/plugins/mod_selftests.lua
+++ b/plugins/mod_selftests.lua
@@ -6,14 +6,13 @@
-- COPYING file in the source package for more information.
--
-
+module.host = "*" -- Global module
local st = require "util.stanza";
local register_component = require "core.componentmanager".register_component;
local core_route_stanza = core_route_stanza;
local socket = require "socket";
-local config = require "core.configmanager";
-local ping_hosts = config.get("*", "mod_selftests", "ping_hosts") or { "coversant.interop.xmpp.org", "djabberd.interop.xmpp.org", "djabberd-trunk.interop.xmpp.org", "ejabberd.interop.xmpp.org", "openfire.interop.xmpp.org" };
+local ping_hosts = module:get_option("ping_hosts") or { "coversant.interop.xmpp.org", "djabberd.interop.xmpp.org", "djabberd-trunk.interop.xmpp.org", "ejabberd.interop.xmpp.org", "openfire.interop.xmpp.org" };
local open_pings = {};
diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua
index 8926edfc..10455559 100644
--- a/plugins/mod_tls.lua
+++ b/plugins/mod_tls.lua
@@ -6,14 +6,11 @@
-- COPYING file in the source package for more information.
--
-
-
local st = require "util.stanza";
local xmlns_starttls ='urn:ietf:params:xml:ns:xmpp-tls';
-local config = require "core.configmanager";
-local secure_auth_only = config.get("*", "core", "require_encryption");
+local secure_auth_only = module:get_option("require_encryption");
module:add_handler("c2s_unauthed", "starttls", xmlns_starttls,
function (session, stanza)
@@ -31,7 +28,7 @@ module:add_handler("c2s_unauthed", "starttls", xmlns_starttls,
local starttls_attr = { xmlns = xmlns_starttls };
module:add_event_hook("stream-features",
- function (session, features)
+ function (session, features)
if session.conn.starttls then
features:tag("starttls", starttls_attr);
if secure_auth_only then
diff --git a/plugins/mod_version.lua b/plugins/mod_version.lua
index 87bff5d9..9af830f8 100644
--- a/plugins/mod_version.lua
+++ b/plugins/mod_version.lua
@@ -6,17 +6,13 @@
-- COPYING file in the source package for more information.
--
-
-local prosody = prosody;
local st = require "util.stanza";
-local xmlns_version = "jabber:iq:version"
-
-module:add_feature(xmlns_version);
+module:add_feature("jabber:iq:version");
local version = "the best operating system ever!";
-if not require "core.configmanager".get("*", "core", "hide_os_type") then
+if not module:get_option("hide_os_type") then
if os.getenv("WINDIR") then
version = "Windows";
else
@@ -31,11 +27,15 @@ end
version = version:match("^%s*(.-)%s*$") or version;
-module:add_iq_handler({"c2s", "s2sin"}, xmlns_version, function(session, stanza)
- if stanza.attr.type == "get" then
- session.send(st.reply(stanza):query(xmlns_version)
- :tag("name"):text("Prosody"):up()
- :tag("version"):text(prosody.version):up()
- :tag("os"):text(version));
+local query = st.stanza("query", {xmlns = "jabber:iq:version"})
+ :tag("name"):text("Prosody"):up()
+ :tag("version"):text(prosody.version):up()
+ :tag("os"):text(version);
+
+module:hook("iq/host/jabber:iq:version:query", function(event)
+ local stanza = event.stanza;
+ if stanza.attr.type == "get" and stanza.attr.to == module.host then
+ event.origin.send(st.reply(stanza):add_child(query));
+ return true;
end
end);
diff --git a/plugins/mod_watchregistrations.lua b/plugins/mod_watchregistrations.lua
index 9457313f..6a2af853 100644
--- a/plugins/mod_watchregistrations.lua
+++ b/plugins/mod_watchregistrations.lua
@@ -9,12 +9,10 @@
local host = module:get_host();
-local config = require "core.configmanager";
+local registration_watchers = module:get_option("registration_watchers")
+ or module:get_option("admins") or {};
-local registration_watchers = config.get(host, "core", "registration_watchers")
- or config.get(host, "core", "admins") or {};
-
-local registration_alert = config.get(host, "core", "registration_notification") or "User $username just registered on $host from $ip";
+local registration_alert = module:get_option("registration_notification") or "User $username just registered on $host from $ip";
local st = require "util.stanza";
diff --git a/plugins/mod_welcome.lua b/plugins/mod_welcome.lua
index 5c0da8b8..cc50cba3 100644
--- a/plugins/mod_welcome.lua
+++ b/plugins/mod_welcome.lua
@@ -6,10 +6,8 @@
-- COPYING file in the source package for more information.
--
-local config = require "core.configmanager";
-
local host = module:get_host();
-local welcome_text = config.get("*", "core", "welcome_message") or "Hello $user, welcome to the $host IM server!";
+local welcome_text = module:get_option("welcome_message") or "Hello $user, welcome to the $host IM server!";
local st = require "util.stanza";
diff --git a/plugins/mod_xmlrpc.lua b/plugins/mod_xmlrpc.lua
index 46edcaee..7165386a 100644
--- a/plugins/mod_xmlrpc.lua
+++ b/plugins/mod_xmlrpc.lua
@@ -16,6 +16,7 @@ local unpack = unpack;
local tostring = tostring;
local is_admin = require "core.usermanager".is_admin;
local jid_split = require "util.jid".split;
+local jid_bare = require "util.jid".bare;
local b64_decode = require "util.encodings".base64.decode;
local get_method = require "core.objectmanager".get_object;
local validate_credentials = require "core.usermanager".validate_credentials;
@@ -65,10 +66,15 @@ local function parse_xml(xml)
return stanza.tags[1];
end
-local function handle_xmlrpc_request(method, args)
+local function handle_xmlrpc_request(jid, method, args)
+ local is_secure_call = (method:sub(1,7) == "secure/");
+ if not is_admin(jid) and not is_secure_call then
+ return create_error_response(401, "not authorized");
+ end
method = get_method(method);
if not method then return create_error_response(404, "method not found"); end
args = args or {};
+ if is_secure_call then table.insert(args, 1, jid); end
local success, result = pcall(method, unpack(args));
if success then
success, result = pcall(create_response, result or "nil");
@@ -77,22 +83,20 @@ local function handle_xmlrpc_request(method, args)
end
return create_error_response(500, "Error in creating response: "..result);
end
- return create_error_response(0, result or "nil");
+ return create_error_response(0, tostring(result):gsub("^[^:]+:%d+: ", ""));
end
local function handle_xmpp_request(origin, stanza)
local query = stanza.tags[1];
if query.name == "query" then
if #query.tags == 1 then
- if is_admin(stanza.attr.from) then
- local success, method, args = pcall(translate_request, query.tags[1]);
- if success then
- local result = handle_xmlrpc_request(method, args);
- origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:rpc'}):add_child(result));
- else
- origin.send(st.error_reply(stanza, "modify", "bad-request", method));
- end
- else origin.send(st.error_reply(stanza, "auth", "forbidden", "No content in XML-RPC request")); end
+ local success, method, args = pcall(translate_request, query.tags[1]);
+ if success then
+ local result = handle_xmlrpc_request(jid_bare(stanza.attr.from), method, args);
+ origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:rpc'}):add_child(result));
+ else
+ origin.send(st.error_reply(stanza, "modify", "bad-request", method));
+ end
else origin.send(st.error_reply(stanza, "modify", "bad-request", "No content in XML-RPC request")); end
else origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end
end
@@ -106,7 +110,7 @@ local function handle_http_request(method, body, request)
-- authenticate user
local username, password = b64_decode(request['authorization'] or ''):gmatch('([^:]*):(.*)')(); -- TODO digest auth
local node, host = jid_split(username);
- if not validate_credentials(host, node, password) and is_admin(username) then
+ if not validate_credentials(host, node, password) then
return unauthorized_response;
end
-- parse request
@@ -117,7 +121,7 @@ local function handle_http_request(method, body, request)
-- execute request
local success, method, args = pcall(translate_request, stanza);
if success then
- return { headers = default_headers; body = tostring(handle_xmlrpc_request(method, args)) };
+ return { headers = default_headers; body = tostring(handle_xmlrpc_request(node.."@"..host, method, args)) };
end
return "<html><body>Error parsing XML-RPC request: "..tostring(method).."</body></html>";
end