diff options
Diffstat (limited to 'plugins')
28 files changed, 445 insertions, 295 deletions
diff --git a/plugins/adhoc/adhoc.lib.lua b/plugins/adhoc/adhoc.lib.lua index eff3caff..acdae6b9 100644 --- a/plugins/adhoc/adhoc.lib.lua +++ b/plugins/adhoc/adhoc.lib.lua @@ -12,7 +12,7 @@ local states = {} local _M = {}; -function _cmdtag(desc, status, sessionid, action) +local function _cmdtag(desc, status, sessionid, action) local cmd = st.stanza("command", { xmlns = xmlns_cmd, node = desc.node, status = status }); if sessionid then cmd.attr.sessionid = sessionid; end if action then cmd.attr.action = action; end @@ -35,6 +35,7 @@ function _M.handle_cmd(command, origin, stanza) local data, state = command:handler(dataIn, states[sessionid]); states[sessionid] = state; local stanza = st.reply(stanza); + local cmdtag; if data.status == "completed" then states[sessionid] = nil; cmdtag = command:cmdtag("completed", sessionid); @@ -64,8 +65,8 @@ function _M.handle_cmd(command, origin, stanza) if (action == "prev") or (action == "next") or (action == "complete") then actions:tag(action):up(); else - module:log("error", 'Command "'..command.name.. - '" at node "'..command.node..'" provided an invalid action "'..action..'"'); + module:log("error", "Command %q at node %q provided an invalid action %q", + command.name, command.node, action); end end cmdtag:add_child(actions); diff --git a/plugins/adhoc/mod_adhoc.lua b/plugins/adhoc/mod_adhoc.lua index 49d07103..69b2c8da 100644 --- a/plugins/adhoc/mod_adhoc.lua +++ b/plugins/adhoc/mod_adhoc.lua @@ -100,3 +100,4 @@ local function adhoc_removed(event) end module:handle_items("adhoc", adhoc_added, adhoc_removed); +module:handle_items("adhoc-provider", adhoc_added, adhoc_removed); diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua index 4d2c60d7..50493abe 100644 --- a/plugins/mod_admin_adhoc.lua +++ b/plugins/mod_admin_adhoc.lua @@ -23,10 +23,19 @@ local timer_add_task = require "util.timer".add_task; local dataforms_new = require "util.dataforms".new; local array = require "util.array"; local modulemanager = require "modulemanager"; +local core_post_stanza = prosody.core_post_stanza; module:depends("adhoc"); local adhoc_new = module:require "adhoc".new; +local function generate_error_message(errors) + local errmsg = {}; + for name, err in pairs(errors) do + errmsg[#errmsg + 1] = name .. ": " .. err; + end + return { status = "completed", error = { message = t_concat(errmsg, "\n") } }; +end + function add_user_command_handler(self, data, state) local add_user_layout = dataforms_new{ title = "Adding a User"; @@ -42,9 +51,9 @@ function add_user_command_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = add_user_layout:data(data.form); - if not fields.accountjid then - return { status = "completed", error = { message = "You need to specify a JID." } }; + local fields, err = add_user_layout:data(data.form); + if err then + return generate_error_message(err); end local username, host, resource = jid.split(fields.accountjid); if data.to ~= host then @@ -55,15 +64,14 @@ function add_user_command_handler(self, data, state) return { status = "completed", error = { message = "Account already exists" } }; else if usermanager_create_user(username, fields.password, host) then - module:log("info", "Created new account " .. username.."@"..host); + module:log("info", "Created new account %s@%s", username, host); return { status = "completed", info = "Account successfully created" }; else return { status = "completed", error = { message = "Failed to write data to disk" } }; end end else - module:log("debug", (fields.accountjid or "<nil>") .. " " .. (fields.password or "<nil>") .. " " - .. (fields["password-verify"] or "<nil>")); + module:log("debug", "Invalid data, password mismatch or empty username while creating account for %s", fields.accountjid or "<nil>"); return { status = "completed", error = { message = "Invalid data.\nPassword mismatch, or empty username" } }; end else @@ -85,9 +93,9 @@ function change_user_password_command_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = change_user_password_layout:data(data.form); - if not fields.accountjid or fields.accountjid == "" or not fields.password then - return { status = "completed", error = { message = "Please specify username and password" } }; + local fields, err = change_user_password_layout:data(data.form); + if err then + return generate_error_message(err); end local username, host, resource = jid.split(fields.accountjid); if data.to ~= host then @@ -126,16 +134,19 @@ function delete_user_command_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = delete_user_layout:data(data.form); + local fields, err = delete_user_layout:data(data.form); + if err then + return generate_error_message(err); + end local failed = {}; local succeeded = {}; for _, aJID in ipairs(fields.accountjids) do local username, host, resource = jid.split(aJID); if (host == data.to) and usermanager_user_exists(username, host) and disconnect_user(aJID) and usermanager_create_user(username, nil, host) then - module:log("debug", "User " .. aJID .. " has been deleted"); + module:log("debug", "User %s has been deleted", aJID); succeeded[#succeeded+1] = aJID; else - module:log("debug", "Tried to delete non-existant user "..aJID); + module:log("debug", "Tried to delete non-existant user %s", aJID); failed[#failed+1] = aJID; end end @@ -154,7 +165,7 @@ function disconnect_user(match_jid) local sessions = host.sessions[node] and host.sessions[node].sessions; for resource, session in pairs(sessions or {}) do if not givenResource or (resource == givenResource) then - module:log("debug", "Disconnecting "..node.."@"..hostname.."/"..resource); + module:log("debug", "Disconnecting %s@%s/%s", node, hostname, resource); session:close(); end end @@ -175,7 +186,10 @@ function end_user_session_handler(self, data, state) return { status = "canceled" }; end - local fields = end_user_session_layout:data(data.form); + local fields, err = end_user_session_layout:data(data.form); + if err then + return generate_error_message(err); + end local failed = {}; local succeeded = {}; for _, aJID in ipairs(fields.accountjids) do @@ -223,9 +237,9 @@ function get_user_password_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = get_user_password_layout:data(data.form); - if not fields.accountjid then - return { status = "completed", error = { message = "Please specify a JID." } }; + local fields, err = get_user_password_layout:data(data.form); + if err then + return generate_error_message(err); end local user, host, resource = jid.split(fields.accountjid); local accountjid = ""; @@ -261,10 +275,10 @@ function get_user_roster_handler(self, data, state) return { status = "canceled" }; end - local fields = get_user_roster_layout:data(data.form); + local fields, err = get_user_roster_layout:data(data.form); - if not fields.accountjid then - return { status = "completed", error = { message = "Please specify a JID" } }; + if err then + return generate_error_message(err); end local user, host, resource = jid.split(fields.accountjid); @@ -323,10 +337,10 @@ function get_user_stats_handler(self, data, state) return { status = "canceled" }; end - local fields = get_user_stats_layout:data(data.form); + local fields, err = get_user_stats_layout:data(data.form); - if not fields.accountjid then - return { status = "completed", error = { message = "Please specify a JID." } }; + if err then + return generate_error_message(err); end local user, host, resource = jid.split(fields.accountjid); @@ -376,7 +390,11 @@ function get_online_users_command_handler(self, data, state) return { status = "canceled" }; end - local fields = get_online_users_layout:data(data.form); + local fields, err = get_online_users_layout:data(data.form); + + if err then + return generate_error_message(err); + end local max_items = nil if fields.max_items ~= "all" then @@ -436,11 +454,9 @@ function load_module_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = layout:data(data.form); - if (not fields.module) or (fields.module == "") then - return { status = "completed", error = { - message = "Please specify a module." - } }; + local fields, err = layout:data(data.form); + if err then + return generate_error_message(err); end if modulemanager.is_loaded(data.to, fields.module) then return { status = "completed", info = "Module already loaded" }; @@ -453,7 +469,6 @@ function load_module_handler(self, data, state) '". Error was: "'..tostring(err or "<unspecified>")..'"' } }; end else - local modules = array.collect(keys(hosts[data.to].modules)):sort(); return { status = "executing", form = layout }, "executing"; end end @@ -470,11 +485,9 @@ function reload_modules_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = layout:data(data.form); - if #fields.modules == 0 then - return { status = "completed", error = { - message = "Please specify a module. (This means your client misbehaved, as this field is required)" - } }; + local fields, err = layout:data(data.form); + if err then + return generate_error_message(err); end local ok_list, err_list = {}, {}; for _, module in ipairs(fields.modules) do @@ -538,7 +551,11 @@ function shut_down_service_handler(self, data, state) return { status = "canceled" }; end - local fields = shut_down_service_layout:data(data.form); + local fields, err = shut_down_service_layout:data(data.form); + + if err then + return generate_error_message(err); + end if fields.announcement and #fields.announcement > 0 then local message = st.message({type = "headline"}, fields.announcement):up() @@ -566,11 +583,9 @@ function unload_modules_handler(self, data, state) if data.action == "cancel" then return { status = "canceled" }; end - local fields = layout:data(data.form); - if #fields.modules == 0 then - return { status = "completed", error = { - message = "Please specify a module. (This means your client misbehaved, as this field is required)" - } }; + local fields, err = layout:data(data.form); + if err then + return generate_error_message(err); end local ok_list, err_list = {}, {}; for _, module in ipairs(fields.modules) do @@ -605,17 +620,17 @@ local reload_modules_desc = adhoc_new("Reload modules", "http://prosody.im/proto local shut_down_service_desc = adhoc_new("Shut Down Service", "http://jabber.org/protocol/admin#shutdown", shut_down_service_handler, "global_admin"); local unload_modules_desc = adhoc_new("Unload modules", "http://prosody.im/protocol/modules#unload", unload_modules_handler, "admin"); -module:add_item("adhoc", add_user_desc); -module:add_item("adhoc", change_user_password_desc); -module:add_item("adhoc", config_reload_desc); -module:add_item("adhoc", delete_user_desc); -module:add_item("adhoc", end_user_session_desc); -module:add_item("adhoc", get_user_password_desc); -module:add_item("adhoc", get_user_roster_desc); -module:add_item("adhoc", get_user_stats_desc); -module:add_item("adhoc", get_online_users_desc); -module:add_item("adhoc", list_modules_desc); -module:add_item("adhoc", load_module_desc); -module:add_item("adhoc", reload_modules_desc); -module:add_item("adhoc", shut_down_service_desc); -module:add_item("adhoc", unload_modules_desc); +module:provides("adhoc", add_user_desc); +module:provides("adhoc", change_user_password_desc); +module:provides("adhoc", config_reload_desc); +module:provides("adhoc", delete_user_desc); +module:provides("adhoc", end_user_session_desc); +module:provides("adhoc", get_user_password_desc); +module:provides("adhoc", get_user_roster_desc); +module:provides("adhoc", get_user_stats_desc); +module:provides("adhoc", get_online_users_desc); +module:provides("adhoc", list_modules_desc); +module:provides("adhoc", load_module_desc); +module:provides("adhoc", reload_modules_desc); +module:provides("adhoc", shut_down_service_desc); +module:provides("adhoc", unload_modules_desc); diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index cdac7d4e..ebd817b5 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -13,7 +13,7 @@ local _G = _G; local prosody = _G.prosody; local hosts = prosody.hosts; -local console_listener = { default_port = 5582; default_mode = "*l"; interface = "127.0.0.1" }; +local console_listener = { default_port = 5582; default_mode = "*a"; interface = "127.0.0.1" }; local hostmanager = require "core.hostmanager"; local modulemanager = require "core.modulemanager"; @@ -30,6 +30,7 @@ local envloadfile = require "util.envload".envloadfile; local commands = module:shared("commands") local def_env = module:shared("env"); local default_env_mt = { __index = def_env }; +local core_post_stanza = prosody.core_post_stanza; local function redirect_output(_G, session) local env = setmetatable({ print = session.print }, { __index = function (t, k) return rawget(_G, k); end }); @@ -81,67 +82,74 @@ end function console_listener.onincoming(conn, data) local session = sessions[conn]; - -- Handle data - (function(session, data) - local useglobalenv; - - 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"); - if commands[command] then - commands[command](session, data); - return; + local partial = session.partial_data; + if partial then + data = partial..data; + end + + for line in data:gmatch("[^\n]*[\n\004]") do + -- Handle data (loop allows us to break to add \0 after response) + repeat + local useglobalenv; + + if line:match("^>") then + line = line:gsub("^>", ""); + useglobalenv = true; + elseif line == "\004" then + commands["bye"](session, line); + break; + else + local command = line:match("^%w+") or line:match("%p"); + if commands[command] then + commands[command](session, line); + break; + end end - end - session.env._ = data; - - local chunkname = "=console"; - local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil - local chunk, err = envload("return "..data, chunkname, env); - if not chunk then - chunk, err = envload(data, chunkname, env); + session.env._ = line; + + local chunkname = "=console"; + local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil + local chunk, err = envload("return "..line, chunkname, env); if not chunk then - err = err:gsub("^%[string .-%]:%d+: ", ""); - err = err:gsub("^:%d+: ", ""); - err = err:gsub("'<eof>'", "the end of the line"); - session.print("Sorry, I couldn't understand that... "..err); - return; + chunk, err = envload(line, chunkname, env); + if not chunk then + err = err:gsub("^%[string .-%]:%d+: ", ""); + err = err:gsub("^:%d+: ", ""); + err = err:gsub("'<eof>'", "the end of the line"); + session.print("Sorry, I couldn't understand that... "..err); + break; + end end - end - - local ranok, taskok, message = pcall(chunk); - if not (ranok or message or useglobalenv) and commands[data:lower()] then - commands[data:lower()](session, data); - return; - end - - if not ranok then - session.print("Fatal error while running command, it did not complete"); - session.print("Error: "..taskok); - return; - end - - if not message then - session.print("Result: "..tostring(taskok)); - return; - elseif (not taskok) and message then - session.print("Command completed with a problem"); - session.print("Message: "..tostring(message)); - return; - end + local ranok, taskok, message = pcall(chunk); + + if not (ranok or message or useglobalenv) and commands[line:lower()] then + commands[line:lower()](session, line); + break; + end + + if not ranok then + session.print("Fatal error while running command, it did not complete"); + session.print("Error: "..taskok); + break; + end + + if not message then + session.print("Result: "..tostring(taskok)); + break; + elseif (not taskok) and message then + session.print("Command completed with a problem"); + session.print("Message: "..tostring(message)); + break; + end + + session.print("OK: "..tostring(message)); + until true - session.print("OK: "..tostring(message)); - end)(session, data); - - session.send(string.char(0)); + session.send(string.char(0)); + end + session.partial_data = data:match("[^\n]+$"); end function console_listener.ondisconnect(conn, err) @@ -191,6 +199,7 @@ function commands.help(session, data) print [[s2s - Commands to manage sessions between this server and others]] print [[module - Commands to load/reload/unload modules/plugins]] print [[host - Commands to activate, deactivate and list virtual hosts]] + print [[user - Commands to create and delete users, and change their passwords]] print [[server - Uptime, version, shutting down, etc.]] print [[config - Reloading the configuration, etc.]] print [[console - Help regarding the console itself]] @@ -202,6 +211,7 @@ function commands.help(session, data) elseif section == "s2s" then print [[s2s:show(domain) - Show all s2s connections for the given domain (or all if no domain given)]] 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 print [[module:load(module, host) - Load the specified module on the specified host (or all hosts if none given)]] print [[module:reload(module, host) - The same, but unloads and loads the module (saving state if the module supports it)]] @@ -211,6 +221,10 @@ function commands.help(session, data) print [[host:activate(hostname) - Activates the specified host]] print [[host:deactivate(hostname) - Disconnects all clients on this host and deactivates]] print [[host:list() - List the currently-activated hosts]] + elseif section == "user" then + print [[user:create(jid, password) - Create the specified user account]] + print [[user:password(jid, password) - Set the password for the specified user account]] + print [[user:delete(jid, password) - Permanently remove the specified user account]] elseif section == "server" then print [[server:version() - Show the server's version number]] print [[server:uptime() - Show how long the server has been running]] @@ -679,7 +693,6 @@ function def_env.s2s:showcert(domain) end local domain_certs = array.collect(values(cert_set)); -- Phew. We now have a array of unique certificates presented by domain. - local print = self.session.print; local n_certs = #domain_certs; if n_certs == 0 then @@ -773,6 +786,40 @@ function def_env.s2s:close(from, to) return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end +function def_env.s2s:closeall(host) + local count = 0; + + if not host or type(host) ~= "string" then return false, "wrong syntax: please use s2s:closeall('hostname.tld')"; end + if hosts[host] then + for session in pairs(incoming_s2s) do + if session.to_host == host then + (session.close or s2smanager.destroy_session)(session); + count = count + 1; + end + end + for _, session in pairs(hosts[host].s2sout) do + (session.close or s2smanager.destroy_session)(session); + count = count + 1; + end + else + for session in pairs(incoming_s2s) do + if session.from_host == host then + (session.close or s2smanager.destroy_session)(session); + count = count + 1; + end + end + for _, h in pairs(hosts) do + if h.s2sout[host] then + (h.s2sout[host].close or s2smanager.destroy_session)(h.s2sout[host]); + count = count + 1; + end + end + end + + if count == 0 then return false, "No sessions to close."; + else return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end +end + def_env.host = {}; def_env.hosts = def_env.host; function def_env.host:activate(hostname, config) @@ -860,6 +907,53 @@ function def_env.muc:room(room_jid) return setmetatable({ room = room_obj }, console_room_mt); end +local um = require"core.usermanager"; + +def_env.user = {}; +function def_env.user:create(jid, password) + local username, host = jid_split(jid); + local ok, err = um.create_user(username, password, host); + if ok then + return true, "User created"; + else + return nil, "Could not create user: "..err; + end +end + +function def_env.user:delete(jid) + local username, host = jid_split(jid); + local ok, err = um.delete_user(username, host); + if ok then + return true, "User deleted"; + else + return nil, "Could not delete user: "..err; + end +end + +function def_env.user:passwd(jid, password) + local username, host = jid_split(jid); + local ok, err = um.set_password(username, password, host); + if ok then + return true, "User created"; + else + return nil, "Could not change password for user: "..err; + end +end + +def_env.xmpp = {}; + +local st = require "util.stanza"; +function def_env.xmpp:ping(localhost, remotehost) + if hosts[localhost] then + core_post_stanza(hosts[localhost], + st.iq{ from=localhost, to=remotehost, type="get", id="ping" } + :tag("ping", {xmlns="urn:xmpp:ping"})); + return true, "Sent ping"; + else + return nil, "No such host"; + end +end + ------------- function printbanner(session) diff --git a/plugins/mod_announce.lua b/plugins/mod_announce.lua index 77555bec..0cfd284c 100644 --- a/plugins/mod_announce.lua +++ b/plugins/mod_announce.lua @@ -25,7 +25,7 @@ function send_to_online(message, host) for username in pairs(host_session.sessions) do c = c + 1; message.attr.to = username.."@"..hostname; - core_post_stanza(host_session, message); + module:send(message); end end end @@ -96,5 +96,5 @@ end local adhoc_new = module:require "adhoc".new; local announce_desc = adhoc_new("Send Announcement to Online Users", "http://jabber.org/protocol/admin#announce", announce_handler, "admin"); -module:add_item("adhoc", announce_desc); +module:provides("adhoc", announce_desc); diff --git a/plugins/mod_auth_cyrus.lua b/plugins/mod_auth_cyrus.lua index 447fae51..e4493f04 100644 --- a/plugins/mod_auth_cyrus.lua +++ b/plugins/mod_auth_cyrus.lua @@ -14,6 +14,7 @@ local cyrus_service_realm = module:get_option("cyrus_service_realm"); local cyrus_service_name = module:get_option("cyrus_service_name"); local cyrus_application_name = module:get_option("cyrus_application_name"); local require_provisioning = module:get_option("cyrus_require_provisioning") or false; +local host_fqdn = module:get_option("cyrus_server_fqdn"); prosody.unlock_globals(); --FIXME: Figure out why this is needed and -- why cyrussasl isn't caught by the sandbox @@ -23,7 +24,8 @@ local new_sasl = function(realm) return cyrus_new( cyrus_service_realm or realm, cyrus_service_name or "xmpp", - cyrus_application_name or "prosody" + cyrus_application_name or "prosody", + host_fqdn ); end diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 8b612286..f6e3095e 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -14,7 +14,7 @@ local sm = require "core.sessionmanager"; local sm_destroy_session = sm.destroy_session; local new_uuid = require "util.uuid".generate; local fire_event = prosody.events.fire_event; -local core_process_stanza = core_process_stanza; +local core_process_stanza = prosody.core_process_stanza; local st = require "util.stanza"; local logger = require "util.logger"; local log = logger.init("mod_bosh"); @@ -56,7 +56,7 @@ local trusted_proxies = module:get_option_set("trusted_proxies", {"127.0.0.1"}). local function get_ip_from_request(request) local ip = request.conn:ip(); - local forwarded_for = request.headers["x-forwarded-for"]; + local forwarded_for = request.headers.x_forwarded_for; if forwarded_for then forwarded_for = forwarded_for..", "..ip; for forwarded_ip in forwarded_for:gmatch("[^%s,]+") do diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 55c53e2d..2318ecad 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -24,9 +24,11 @@ local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; local log = module._log; local c2s_timeout = module:get_option_number("c2s_timeout"); +local stream_close_timeout = module:get_option_number("c2s_close_timeout", 5); local opt_keepalives = module:get_option_boolean("tcp_keepalives", false); local sessions = module:shared("sessions"); +local core_process_stanza = prosody.core_process_stanza; local stream_callbacks = { default_ns = "jabber:client", handlestanza = core_process_stanza }; local listener = {}; @@ -75,7 +77,7 @@ end function stream_callbacks.streamclosed(session) session.log("debug", "Received </stream:stream>"); - session:close(); + session:close(false); end function stream_callbacks.error(session, error, data) @@ -121,9 +123,9 @@ local function session_close(session, reason) session.send("<?xml version='1.0'?>"); session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); end - if reason then + if reason then -- nil == no err, initiated by us, false == initiated by client if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting client, <stream:error> is: %s", reason); + log("debug", "Disconnecting client, <stream:error> is: %s", reason); session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); elseif type(reason) == "table" then if reason.condition then @@ -134,17 +136,36 @@ local function session_close(session, reason) if reason.extra then stanza:add_child(reason.extra); end - log("info", "Disconnecting client, <stream:error> is: %s", tostring(stanza)); + log("debug", "Disconnecting client, <stream:error> is: %s", tostring(stanza)); session.send(stanza); elseif reason.name then -- a stanza - log("info", "Disconnecting client, <stream:error> is: %s", tostring(reason)); + log("debug", "Disconnecting client, <stream:error> is: %s", tostring(reason)); session.send(reason); end end end + session.send("</stream:stream>"); - session.conn:close(); - listener.ondisconnect(session.conn, (reason and (reason.text or reason.condition)) or reason or "session closed"); + function session.send() return false; end + + local reason = (reason and (reason.text or reason.condition)) or reason; + session.log("info", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed"); + + -- Authenticated incoming stream may still be sending us stanzas, so wait for </stream:stream> from remote + local conn = session.conn; + if reason == nil and not session.notopen and session.type == "c2s" then + -- Grace time to process data from authenticated cleanly-closed stream + add_task(stream_close_timeout, function () + if not session.destroyed then + session.log("warn", "Failed to receive a stream close response, closing connection anyway..."); + sm_destroy_session(session, reason); + conn:close(); + end + end); + else + sm_destroy_session(session, reason); + conn:close(); + end end end @@ -208,10 +229,9 @@ end function listener.ondisconnect(conn, err) local session = sessions[conn]; if session then - (session.log or log)("info", "Client disconnected: %s", err); + (session.log or log)("info", "Client disconnected: %s", err or "connection closed"); sm_destroy_session(session, err); sessions[conn] = nil; - session = nil; end end diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua index 738124cc..751de59b 100644 --- a/plugins/mod_component.lua +++ b/plugins/mod_component.lua @@ -18,6 +18,8 @@ local jid_split = require "util.jid".split; local new_xmpp_stream = require "util.xmppstream".new; local uuid_gen = require "util.uuid".generate; +local core_process_stanza = prosody.core_process_stanza; + local log = module._log; @@ -124,7 +126,7 @@ local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; function stream_callbacks.error(session, error, data, data2) if session.destroyed then return; end - module:log("warn", "Error processing component stream: "..tostring(error)); + module:log("warn", "Error processing component stream: %s", tostring(error)); if error == "no-stream" then session:close("invalid-namespace"); elseif error == "parse-error" then @@ -169,8 +171,6 @@ function stream_callbacks.streamclosed(session) session:close(); end -local core_process_stanza = core_process_stanza; - function stream_callbacks.handlestanza(session, stanza) -- Namespaces are icky. if not stanza.attr.xmlns and stanza.name == "handshake" then diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index 2299c0dc..69616a57 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -41,6 +41,11 @@ module:hook("stanza/jabber:server:dialback:verify", function(event) -- We are being asked to verify the key, to ensure it was generated by us origin.log("debug", "verifying that dialback key is ours..."); local attr = stanza.attr; + if attr.type then + module:log("warn", "Ignoring incoming session from %s claiming a dialback key for %s is %s", + origin.from_host or "(unknown)", attr.from or "(unknown)", attr.type); + return true; + end -- COMPAT: Grr, ejabberd breaks this one too?? it is black and white in XEP-220 example 34 --if attr.from ~= origin.to_host then error("invalid-from"); end local type; @@ -84,7 +89,7 @@ module:hook("stanza/jabber:server:dialback:result", function(event) origin.from_host = from; end if not origin.to_host then - origin.to_host = nameprep(attr.to); + origin.to_host = to; end origin.log("debug", "asking %s if key %s belongs to them", from, stanza[1]); @@ -102,7 +107,6 @@ module:hook("stanza/jabber:server:dialback:verify", function(event) if origin.type == "s2sout_unauthed" or origin.type == "s2sout" then local attr = stanza.attr; local dialback_verifying = dialback_requests[attr.from.."/"..(attr.id or "")]; - module:log("debug", tostring(dialback_verifying).." "..attr.from.." "..origin.to_host); if dialback_verifying and attr.from == origin.to_host then local valid; if attr.type == "valid" then @@ -110,7 +114,7 @@ module:hook("stanza/jabber:server:dialback:verify", function(event) valid = "valid"; else -- Warn the original connection that is was not verified successfully - log("warn", "authoritative server for "..(attr.from or "(unknown)").." denied the key"); + log("warn", "authoritative server for %s denied the key", attr.from or "(unknown)"); valid = "invalid"; end if not dialback_verifying.sends2s then diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index c3a9c54d..6587d435 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -32,7 +32,7 @@ do -- validate disco_items end end -module:add_identity("server", "im", "Prosody"); -- FIXME should be in the non-existing mod_router +module:add_identity("server", "im", module:get_option_string("name", "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"); diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index 6412ad11..8044a533 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -17,10 +17,7 @@ if module:get_host_type() == "local" then local origin, stanza = data.origin, data.stanza; local session = full_sessions[stanza.attr.to]; - if session then - -- TODO fire post processing event - session.send(stanza); - else -- resource not online + if not (session and session.send(stanza)) then if stanza.attr.type == "get" or stanza.attr.type == "set" then origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end diff --git a/plugins/mod_message.lua b/plugins/mod_message.lua index ebff2fe7..0b0ad8e4 100644 --- a/plugins/mod_message.lua +++ b/plugins/mod_message.lua @@ -35,10 +35,13 @@ local function process_to_bare(bare, origin, stanza) if user then -- some resources are connected local recipients = user.top_resources; if recipients then + local sent; for i=1,#recipients do - recipients[i].send(stanza); + sent = recipients[i].send(stanza) or sent; + end + if sent then + return true; end - return true; end end -- no resources are online @@ -65,9 +68,7 @@ module:hook("message/full", function(data) local origin, stanza = data.origin, data.stanza; local session = full_sessions[stanza.attr.to]; - if session then - -- TODO fire post processing event - session.send(stanza); + if session and session.send(stanza) then return true; else -- resource not online return process_to_bare(jid_bare(stanza.attr.to), origin, stanza); diff --git a/plugins/mod_motd.lua b/plugins/mod_motd.lua index 39b74de9..ddde9c78 100644 --- a/plugins/mod_motd.lua +++ b/plugins/mod_motd.lua @@ -24,7 +24,7 @@ module:hook("presence/bare", function (event) local motd_stanza = st.message({ to = session.full_jid, from = motd_jid }) :tag("body"):text(motd_text); - core_route_stanza(hosts[host], motd_stanza); + module:send(motd_stanza); module:log("debug", "MOTD send to user %s", session.full_jid); end end, 1); diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index bbdd5f19..c2261e5f 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -17,6 +17,7 @@ local pairs, ipairs = pairs, ipairs; local next = next; local type = type; local calculate_hash = require "util.caps".calculate_hash; +local core_post_stanza = prosody.core_post_stanza; local NULL = {}; local data = {}; @@ -32,7 +33,7 @@ module.restore = function(state) hash_map = state.hash_map or {}; end -module:add_identity("pubsub", "pep", "Prosody"); +module:add_identity("pubsub", "pep", module:get_option_string("name", "Prosody")); module:add_feature("http://jabber.org/protocol/pubsub#publish"); local function subscription_presence(user_bare, recipient) diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua index 1670ac95..db594ccc 100644 --- a/plugins/mod_posix.lua +++ b/plugins/mod_posix.lua @@ -34,19 +34,19 @@ module:hook("server-started", function () if gid then local success, msg = pposix.setgid(gid); if success then - module:log("debug", "Changed group to "..gid.." successfully."); + module:log("debug", "Changed group to %s successfully.", gid); else - module:log("error", "Failed to change group to "..gid..". Error: "..msg); - prosody.shutdown("Failed to change group to "..gid); + module:log("error", "Failed to change group to %s. Error: %s", gid, msg); + prosody.shutdown("Failed to change group to %s", gid); end end if uid then local success, msg = pposix.setuid(uid); if success then - module:log("debug", "Changed user to "..uid.." successfully."); + module:log("debug", "Changed user to %s successfully.", uid); else - module:log("error", "Failed to change user to "..uid..". Error: "..msg); - prosody.shutdown("Failed to change user to "..uid); + module:log("error", "Failed to change user to %s. Error: %s", uid, msg); + prosody.shutdown("Failed to change user to %s", uid); end end end); diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua index 6d039d83..dac86ae6 100644 --- a/plugins/mod_presence.lua +++ b/plugins/mod_presence.lua @@ -14,6 +14,7 @@ local t_concat, t_insert = table.concat, table.insert; local s_find = string.find; local tonumber = tonumber; +local core_post_stanza = prosody.core_post_stanza; local st = require "util.stanza"; local jid_split = require "util.jid".split; local jid_bare = require "util.jid".bare; @@ -160,7 +161,7 @@ function send_presence_of_available_resources(user, host, jid, recipient_session end end end - log("debug", "broadcasted presence of "..count.." resources from "..user.."@"..host.." to "..jid); + log("debug", "broadcasted presence of %d resources from %s@%s to %s", count, user, host, jid); return count; end @@ -169,7 +170,7 @@ function handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_ if to_bare == from_bare then return; end -- No self contacts local st_from, st_to = stanza.attr.from, stanza.attr.to; stanza.attr.from, stanza.attr.to = from_bare, to_bare; - log("debug", "outbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare); + log("debug", "outbound presence %s from %s for %s", stanza.attr.type, from_bare, to_bare); if stanza.attr.type == "probe" then stanza.attr.from, stanza.attr.to = st_from, st_to; return; @@ -214,7 +215,7 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b local node, host = jid_split(to_bare); local st_from, st_to = stanza.attr.from, stanza.attr.to; stanza.attr.from, stanza.attr.to = from_bare, to_bare; - log("debug", "inbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare); + log("debug", "inbound presence %s from %s for %s", stanza.attr.type, from_bare, to_bare); if stanza.attr.type == "probe" then local result, err = rostermanager.is_contact_subscribed(node, host, from_bare); @@ -352,13 +353,15 @@ module:hook("resource-unbind", function(event) -- Send unavailable presence if session.presence then local pres = st.presence{ type = "unavailable" }; - if not(err) or err == "closed" then err = "connection closed"; end - pres:tag("status"):text("Disconnected: "..err):up(); + if err then + pres:tag("status"):text("Disconnected: "..err):up(); + end session:dispatch_stanza(pres); elseif session.directed then local pres = st.presence{ type = "unavailable", from = session.full_jid }; - if not(err) or err == "closed" then err = "connection closed"; end - pres:tag("status"):text("Disconnected: "..err):up(); + if err then + pres:tag("status"):text("Disconnected: "..err):up(); + end for jid in pairs(session.directed) do pres.attr.to = jid; core_post_stanza(session, pres, true); diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua index 2cbd7184..40b119cc 100644 --- a/plugins/mod_pubsub.lua +++ b/plugins/mod_pubsub.lua @@ -201,7 +201,7 @@ function simple_broadcast(node, jids, item) for jid in pairs(jids) do module:log("debug", "Sending notification to %s", jid); message.attr.to = jid; - core_post_stanza(hosts[module.host], message); + module:send(message); end end diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index 755b718e..6c690c3b 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -120,10 +120,10 @@ local function handle_registration_stanza(event) for jid, item in pairs(roster) do if jid and jid ~= "pending" then if item.subscription == "both" or item.subscription == "from" or (roster.pending and roster.pending[jid]) then - core_post_stanza(hosts[host], st.presence({type="unsubscribed", from=bare, to=jid})); + module:send(st.presence({type="unsubscribed", from=bare, to=jid})); end if item.subscription == "both" or item.subscription == "to" or item.ask then - core_post_stanza(hosts[host], st.presence({type="unsubscribe", from=bare, to=jid})); + module:send(st.presence({type="unsubscribe", from=bare, to=jid})); end end end diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua index 96cc15f2..bfb2d927 100644 --- a/plugins/mod_roster.lua +++ b/plugins/mod_roster.lua @@ -18,7 +18,7 @@ local pairs, ipairs = pairs, ipairs; local rm_remove_from_roster = require "core.rostermanager".remove_from_roster; local rm_add_to_roster = require "core.rostermanager".add_to_roster; local rm_roster_push = require "core.rostermanager".roster_push; -local core_post_stanza = core_post_stanza; +local core_post_stanza = prosody.core_post_stanza; module:add_feature("jabber:iq:roster"); diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index f6c20606..321ed0d7 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -10,7 +10,7 @@ module:set_global(); local prosody = prosody; local hosts = prosody.hosts; -local core_process_stanza = core_process_stanza; +local core_process_stanza = prosody.core_process_stanza; local tostring, type = tostring, type; local t_insert = table.insert; @@ -30,7 +30,8 @@ local cert_verify_identity = require "util.x509".verify_identity; local s2sout = module:require("s2sout"); -local connect_timeout = module:get_option_number("s2s_timeout", 60); +local connect_timeout = module:get_option_number("s2s_timeout", 90); +local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5); local sessions = module:shared("sessions"); @@ -97,9 +98,10 @@ function route_to_existing_session(event) log("error", "WARNING! This might, possibly, be a bug, but it might not..."); log("error", "We are going to send from %s instead of %s", tostring(host.from_host), tostring(from_host)); end - host.sends2s(stanza); - host.log("debug", "stanza sent over "..host.type); - return true; + if host.sends2s(stanza) then + host.log("debug", "stanza sent over %s", host.type); + return true; + end end end end @@ -288,19 +290,7 @@ end function stream_callbacks.streamclosed(session) (session.log or log)("debug", "Received </stream:stream>"); - session:close(); -end - -function stream_callbacks.streamdisconnected(session, err) - if err and err ~= "closed" and session.direction == "outgoing" and session.notopen then - (session.log or log)("debug", "s2s connection attempt failed: %s", err); - if s2sout.attempt_connection(session, err) then - (session.log or log)("debug", "...so we're going to try another target"); - return true; -- Session lives for now - end - end - (session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "closed")); - s2s_destroy_session(session, err); + session:close(false); end function stream_callbacks.error(session, error, data) @@ -352,9 +342,9 @@ local function session_close(session, reason, remote_reason) session.sends2s("<?xml version='1.0'?>"); session.sends2s(st.stanza("stream:stream", default_stream_attr):top_tag()); end - if reason then + if reason then -- nil == no err, initiated by us, false == initiated by remote if type(reason) == "string" then -- assume stream error - log("info", "Disconnecting %s[%s], <stream:error> is: %s", session.host or "(unknown host)", session.type, reason); + log("debug", "Disconnecting %s[%s], <stream:error> is: %s", session.host or "(unknown host)", session.type, reason); session.sends2s(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); elseif type(reason) == "table" then if reason.condition then @@ -365,20 +355,35 @@ local function session_close(session, reason, remote_reason) if reason.extra then stanza:add_child(reason.extra); end - log("info", "Disconnecting %s[%s], <stream:error> is: %s", session.host or "(unknown host)", session.type, tostring(stanza)); + log("debug", "Disconnecting %s[%s], <stream:error> is: %s", session.host or "(unknown host)", session.type, tostring(stanza)); session.sends2s(stanza); elseif reason.name then -- a stanza - log("info", "Disconnecting %s->%s[%s], <stream:error> is: %s", session.from_host or "(unknown host)", session.to_host or "(unknown host)", session.type, tostring(reason)); + log("debug", "Disconnecting %s->%s[%s], <stream:error> is: %s", session.from_host or "(unknown host)", session.to_host or "(unknown host)", session.type, tostring(reason)); session.sends2s(reason); end end end + session.sends2s("</stream:stream>"); - if session.notopen or not session.conn:close() then - session.conn:close(true); -- Force FIXME: timer? + function session.sends2s() return false; end + + local reason = remote_reason or (reason and (reason.text or reason.condition)) or reason; + session.log("info", "%s s2s stream %s->%s closed: %s", session.direction, session.from_host or "(unknown host)", session.to_host or "(unknown host)", reason or "stream closed"); + + -- Authenticated incoming stream may still be sending us stanzas, so wait for </stream:stream> from remote + local conn = session.conn; + if reason == nil and not session.notopen and session.type == "s2sin" then + add_task(stream_close_timeout, function () + if not session.destroyed then + session.log("warn", "Failed to receive a stream close response, closing connection anyway..."); + s2s_destroy_session(session, reason); + conn:close(); + end + end); + else + s2s_destroy_session(session, reason); + conn:close(); -- Close immediately, as this is an outgoing connection or is not authed end - session.conn:close(); - listener.ondisconnect(session.conn, remote_reason or (reason and (reason.text or reason.condition)) or reason or "stream closed"); end end @@ -413,11 +418,9 @@ local function initialize_session(session) return handlestanza(session, stanza); end - local conn = session.conn; add_task(connect_timeout, function () - if session.conn ~= conn or session.connecting - or session.type == "s2sin" or session.type == "s2sout" then - return; -- Ok, we're connect[ed|ing] + if session.type == "s2sin" or session.type == "s2sout" then + return; -- Ok, we're connected end -- Not connected, need to close session and clean up (session.log or log)("debug", "Destroying incomplete session %s->%s due to inactivity", @@ -474,11 +477,17 @@ end function listener.ondisconnect(conn, err) local session = sessions[conn]; if session then - if stream_callbacks.streamdisconnected(session, err) then - return; -- Connection lives, for now + if err and session.direction == "outgoing" and session.notopen then + (session.log or log)("debug", "s2s connection attempt failed: %s", err); + if s2sout.attempt_connection(session, err) then + (session.log or log)("debug", "...so we're going to try another target"); + return; -- Session lives for now + end end + (session.log or log)("debug", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "connection closed")); + s2s_destroy_session(session, err); + sessions[conn] = nil; end - sessions[conn] = nil; end function listener.register_outgoing(conn, session) diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua index 48a49036..17978b39 100644 --- a/plugins/mod_s2s/s2sout.lib.lua +++ b/plugins/mod_s2s/s2sout.lib.lua @@ -95,14 +95,14 @@ function s2sout.attempt_connection(host_session, err) handle = nil; host_session.connecting = nil; if answer then - log("debug", to_host.." has SRV records, handling..."); + log("debug", "%s has SRV records, handling...", to_host); local srv_hosts = {}; host_session.srv_hosts = srv_hosts; for _, record in ipairs(answer) do t_insert(srv_hosts, record.srv); end if #srv_hosts == 1 and srv_hosts[1].target == "." then - log("debug", to_host.." does not provide a XMPP service"); + log("debug", "%s does not provide a XMPP service", to_host); s2s_destroy_session(host_session, err); -- Nothing to see here return; end @@ -115,7 +115,7 @@ function s2sout.attempt_connection(host_session, err) log("debug", "Best record found, will connect to %s:%d", connect_host, connect_port); end else - log("debug", to_host.." has no SRV records, falling back to A/AAAA"); + log("debug", "%s has no SRV records, falling back to A/AAAA", to_host); end -- Try with SRV, or just the plain hostname if no SRV local ok, err = s2sout.try_connect(host_session, connect_host, connect_port); @@ -170,92 +170,91 @@ function s2sout.try_connect(host_session, connect_host, connect_port, err) local IPs = {}; host_session.ip_hosts = IPs; local handle4, handle6; - local has_other = false; + local have_other_result = not(has_ipv4) or not(has_ipv6) or false; if has_ipv4 then - handle4 = adns.lookup(function (reply, err) - handle4 = nil; - - -- COMPAT: This is a compromise for all you CNAME-(ab)users :) - if not (reply and reply[#reply] and reply[#reply].a) then - local count = max_dns_depth; - reply = dns.peek(connect_host, "CNAME", "IN"); - while count > 0 and reply and reply[#reply] and not reply[#reply].a and reply[#reply].cname do - log("debug", "Looking up %s (DNS depth is %d)", tostring(reply[#reply].cname), count); - reply = dns.peek(reply[#reply].cname, "A", "IN") or dns.peek(reply[#reply].cname, "CNAME", "IN"); - count = count - 1; + handle4 = adns.lookup(function (reply, err) + handle4 = nil; + + -- COMPAT: This is a compromise for all you CNAME-(ab)users :) + if not (reply and reply[#reply] and reply[#reply].a) then + local count = max_dns_depth; + reply = dns.peek(connect_host, "CNAME", "IN"); + while count > 0 and reply and reply[#reply] and not reply[#reply].a and reply[#reply].cname do + log("debug", "Looking up %s (DNS depth is %d)", tostring(reply[#reply].cname), count); + reply = dns.peek(reply[#reply].cname, "A", "IN") or dns.peek(reply[#reply].cname, "CNAME", "IN"); + count = count - 1; + end end - end - -- end of CNAME resolving + -- end of CNAME resolving - if reply and reply[#reply] and reply[#reply].a then - for _, ip in ipairs(reply) do - log("debug", "DNS reply for %s gives us %s", connect_host, ip.a); - IPs[#IPs+1] = new_ip(ip.a, "IPv4"); + if reply and reply[#reply] and reply[#reply].a then + for _, ip in ipairs(reply) do + log("debug", "DNS reply for %s gives us %s", connect_host, ip.a); + IPs[#IPs+1] = new_ip(ip.a, "IPv4"); + end end - end - if has_other then - if #IPs > 0 then - rfc3484_dest(host_session.ip_hosts, sources); - for i = 1, #IPs do - IPs[i] = {ip = IPs[i], port = connect_port}; + if have_other_result then + if #IPs > 0 then + rfc3484_dest(host_session.ip_hosts, sources); + for i = 1, #IPs do + IPs[i] = {ip = IPs[i], port = connect_port}; + end + host_session.ip_choice = 0; + s2sout.try_next_ip(host_session); + else + log("debug", "DNS lookup failed to get a response for %s", connect_host); + host_session.ip_hosts = nil; + if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can + log("debug", "No other records to try for %s - destroying", host_session.to_host); + err = err and (": "..err) or ""; + s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't + end end - host_session.ip_choice = 0; - s2sout.try_next_ip(host_session); else - log("debug", "DNS lookup failed to get a response for %s", connect_host); - host_session.ip_hosts = nil; - if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can - log("debug", "No other records to try for %s - destroying", host_session.to_host); - err = err and (": "..err) or ""; - s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't - end + have_other_result = true; end - else - has_other = true; - end - end, connect_host, "A", "IN"); + end, connect_host, "A", "IN"); else - has_other = true; + have_other_result = true; end if has_ipv6 then - handle6 = adns.lookup(function (reply, err) - handle6 = nil; + handle6 = adns.lookup(function (reply, err) + handle6 = nil; - if reply and reply[#reply] and reply[#reply].aaaa then - for _, ip in ipairs(reply) do - log("debug", "DNS reply for %s gives us %s", connect_host, ip.aaaa); - IPs[#IPs+1] = new_ip(ip.aaaa, "IPv6"); + if reply and reply[#reply] and reply[#reply].aaaa then + for _, ip in ipairs(reply) do + log("debug", "DNS reply for %s gives us %s", connect_host, ip.aaaa); + IPs[#IPs+1] = new_ip(ip.aaaa, "IPv6"); + end end - end - if has_other then - if #IPs > 0 then - rfc3484_dest(host_session.ip_hosts, sources); - for i = 1, #IPs do - IPs[i] = {ip = IPs[i], port = connect_port}; + if have_other_result then + if #IPs > 0 then + rfc3484_dest(host_session.ip_hosts, sources); + for i = 1, #IPs do + IPs[i] = {ip = IPs[i], port = connect_port}; + end + host_session.ip_choice = 0; + s2sout.try_next_ip(host_session); + else + log("debug", "DNS lookup failed to get a response for %s", connect_host); + host_session.ip_hosts = nil; + if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can + log("debug", "No other records to try for %s - destroying", host_session.to_host); + err = err and (": "..err) or ""; + s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't + end end - host_session.ip_choice = 0; - s2sout.try_next_ip(host_session); else - log("debug", "DNS lookup failed to get a response for %s", connect_host); - host_session.ip_hosts = nil; - if not s2sout.attempt_connection(host_session, "name resolution failed") then -- Retry if we can - log("debug", "No other records to try for %s - destroying", host_session.to_host); - err = err and (": "..err) or ""; - s2s_destroy_session(host_session, "DNS resolution failed"..err); -- End of the line, we can't - end + have_other_result = true; end - else - has_other = true; - end - end, connect_host, "AAAA", "IN"); + end, connect_host, "AAAA", "IN"); else - has_other = true; + have_other_result = true; end - return true; elseif host_session.ip_hosts and #host_session.ip_hosts > host_session.ip_choice then -- Not our first attempt, and we also have IPs left to try s2sout.try_next_ip(host_session); diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 804db5f9..f6abd3b8 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -208,7 +208,7 @@ module:hook("stanza/urn:ietf:params:xml:ns:xmpp-sasl:auth", function(event) session.sasl_handler = nil; -- allow starting a new SASL negotiation before completing an old one end if not session.sasl_handler then - session.sasl_handler = usermanager_get_sasl_handler(module.host); + session.sasl_handler = usermanager_get_sasl_handler(module.host, session); end local mechanism = stanza.attr.mechanism; if not session.secure and (secure_auth_only or (mechanism == "PLAIN" and not allow_unencrypted_plain_auth)) then @@ -246,7 +246,7 @@ module:hook("stream-features", function(event) if secure_auth_only and not origin.secure then return; end - origin.sasl_handler = usermanager_get_sasl_handler(module.host); + origin.sasl_handler = usermanager_get_sasl_handler(module.host, origin); local mechanisms = st.stanza("mechanisms", mechanisms_attr); for mechanism in pairs(origin.sasl_handler:mechanisms()) do if mechanism ~= "PLAIN" or origin.secure or allow_unencrypted_plain_auth then diff --git a/plugins/mod_vcard.lua b/plugins/mod_vcard.lua index e2f1dfb8..d3c27cc0 100644 --- a/plugins/mod_vcard.lua +++ b/plugins/mod_vcard.lua @@ -46,13 +46,8 @@ end module:hook("iq/bare/vcard-temp:vCard", handle_vcard); module:hook("iq/host/vcard-temp:vCard", handle_vcard); --- COMPAT: https://support.process-one.net/browse/EJAB-1045 -if module:get_option("vcard_compatibility") then - module:hook("iq/full", function(data) - local stanza = data.stanza; - local payload = stanza.tags[1]; - if stanza.attr.type == "get" and payload.name == "vCard" and payload.attr.xmlns == "vcard-temp" then - return handle_vcard(data); - end - end, 1); +-- COMPAT w/0.8 +if module:get_option("vcard_compatibility") ~= nil then + module:log("error", "The vcard_compatibility option has been removed, see".. + "mod_compat_vcard in prosody-modules if you still need this."); end diff --git a/plugins/mod_watchregistrations.lua b/plugins/mod_watchregistrations.lua index ef18d713..abca90bd 100644 --- a/plugins/mod_watchregistrations.lua +++ b/plugins/mod_watchregistrations.lua @@ -25,6 +25,6 @@ module:hook("user-registered", function (user) for jid in registration_watchers do module:log("debug", "Notifying %s", jid); message.attr.to = jid; - core_route_stanza(hosts[host], message); + module:send(message); end end); diff --git a/plugins/mod_welcome.lua b/plugins/mod_welcome.lua index 8f9cca2a..e498f0b3 100644 --- a/plugins/mod_welcome.lua +++ b/plugins/mod_welcome.lua @@ -16,6 +16,6 @@ module:hook("user-registered", local welcome_stanza = st.message({ to = user.username.."@"..user.host, from = host }) :tag("body"):text(welcome_text:gsub("$(%w+)", user)); - core_route_stanza(hosts[host], welcome_stanza); + module:send(welcome_stanza); module:log("debug", "Welcomed user %s@%s", user.username, user.host); end); diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 43b8423d..0fa172ee 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -29,11 +29,11 @@ local st = require "util.stanza"; local uuid_gen = require "util.uuid".generate; local datamanager = require "util.datamanager"; local um_is_admin = require "core.usermanager".is_admin; +local hosts = hosts; rooms = {}; local rooms = rooms; local persistent_rooms = datamanager.load(nil, muc_host, "persistent") or {}; -local component = hosts[module.host]; -- Configurable options local max_history_messages = module:get_option_number("max_history_messages"); @@ -42,7 +42,7 @@ local function is_admin(jid) return um_is_admin(jid, module.host); end -local function room_route_stanza(room, stanza) core_post_stanza(component, stanza); end +local function room_route_stanza(room, stanza) module:send(stanza); end local function room_save(room, forced) local node = jid_split(room.jid); persistent_rooms[room.jid] = room._data.persistent; @@ -65,19 +65,27 @@ local function room_save(room, forced) if forced then datamanager.store(nil, muc_host, "persistent", persistent_rooms); end end +local persistent_errors = false; for jid in pairs(persistent_rooms) do local node = jid_split(jid); - local data = datamanager.load(node, muc_host, "config") or {}; - local room = muc_new_room(jid, { - max_history_length = max_history_messages; - }); - room._data = data._data; - room._data.max_history_length = max_history_messages; -- Overwrite old max_history_length in data with current settings - room._affiliations = data._affiliations; - room.route_stanza = room_route_stanza; - room.save = room_save; - rooms[jid] = room; + local data = datamanager.load(node, muc_host, "config"); + if data then + local room = muc_new_room(jid, { + max_history_length = max_history_messages; + }); + room._data = data._data; + room._data.max_history_length = max_history_messages; -- Overwrite old max_history_length in data with current settings + room._affiliations = data._affiliations; + room.route_stanza = room_route_stanza; + room.save = room_save; + rooms[jid] = room; + else -- missing room data + persistent_rooms[jid] = nil; + module:log("error", "Missing data for room '%s', removing from persistent room list", jid); + persistent_errors = true; + end end +if persistent_errors then datamanager.store(nil, muc_host, "persistent", persistent_rooms); end local host_room = muc_new_room(muc_host, { max_history_length = max_history_messages; @@ -160,11 +168,11 @@ module:hook("presence/host", handle_to_domain, -1); hosts[module.host].send = function(stanza) -- FIXME do a generic fix if stanza.attr.type == "result" or stanza.attr.type == "error" then - core_post_stanza(component, stanza); + module:send(stanza); else error("component.send only supports result and error stanzas at the moment"); end end -prosody.hosts[module:get_host()].muc = { rooms = rooms }; +hosts[module:get_host()].muc = { rooms = rooms }; module.save = function() return {rooms = rooms}; @@ -180,5 +188,5 @@ module.restore = function(data) room.save = room_save; rooms[jid] = room; end - prosody.hosts[module:get_host()].muc = { rooms = rooms }; + hosts[module:get_host()].muc = { rooms = rooms }; end diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 5178cb1e..a40dc05f 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -856,7 +856,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha if not occupant then -- not in room origin.send(st.error_reply(stanza, "cancel", "not-acceptable")); elseif occupant.role == "visitor" then - origin.send(st.error_reply(stanza, "cancel", "forbidden")); + origin.send(st.error_reply(stanza, "auth", "forbidden")); else local from = stanza.attr.from; stanza.attr.from = current_nick; @@ -867,7 +867,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha self:set_subject(current_nick, subject); -- TODO use broadcast_message_stanza else stanza.attr.from = from; - origin.send(st.error_reply(stanza, "cancel", "forbidden")); + origin.send(st.error_reply(stanza, "auth", "forbidden")); end else self:broadcast_message(stanza, self:get_historylength() > 0); |