diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/mod_admin_telnet.lua | 69 | ||||
-rw-r--r-- | plugins/mod_blocklist.lua | 2 | ||||
-rw-r--r-- | plugins/mod_bosh.lua | 16 | ||||
-rw-r--r-- | plugins/mod_c2s.lua | 4 | ||||
-rw-r--r-- | plugins/mod_component.lua | 14 | ||||
-rw-r--r-- | plugins/mod_groups.lua | 6 | ||||
-rw-r--r-- | plugins/mod_limits.lua | 22 | ||||
-rw-r--r-- | plugins/mod_mam/mod_mam.lua | 24 | ||||
-rw-r--r-- | plugins/mod_muc_mam.lua | 10 | ||||
-rw-r--r-- | plugins/mod_pep.lua | 2 | ||||
-rw-r--r-- | plugins/mod_pep_simple.lua | 4 | ||||
-rw-r--r-- | plugins/mod_proxy65.lua | 2 | ||||
-rw-r--r-- | plugins/mod_pubsub/mod_pubsub.lua | 2 | ||||
-rw-r--r-- | plugins/mod_pubsub/pubsub.lib.lua | 21 | ||||
-rw-r--r-- | plugins/mod_s2s/mod_s2s.lua | 56 | ||||
-rw-r--r-- | plugins/mod_s2s/s2sout.lib.lua | 349 | ||||
-rw-r--r-- | plugins/mod_saslauth.lua | 3 | ||||
-rw-r--r-- | plugins/mod_stanza_debug.lua | 5 | ||||
-rw-r--r-- | plugins/mod_vcard_legacy.lua | 13 | ||||
-rw-r--r-- | plugins/mod_websocket.lua | 3 | ||||
-rw-r--r-- | plugins/muc/language.lib.lua | 1 |
21 files changed, 173 insertions, 455 deletions
diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index fa03840b..b6cdfe82 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -62,6 +62,9 @@ end function runner_callbacks:error(err) module:log("error", "Traceback[telnet]: %s", err); + + self.data.print("Fatal error while running command, it did not complete"); + self.data.print("Error: "..tostring(err)); end @@ -114,6 +117,11 @@ function console:process_line(session, line) session.env._ = line; + if not useglobalenv and commands[line:lower()] then + commands[line:lower()](session, line); + return; + end + local chunkname = "=console"; local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil local chunk, err = envload("return "..line, chunkname, env); @@ -128,18 +136,7 @@ function console:process_line(session, line) end end - local ranok, taskok, message = pcall(chunk); - - if not (ranok or message or useglobalenv) and commands[line:lower()] then - commands[line:lower()](session, line); - return; - end - - if not ranok then - session.print("Fatal error while running command, it did not complete"); - session.print("Error: "..taskok); - return; - end + local taskok, message = chunk(); if not message then session.print("Result: "..tostring(taskok)); @@ -242,6 +239,7 @@ function commands.help(session, data) print [[server - Uptime, version, shutting down, etc.]] print [[port - Commands to manage ports the server is listening on]] print [[dns - Commands to manage and inspect the internal DNS resolver]] + print [[xmpp - Commands for sending XMPP stanzas]] print [[config - Reloading the configuration, etc.]] print [[console - Help regarding the console itself]] elseif section == "c2s" then @@ -249,6 +247,7 @@ function commands.help(session, data) print [[c2s:show_insecure() - Show all unencrypted client connections]] print [[c2s:show_secure() - Show all encrypted client connections]] print [[c2s:show_tls() - Show TLS cipher info for encrypted sessions]] + print [[c2s:count() - Count sessions without listing them]] print [[c2s:close(jid) - Close all sessions for the specified JID]] print [[c2s:closeall() - Close all active c2s connections ]] elseif section == "s2s" then @@ -284,6 +283,8 @@ function commands.help(session, data) print [[dns:setnameserver(nameserver) - Replace the list of name servers with the supplied one]] print [[dns:purge() - Clear the DNS cache]] print [[dns:cache() - Show cached records]] + elseif section == "xmpp" then + print [[xmpp:ping(localhost, remotehost) -- Sends a ping to a remote XMPP server and reports the response]] elseif section == "config" then print [[config:reload() - Reload the server configuration. Modules may need to be reloaded for changes to take effect.]] elseif section == "console" then @@ -595,10 +596,16 @@ local function get_jid(session) return jid_join("["..ip.."]:"..clientport, session.host or "["..serverip.."]:"..serverport); end -local function show_c2s(callback) - local c2s = array.collect(values(module:shared"/*/c2s/sessions")); +local function get_c2s() + local c2s = array.collect(values(prosody.full_sessions)); + c2s:append(array.collect(values(module:shared"/*/c2s/sessions"))); c2s:append(array.collect(values(module:shared"/*/bosh/sessions"))); - c2s:sort(function(a, b) + c2s:unique(); + return c2s; +end + +local function show_c2s(callback) + get_c2s():sort(function(a, b) if a.host == b.host then if a.username == b.username then return (a.resource or "") > (b.resource or ""); @@ -612,9 +619,8 @@ local function show_c2s(callback) end function def_env.c2s:count() - local c2s_count = iterators.count(values(module:shared"/*/c2s/sessions")) - local bosh_count = iterators.count(values(module:shared"/*/bosh/sessions")) - return true, "Total: ".. c2s_count + bosh_count .." clients"; + local c2s = get_c2s(); + return true, "Total: ".. #c2s .." clients"; end function def_env.c2s:show(match_jid, annotate) @@ -660,23 +666,32 @@ function def_env.c2s:show_tls(match_jid) return self:show(match_jid, tls_info); end -function def_env.c2s:close(match_jid) +local function build_reason(text, condition) + if text or condition then + return { + text = text, + condition = condition or "undefined-condition", + }; + end +end + +function def_env.c2s:close(match_jid, text, condition) local count = 0; show_c2s(function (jid, session) if jid == match_jid or jid_bare(jid) == match_jid then count = count + 1; - session:close(); + session:close(build_reason(text, condition)); end end); return true, "Total: "..count.." sessions closed"; end -function def_env.c2s:closeall() +function def_env.c2s:closeall(text, condition) local count = 0; --luacheck: ignore 212/jid show_c2s(function (jid, session) count = count + 1; - session:close(); + session:close(build_reason(text, condition)); end); return true, "Total: "..count.." sessions closed"; end @@ -881,7 +896,7 @@ function def_env.s2s:showcert(domain) .." presented by "..domain.."."); end -function def_env.s2s:close(from, to) +function def_env.s2s:close(from, to, text, condition) local print, count = self.session.print, 0; local s2s_sessions = module:shared"/*/s2s/sessions"; @@ -895,23 +910,23 @@ function def_env.s2s:close(from, to) end for _, session in pairs(s2s_sessions) do - local id = session.type..tostring(session):match("[a-f0-9]+$"); + local id = session.id or (session.type..tostring(session):match("[a-f0-9]+$")); if (match_id and match_id == id) or (session.from_host == from and session.to_host == to) then print(("Closing connection from %s to %s [%s]"):format(session.from_host, session.to_host, id)); - (session.close or s2smanager.destroy_session)(session); + (session.close or s2smanager.destroy_session)(session, build_reason(text, condition)); count = count + 1 ; end end return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end -function def_env.s2s:closeall(host) +function def_env.s2s:closeall(host, text, condition) local count = 0; local s2s_sessions = module:shared"/*/s2s/sessions"; for _,session in pairs(s2s_sessions) do if not host or session.from_host == host or session.to_host == host then - session:close(); + session:close(build_reason(text, condition)); count = count + 1; end end diff --git a/plugins/mod_blocklist.lua b/plugins/mod_blocklist.lua index cf8aad80..dad06b62 100644 --- a/plugins/mod_blocklist.lua +++ b/plugins/mod_blocklist.lua @@ -67,7 +67,7 @@ local function migrate_privacy_list(username) if item.type == "jid" and item.action == "deny" then local jid = jid_prep(item.value); if not jid then - module:log("warn", "Invalid JID in privacy store for user '%s' not migrated: %s", username, tostring(item.value)); + module:log("warn", "Invalid JID in privacy store for user '%s' not migrated: %s", username, item.value); else migrated_data[jid] = true; end diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index d4e980f2..f4d7eba2 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -78,7 +78,7 @@ end); -- Used to respond to idle sessions (those with waiting requests) function on_destroy_request(request) - log("debug", "Request destroyed: %s", tostring(request)); + log("debug", "Request destroyed: %s", request); local session = sessions[request.context.sid]; if session then local requests = session.requests; @@ -115,7 +115,7 @@ function session_timeout(now, session, context, reason) -- luacheck: ignore 212/ end function handle_POST(event) - log("debug", "Handling new request %s: %s\n----------", tostring(event.request), tostring(event.request.body)); + log("debug", "Handling new request %s: %s\n----------", event.request, event.request.body); local request, response = event.request, event.response; response.on_destroy = on_destroy_request; @@ -224,7 +224,7 @@ local function bosh_reset_stream(session) session.notopen = true; end local stream_xmlns_attr = { xmlns = "urn:ietf:params:xml:ns:xmpp-streams" }; local function bosh_close_stream(session, reason) - (session.log or log)("info", "BOSH client disconnected: %s", tostring((reason and reason.condition or reason) or "session close")); + (session.log or log)("info", "BOSH client disconnected: %s", (reason and reason.condition or reason) or "session close"); local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", ["xmlns:stream"] = xmlns_streams }); @@ -249,7 +249,7 @@ local function bosh_close_stream(session, reason) close_reply = reason; end end - log("info", "Disconnecting client, <stream:error> is: %s", tostring(close_reply)); + log("info", "Disconnecting client, <stream:error> is: %s", close_reply); end local response_body = tostring(close_reply); @@ -275,7 +275,7 @@ function stream_callbacks.streamopened(context, attr) local to_host = nameprep(attr.to); local wait = tonumber(attr.wait); if not to_host then - log("debug", "BOSH client tried to connect to invalid host: %s", tostring(attr.to)); + log("debug", "BOSH client tried to connect to invalid host: %s", attr.to); report_bad_host(); local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", ["xmlns:stream"] = xmlns_streams, condition = "improper-addressing" }); @@ -283,7 +283,7 @@ function stream_callbacks.streamopened(context, attr) return; end if not rid or (not attr.wait or not wait or wait < 0 or wait % 1 ~= 0) then - log("debug", "BOSH client sent invalid rid or wait attributes: rid=%s, wait=%s", tostring(attr.rid), tostring(attr.wait)); + log("debug", "BOSH client sent invalid rid or wait attributes: rid=%s, wait=%s", attr.rid, attr.wait); local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", ["xmlns:stream"] = xmlns_streams, condition = "bad-request" }); response:send(tostring(close_reply)); @@ -329,7 +329,7 @@ function stream_callbacks.streamopened(context, attr) s.attr.xmlns = "jabber:client"; end s = filter("stanzas/out", s); - --log("debug", "Sending BOSH data: %s", tostring(s)); + --log("debug", "Sending BOSH data: %s", s); if not s then return true end t_insert(session.send_buffer, tostring(s)); @@ -432,7 +432,7 @@ function stream_callbacks.streamopened(context, attr) end end -local function handleerr(err) log("error", "Traceback[bosh]: %s", traceback(tostring(err), 2)); end +local function handleerr(err) log("error", "Traceback[bosh]: %s", traceback(err, 2)); end function runner_callbacks:error(err) -- luacheck: ignore 212/self return handleerr(err); diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index bfec1055..53af34f0 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -127,7 +127,7 @@ function stream_callbacks.error(session, error, data) session.log("debug", "Invalid opening stream header (%s)", (data:gsub("^([^\1]+)\1", "{%1}"))); session:close("invalid-namespace"); elseif error == "parse-error" then - (session.log or log)("debug", "Client XML parse error: %s", tostring(data)); + (session.log or log)("debug", "Client XML parse error: %s", data); session:close("not-well-formed"); elseif error == "stream-error" then local condition, text = "undefined-condition"; @@ -289,7 +289,7 @@ function listener.onconnect(conn) if data then local ok, err = stream:feed(data); if not ok then - log("debug", "Received invalid XML (%s) %d bytes: %q", tostring(err), #data, data:sub(1, 300)); + log("debug", "Received invalid XML (%s) %d bytes: %q", err, #data, data:sub(1, 300)); session:close("not-well-formed"); end end diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua index b1ffc81d..afcfc68c 100644 --- a/plugins/mod_component.lua +++ b/plugins/mod_component.lua @@ -167,11 +167,11 @@ local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; function stream_callbacks.error(session, error, data) if session.destroyed then return; end - module:log("warn", "Error processing component stream: %s", tostring(error)); + module:log("warn", "Error processing component stream: %s", error); if error == "no-stream" then session:close("invalid-namespace"); elseif error == "parse-error" then - session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(data)); + session.log("warn", "External component %s XML parse error: %s", session.host, data); session:close("not-well-formed"); elseif error == "stream-error" then local condition, text = "undefined-condition"; @@ -208,7 +208,7 @@ function stream_callbacks.streamclosed(session) session:close(); end -local function handleerr(err) log("error", "Traceback[component]: %s", traceback(tostring(err), 2)); end +local function handleerr(err) log("error", "Traceback[component]: %s", traceback(err, 2)); end function stream_callbacks.handlestanza(session, stanza) -- Namespaces are icky. if not stanza.attr.xmlns and stanza.name == "handshake" then @@ -268,10 +268,10 @@ local function session_close(session, reason) if reason.extra then stanza:add_child(reason.extra); end - module:log("info", "Disconnecting component, <stream:error> is: %s", tostring(stanza)); + module:log("info", "Disconnecting component, <stream:error> is: %s", stanza); session.send(stanza); elseif reason.name then -- a stanza - module:log("info", "Disconnecting component, <stream:error> is: %s", tostring(reason)); + module:log("info", "Disconnecting component, <stream:error> is: %s", reason); session.send(reason); end end @@ -312,7 +312,7 @@ function listener.onconnect(conn) function session.data(_, data) local ok, err = stream:feed(data); if ok then return; end - log("debug", "Received invalid XML (%s) %d bytes: %q", tostring(err), #data, data:sub(1, 300)); + log("debug", "Received invalid XML (%s) %d bytes: %q", err, #data, data:sub(1, 300)); session:close("not-well-formed"); end @@ -327,7 +327,7 @@ end function listener.ondisconnect(conn, err) local session = sessions[conn]; if session then - (session.log or log)("info", "component disconnected: %s (%s)", tostring(session.host), tostring(err)); + (session.log or log)("info", "component disconnected: %s (%s)", session.host, err); if session.host then module:context(session.host):fire_event("component-disconnected", { session = session, reason = err }); end diff --git a/plugins/mod_groups.lua b/plugins/mod_groups.lua index 646b7408..0c44f481 100644 --- a/plugins/mod_groups.lua +++ b/plugins/mod_groups.lua @@ -25,7 +25,7 @@ function inject_roster_contacts(event) local function import_jids_to_roster(group_name) for jid in pairs(groups[group_name]) do -- Add them to roster - --module:log("debug", "processing jid %s in group %s", tostring(jid), tostring(group_name)); + --module:log("debug", "processing jid %s in group %s", jid, group_name); if jid ~= bare_jid then if not roster[jid] then roster[jid] = {}; end roster[jid].subscription = "both"; @@ -99,7 +99,7 @@ function module.load() end members[false][#members[false]+1] = curr_group; -- Is a public group end - module:log("debug", "New group: %s", tostring(curr_group)); + module:log("debug", "New group: %s", curr_group); groups[curr_group] = groups[curr_group] or {}; else -- Add JID @@ -108,7 +108,7 @@ function module.load() local jid; jid = jid_prep(entryjid:match("%S+")); if jid then - module:log("debug", "New member of %s: %s", tostring(curr_group), tostring(jid)); + module:log("debug", "New member of %s: %s", curr_group, jid); groups[curr_group][jid] = name or false; members[jid] = members[jid] or {}; members[jid][#members[jid]+1] = curr_group; diff --git a/plugins/mod_limits.lua b/plugins/mod_limits.lua index 7ae8bb34..a1a3b2c0 100644 --- a/plugins/mod_limits.lua +++ b/plugins/mod_limits.lua @@ -32,7 +32,7 @@ local function parse_burst(burst, sess_type) end local n_burst = tonumber(burst); if not n_burst then - module:log("error", "Unable to parse burst for %s: %q, using default burst interval (%ds)", sess_type, tostring(burst), default_burst); + module:log("error", "Unable to parse burst for %s: %q, using default burst interval (%ds)", sess_type, burst, default_burst); end return n_burst or default_burst; end @@ -84,8 +84,13 @@ local function filter_hook(session) local session_type = session.type:match("^[^_]+"); local filter_set, opts = type_filters[session_type], limits[session_type]; if opts then - session.throttle = throttle.create(opts.bytes_per_second * opts.burst_seconds, opts.burst_seconds); - filters.add_filter(session, "bytes/in", filter_set.bytes_in, 1000); + if session.conn and session.conn.setlimit then + session.conn:setlimit(opts.bytes_per_second); + -- Currently no burst support + else + session.throttle = throttle.create(opts.bytes_per_second * opts.burst_seconds, opts.burst_seconds); + filters.add_filter(session, "bytes/in", filter_set.bytes_in, 1000); + end end end @@ -106,9 +111,14 @@ function module.add_host(module) local session_type = session.type:match("^[^_]+"); local jid = session.username .. "@" .. session.host; if unlimited_jids:contains(jid) then - local filter_set = type_filters[session_type]; - filters.remove_filter(session, "bytes/in", filter_set.bytes_in); - session.throttle = nil; + if session.conn and session.conn.setlimit then + session.conn:setlimit(0); + -- Currently no burst support + else + local filter_set = type_filters[session_type]; + filters.remove_filter(session, "bytes/in", filter_set.bytes_in); + session.throttle = nil; + end end end); end diff --git a/plugins/mod_mam/mod_mam.lua b/plugins/mod_mam/mod_mam.lua index 4e0cf531..cfa92ff5 100644 --- a/plugins/mod_mam/mod_mam.lua +++ b/plugins/mod_mam/mod_mam.lua @@ -118,10 +118,12 @@ module:hook("iq-set/self/"..xmlns_mam..":query", function(event) qstart, qend = vstart, vend; end - module:log("debug", "Archive query, id %s with %s from %s until %s", - tostring(qid), qwith or "anyone", - qstart and timestamp(qstart) or "the dawn of time", - qend and timestamp(qend) or "now"); + module:log("debug", "Archive query by %s id=%s with=%s when=%s...%s", + origin.username, + qid or stanza.attr.id, + qwith or "*", + qstart and timestamp(qstart) or "", + qend and timestamp(qend) or ""); -- RSM stuff local qset = rsm.get(query); @@ -129,6 +131,9 @@ module:hook("iq-set/self/"..xmlns_mam..":query", function(event) local reverse = qset and qset.before or false; local before, after = qset and qset.before, qset and qset.after; if type(before) ~= "string" then before = nil; end + if qset then + module:log("debug", "Archive query id=%s rsm=%q", qid or stanza.attr.id, qset); + end -- Load all the data! local data, err = archive:find(origin.username, { @@ -141,6 +146,7 @@ module:hook("iq-set/self/"..xmlns_mam..":query", function(event) }); if not data then + module:log("debug", "Archive query id=%s failed: %s", qid or stanza.attr.id, err); if err == "item-not-found" then origin.send(st.error_reply(stanza, "modify", "item-not-found")); else @@ -194,13 +200,13 @@ module:hook("iq-set/self/"..xmlns_mam..":query", function(event) first, last = last, first; end - -- That's all folks! - module:log("debug", "Archive query %s completed", tostring(qid)); - origin.send(st.reply(stanza) :tag("fin", { xmlns = xmlns_mam, queryid = qid, complete = complete }) :add_child(rsm.generate { first = first, last = last, count = total })); + + -- That's all folks! + module:log("debug", "Archive query id=%s completed, %d items returned", qid or stanza.attr.id, complete and count or count - 1); return true; end); @@ -218,13 +224,13 @@ local function shall_store(user, who) end local prefs = get_prefs(user); local rule = prefs[who]; - module:log("debug", "%s's rule for %s is %s", user, who, tostring(rule)); + module:log("debug", "%s's rule for %s is %s", user, who, rule); if rule ~= nil then return rule; end -- Below could be done by a metatable local default = prefs[false]; - module:log("debug", "%s's default rule is %s", user, tostring(default)); + module:log("debug", "%s's default rule is %s", user, default); if default == "roster" then return has_in_roster(user, who); end diff --git a/plugins/mod_muc_mam.lua b/plugins/mod_muc_mam.lua index eb93a386..7fc9fabf 100644 --- a/plugins/mod_muc_mam.lua +++ b/plugins/mod_muc_mam.lua @@ -251,7 +251,7 @@ module:hook("iq-set/bare/"..xmlns_mam..":query", function(event) end -- That's all folks! - module:log("debug", "Archive query %s completed", tostring(qid)); + module:log("debug", "Archive query %s completed", qid); origin.send(st.reply(stanza) :tag("fin", { xmlns = xmlns_mam, queryid = qid, complete = complete }) @@ -291,7 +291,7 @@ module:hook("muc-get-history", function (event) local data, err = archive:find(jid_split(room_jid), query); if not data then - module:log("error", "Could not fetch history: %s", tostring(err)); + module:log("error", "Could not fetch history: %s", err); return end @@ -317,7 +317,7 @@ module:hook("muc-get-history", function (event) maxchars = maxchars - chars; end history[i], i = item, i+1; - -- module:log("debug", tostring(item)); + -- module:log("debug", item); end function event.next_stanza() i = i - 1; @@ -428,7 +428,9 @@ end module:add_feature(xmlns_mam); module:hook("muc-disco#info", function(event) - event.reply:tag("feature", {var=xmlns_mam}):up(); + if archiving_enabled(event.room) then + event.reply:tag("feature", {var=xmlns_mam}):up(); + end end); -- Cleanup diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 54f0451d..c0a85a9d 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -183,12 +183,12 @@ local function on_node_creation(event) end function get_pep_service(username) - module:log("debug", "get_pep_service(%q)", username); local user_bare = jid_join(username, host); local service = services[username]; if service then return service; end + module:log("debug", "Creating pubsub service for user %q", username); service = pubsub.new({ pep_username = username; node_defaults = { diff --git a/plugins/mod_pep_simple.lua b/plugins/mod_pep_simple.lua index f91e5448..11268ab7 100644 --- a/plugins/mod_pep_simple.lua +++ b/plugins/mod_pep_simple.lua @@ -230,13 +230,13 @@ module:hook("iq/bare/http://jabber.org/protocol/pubsub:pubsub", function(event) return true; else --invalid request session.send(st.error_reply(stanza, 'modify', 'bad-request')); - module:log("debug", "Invalid request: %s", tostring(payload)); + module:log("debug", "Invalid request: %s", payload); return true; end else --no presence subscription session.send(st.error_reply(stanza, 'auth', 'not-authorized') :tag('presence-subscription-required', {xmlns='http://jabber.org/protocol/pubsub#errors'})); - module:log("debug", "Unauthorized request: %s", tostring(payload)); + module:log("debug", "Unauthorized request: %s", payload); return true; end end diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 00833772..29c821e2 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -117,7 +117,7 @@ function module.add_host(module) if jid_compare(jid, acl) then allow = true; break; end end if allow then break; end - module:log("warn", "Denying use of proxy for %s", tostring(stanza.attr.from)); + module:log("warn", "Denying use of proxy for %s", stanza.attr.from); origin.send(st.error_reply(stanza, "auth", "forbidden")); return true; end diff --git a/plugins/mod_pubsub/mod_pubsub.lua b/plugins/mod_pubsub/mod_pubsub.lua index 05f80365..faf08cb2 100644 --- a/plugins/mod_pubsub/mod_pubsub.lua +++ b/plugins/mod_pubsub/mod_pubsub.lua @@ -82,7 +82,6 @@ function simple_broadcast(kind, node, jids, item, actor, node_obj) end local summary; - -- Compose a sensible textual representation of at least Atom payloads if item and item.tags[1] then local payload = item.tags[1]; summary = module:fire_event("pubsub-summary/"..payload.attr.xmlns, { @@ -116,6 +115,7 @@ function is_item_stanza(item) return st.is_stanza(item) and item.attr.xmlns == xmlns_pubsub and item.name == "item"; end +-- Compose a textual representation of Atom payloads module:hook("pubsub-summary/http://www.w3.org/2005/Atom", function (event) local payload = event.payload; local title = payload:get_child_text("title"); diff --git a/plugins/mod_pubsub/pubsub.lib.lua b/plugins/mod_pubsub/pubsub.lib.lua index 50ef7ddf..d59e3d85 100644 --- a/plugins/mod_pubsub/pubsub.lib.lua +++ b/plugins/mod_pubsub/pubsub.lib.lua @@ -185,6 +185,14 @@ local node_metadata_form = dataform { type = "text-single"; name = "pubsub#type"; }; + { + type = "text-single"; + name = "pubsub#access_model"; + }; + { + type = "text-single"; + name = "pubsub#publish_model"; + }; }; local service_method_feature_map = { @@ -258,6 +266,8 @@ function _M.handle_disco_info_node(event, service) ["pubsub#title"] = node_obj.config.title; ["pubsub#description"] = node_obj.config.description; ["pubsub#type"] = node_obj.config.payload_type; + ["pubsub#access_model"] = node_obj.config.access_model; + ["pubsub#publish_model"] = node_obj.config.publish_model; }, "result")); end end @@ -318,14 +328,9 @@ function handlers.get_items(origin, stanza, items, service) for _, id in ipairs(results) do data:add_child(results[id]); end - local reply; - if data then - reply = st.reply(stanza) - :tag("pubsub", { xmlns = xmlns_pubsub }) - :add_child(data); - else - reply = pubsub_error_reply(stanza, "item-not-found"); - end + local reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :add_child(data); origin.send(reply); return true; end diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index f0fdc5fb..ea19f7ad 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -27,8 +27,8 @@ local s2s_destroy_session = require "core.s2smanager".destroy_session; local uuid_gen = require "util.uuid".generate; local fire_global_event = prosody.events.fire_event; local runner = require "util.async".runner; - -local s2sout = module:require("s2sout"); +local connect = require "net.connect".connect; +local service = require "net.resolvers.service"; local connect_timeout = module:get_option_number("s2s_timeout", 90); local stream_close_timeout = module:get_option_number("s2s_close_timeout", 5); @@ -45,6 +45,8 @@ local sessions = module:shared("sessions"); local runner_callbacks = {}; +local listener = {}; + local log = module._log; module:hook("stats-update", function () @@ -77,12 +79,19 @@ local function bounce_sendq(session, reason) (session.log or log)("error", "Attempting to close the dummy origin of s2s error replies, please report this! Traceback: %s", traceback()); end; }; + -- FIXME Allow for more specific error conditions + -- TODO use util.error ? + local error_type = "cancel"; + local condition = "remote-server-not-found"; + if session.had_stream then -- set when a stream is opened by the remote + error_type, condition = "wait", "remote-server-timeout"; + end for i, data in ipairs(sendq) do local reply = data[2]; if reply and not(reply.attr.xmlns) and bouncy_stanzas[reply.name] then reply.attr.type = "error"; - reply:tag("error", {type = "cancel", by = session.from_host}) - :tag("remote-server-not-found", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up(); + reply:tag("error", {type = error_type, by = session.from_host}) + :tag(condition, {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up(); if reason then reply:tag("text", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}) :text("Server-to-server connection failed: "..reason):up(); @@ -127,7 +136,7 @@ function route_to_existing_session(event) elseif host.type == "local" or host.type == "component" then log("error", "Trying to send a stanza to ourselves??") log("error", "Traceback: %s", traceback()); - log("error", "Stanza: %s", tostring(stanza)); + log("error", "Stanza: %s", stanza); return false; else -- FIXME @@ -147,17 +156,13 @@ function route_to_new_session(event) local from_host, to_host, stanza = event.from_host, event.to_host, event.stanza; log("debug", "opening a new outgoing connection for this stanza"); local host_session = s2s_new_outgoing(from_host, to_host); + host_session.version = 1; -- Store in buffer host_session.bounce_sendq = bounce_sendq; host_session.sendq = { {tostring(stanza), stanza.attr.type ~= "error" and stanza.attr.type ~= "result" and st.reply(stanza)} }; - log("debug", "stanza [%s] queued until connection complete", tostring(stanza.name)); - s2sout.initiate_connection(host_session); - if (not host_session.connecting) and (not host_session.conn) then - log("warn", "Connection to %s failed already, destroying session...", to_host); - s2s_destroy_session(host_session, "Connection failed"); - return false; - end + log("debug", "stanza [%s] queued until connection complete", stanza.name); + connect(service.new(to_host, "xmpp-server", "tcp", { default_port = 5269 }), listener, nil, { session = host_session }); return true; end @@ -301,6 +306,7 @@ end function stream_callbacks._streamopened(session, attr) session.version = tonumber(attr.version) or 0; + session.had_stream = true; -- Had a stream opened at least once -- TODO: Rename session.secure to session.encrypted if session.secure == false then @@ -471,8 +477,6 @@ function stream_callbacks.error(session, error, data) end end -local listener = {}; - --- Session methods local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; local function session_close(session, reason, remote_reason) @@ -595,7 +599,7 @@ local function initialize_session(session) if data then local ok, err = stream:feed(data); if ok then return; end - log("debug", "Received invalid XML (%s) %d bytes: %q", tostring(err), #data, data:sub(1, 300)); + log("debug", "Received invalid XML (%s) %d bytes: %q", err, #data, data:sub(1, 300)); session:close("not-well-formed"); end end @@ -671,11 +675,16 @@ function listener.ondisconnect(conn, err) local session = sessions[conn]; if session then sessions[conn] = nil; + (session.log or log)("debug", "s2s disconnected: %s->%s (%s)", session.from_host, session.to_host, err or "connection closed"); + s2s_destroy_session(session, err); + end +end + +function listener.onfail(data, err) + local session = data and data.session; + if session then 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 - return; -- Session lives for now - end end (session.log or log)("debug", "s2s disconnected: %s->%s (%s)", session.from_host, session.to_host, err or "connection closed"); s2s_destroy_session(session, err); @@ -699,6 +708,15 @@ function listener.ondetach(conn) sessions[conn] = nil; end +function listener.onattach(conn, data) + local session = data and data.session; + if session then + session.conn = conn; + sessions[conn] = session; + initialize_session(session); + end +end + function check_auth_policy(event) local host, session = event.host, event.session; local must_secure = secure_auth; @@ -722,8 +740,6 @@ end module:hook("s2s-check-certificate", check_auth_policy, -1); -s2sout.set_listener(listener); - module:hook("server-stopping", function(event) local reason = event.reason; for _, session in pairs(sessions) do diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua deleted file mode 100644 index 34e322d2..00000000 --- a/plugins/mod_s2s/s2sout.lib.lua +++ /dev/null @@ -1,349 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - ---- Module containing all the logic for connecting to a remote server - --- luacheck: ignore 432/err - -local portmanager = require "core.portmanager"; -local wrapclient = require "net.server".wrapclient; -local initialize_filters = require "util.filters".initialize; -local idna_to_ascii = require "util.encodings".idna.to_ascii; -local new_ip = require "util.ip".new_ip; -local rfc6724_dest = require "util.rfc6724".destination; -local socket = require "socket"; -local adns = require "net.adns"; -local t_insert, t_sort, ipairs = table.insert, table.sort, ipairs; -local local_addresses = require "util.net".local_addresses; - -local s2s_destroy_session = require "core.s2smanager".destroy_session; - -local default_mode = module:get_option("network_default_read_size", 4096); - -local log = module._log; - -local sources = {}; -local has_ipv4, has_ipv6; - -local dns_timeout = module:get_option_number("dns_timeout", 15); -local resolvers = module:get_option_set("s2s_dns_resolvers") - -local s2sout = {}; - -local s2s_listener; - - -function s2sout.set_listener(listener) - s2s_listener = listener; -end - -local function compare_srv_priorities(a,b) - return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight); -end - -function s2sout.initiate_connection(host_session) - local log = host_session.log or log; - - initialize_filters(host_session); - host_session.version = 1; - - host_session.resolver = adns.resolver(); - host_session.resolver._resolver:settimeout(dns_timeout); - if resolvers then - for resolver in resolvers do - host_session.resolver._resolver:addnameserver(resolver); - end - end - - -- Kick the connection attempting machine into life - if not s2sout.attempt_connection(host_session) then - -- Intentionally not returning here, the - -- session is needed, connected or not - s2s_destroy_session(host_session); - end - - if not host_session.sends2s then - -- A sends2s which buffers data (until the stream is opened) - -- note that data in this buffer will be sent before the stream is authed - -- and will not be ack'd in any way, successful or otherwise - local buffer; - function host_session.sends2s(data) - if not buffer then - buffer = {}; - host_session.send_buffer = buffer; - end - log("debug", "Buffering data on unconnected s2sout to %s", host_session.to_host); - buffer[#buffer+1] = data; - log("debug", "Buffered item %d: %s", #buffer, data); - end - end -end - -function s2sout.attempt_connection(host_session, err) - local to_host = host_session.to_host; - local connect_host, connect_port = to_host and idna_to_ascii(to_host), 5269; - local log = host_session.log or log; - - if not connect_host then - return false; - end - - if not err then -- This is our first attempt - log("debug", "First attempt to connect to %s, starting with SRV lookup...", to_host); - host_session.connecting = true; - host_session.resolver:lookup(function (answer) - local srv_hosts = { answer = answer }; - host_session.srv_hosts = srv_hosts; - host_session.srv_choice = 0; - host_session.connecting = nil; - if answer and #answer > 0 then - log("debug", "%s has SRV records, handling...", to_host); - 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", "%s does not provide a XMPP service", to_host); - s2s_destroy_session(host_session, err); -- Nothing to see here - return; - end - t_sort(srv_hosts, compare_srv_priorities); - - local srv_choice = srv_hosts[1]; - host_session.srv_choice = 1; - if srv_choice then - connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port; - log("debug", "Best record found, will connect to %s:%d", connect_host, connect_port); - end - else - 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); - if not ok then - if not s2sout.attempt_connection(host_session, err) then - -- No more attempts will be made - s2s_destroy_session(host_session, err); - end - end - end, "_xmpp-server._tcp."..connect_host..".", "SRV"); - - return true; -- Attempt in progress - elseif host_session.ip_hosts then - return s2sout.try_connect(host_session, connect_host, connect_port, err); - elseif host_session.srv_hosts and #host_session.srv_hosts > host_session.srv_choice then -- Not our first attempt, and we also have SRV - host_session.srv_choice = host_session.srv_choice + 1; - local srv_choice = host_session.srv_hosts[host_session.srv_choice]; - connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port; - host_session.log("info", "Connection failed (%s). Attempt #%d: This time to %s:%d", err, host_session.srv_choice, connect_host, connect_port); - else - host_session.log("info", "Failed in all attempts to connect to %s", host_session.to_host); - -- We're out of options - return false; - end - - if not (connect_host and connect_port) then - -- Likely we couldn't resolve DNS - log("warn", "Hmm, we're without a host (%s) and port (%s) to connect to for %s, giving up :(", connect_host, connect_port, to_host); - return false; - end - - return s2sout.try_connect(host_session, connect_host, connect_port); -end - -function s2sout.try_next_ip(host_session) - host_session.connecting = nil; - host_session.ip_choice = host_session.ip_choice + 1; - local ip = host_session.ip_hosts[host_session.ip_choice]; - local ok, err= s2sout.make_connect(host_session, ip.ip, ip.port); - if not ok then - if not s2sout.attempt_connection(host_session, err or "closed") then - err = err and (": "..err) or ""; - s2s_destroy_session(host_session, "Connection failed"..err); - end - end -end - -function s2sout.try_connect(host_session, connect_host, connect_port, err) - host_session.connecting = true; - local log = host_session.log or log; - - if not err then - local IPs = {}; - host_session.ip_hosts = IPs; - -- luacheck: ignore 231/handle4 231/handle6 - local handle4, handle6; - local have_other_result = not(has_ipv4) or not(has_ipv6) or false; - - if has_ipv4 then - handle4 = host_session.resolver:lookup(function (reply, err) - handle4 = nil; - - 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 - elseif err then - log("debug", "Error in DNS lookup: %s", err); - end - - if have_other_result then - if #IPs > 0 then - rfc6724_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 - else - have_other_result = true; - end - end, connect_host, "A", "IN"); - else - have_other_result = true; - end - - if has_ipv6 then - handle6 = host_session.resolver: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"); - end - elseif err then - log("debug", "Error in DNS lookup: %s", err); - end - - if have_other_result then - if #IPs > 0 then - rfc6724_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 - else - have_other_result = true; - end - end, connect_host, "AAAA", "IN"); - else - 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); - else - log("debug", "Out of IP addresses, trying next SRV record (if any)"); - host_session.ip_hosts = nil; - if not s2sout.attempt_connection(host_session, "out of IP addresses") 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, "Connecting failed"..err); -- End of the line, we can't - return false; - end - end - - return true; -end - -function s2sout.make_connect(host_session, connect_host, connect_port) - local log = host_session.log or log; - log("debug", "Beginning new connection attempt to %s ([%s]:%d)", host_session.to_host, connect_host.addr, connect_port); - - -- Reset secure flag in case this is another - -- connection attempt after a failed STARTTLS - host_session.secure = nil; - host_session.encrypted = nil; - - local conn, handler; - local proto = connect_host.proto; - if proto == "IPv4" then - conn, handler = socket.tcp(); - elseif proto == "IPv6" and socket.tcp6 then - conn, handler = socket.tcp6(); - else - handler = "Unsupported protocol: "..tostring(proto); - end - - if not conn then - log("warn", "Failed to create outgoing connection, system error: %s", handler); - return false, handler; - end - - conn:settimeout(0); - local success, err = conn:connect(connect_host.addr, connect_port); - if not success and err ~= "timeout" then - log("warn", "s2s connect() to %s (%s:%d) failed: %s", host_session.to_host, connect_host.addr, connect_port, err); - return false, err; - end - - conn = wrapclient(conn, connect_host.addr, connect_port, s2s_listener, default_mode); - host_session.conn = conn; - - -- Register this outgoing connection so that xmppserver_listener knows about it - -- otherwise it will assume it is a new incoming connection - s2s_listener.register_outgoing(conn, host_session); - - log("debug", "Connection attempt in progress..."); - return true; -end - -module:hook_global("service-added", function (event) - if event.name ~= "s2s" then return end - - local s2s_sources = portmanager.get_active_services():get("s2s"); - if not s2s_sources then - module:log_status("warn", "s2s not listening on any ports, outgoing connections may fail"); - return; - end - for source, _ in pairs(s2s_sources) do - if source == "*" or source == "0.0.0.0" then - for _, addr in ipairs(local_addresses("ipv4", true)) do - sources[#sources + 1] = new_ip(addr, "IPv4"); - end - elseif source == "::" then - for _, addr in ipairs(local_addresses("ipv6", true)) do - sources[#sources + 1] = new_ip(addr, "IPv6"); - end - else - sources[#sources + 1] = new_ip(source, (source:find(":") and "IPv6") or "IPv4"); - end - end - for i = 1,#sources do - if sources[i].proto == "IPv6" then - has_ipv6 = true; - elseif sources[i].proto == "IPv4" then - has_ipv4 = true; - end - end - if not (has_ipv4 or has_ipv6) then - module:log("warn", "No local IPv4 or IPv6 addresses detected, outgoing connections may fail"); - end -end); - -return s2sout; diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 3145cf9b..89313de1 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -14,7 +14,6 @@ local sm_make_authenticated = require "core.sessionmanager".make_authenticated; local base64 = require "util.encodings".base64; local usermanager_get_sasl_handler = require "core.usermanager".get_sasl_handler; -local tostring = tostring; local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", false)); local allow_unencrypted_plain_auth = module:get_option_boolean("allow_unencrypted_plain_auth", false) @@ -77,7 +76,7 @@ local function sasl_process_cdata(session, stanza) local status, ret, err_msg = session.sasl_handler:process(text); status, ret, err_msg = handle_status(session, status, ret, err_msg); local s = build_reply(status, ret, err_msg); - log("debug", "sasl reply: %s", tostring(s)); + log("debug", "sasl reply: %s", s); session.send(s); return true; end diff --git a/plugins/mod_stanza_debug.lua b/plugins/mod_stanza_debug.lua index 6dedb6f7..af98670c 100644 --- a/plugins/mod_stanza_debug.lua +++ b/plugins/mod_stanza_debug.lua @@ -1,18 +1,17 @@ module:set_global(); -local tostring = tostring; local filters = require "util.filters"; local function log_send(t, session) if t and t ~= "" and t ~= " " then - session.log("debug", "SEND: %s", tostring(t)); + session.log("debug", "SEND: %s", t); end return t; end local function log_recv(t, session) if t and t ~= "" and t ~= " " then - session.log("debug", "RECV: %s", tostring(t)); + session.log("debug", "RECV: %s", t); end return t; end diff --git a/plugins/mod_vcard_legacy.lua b/plugins/mod_vcard_legacy.lua index ab2c4490..89ef1a4f 100644 --- a/plugins/mod_vcard_legacy.lua +++ b/plugins/mod_vcard_legacy.lua @@ -105,6 +105,15 @@ module:hook("iq-get/bare/vcard-temp:vCard", function (event) vcard_temp:tag("WORK"):up(); end vcard_temp:up(); + elseif tag.name == "impp" then + local uri = tag:get_child_text("uri"); + if uri and uri:sub(1, 5) == "xmpp:" then + vcard_temp:text_tag("JABBERID", uri:sub(6)) + end + elseif tag.name == "org" then + vcard_temp:tag("ORG") + :text_tag("ORGNAME", tag:get_child_text("text")) + :up(); end end end @@ -216,6 +225,10 @@ function vcard_to_pep(vcard_temp) vcard4:text_tag("text", "work"); end vcard4:up():up():up(); + elseif tag.name == "JABBERID" then + vcard4:tag("impp") + :text_tag("uri", "xmpp:" .. tag:get_text()) + :up(); elseif tag.name == "PHOTO" then local avatar_type = tag:get_child_text("TYPE"); local avatar_payload = tag:get_child_text("BINVAL"); diff --git a/plugins/mod_websocket.lua b/plugins/mod_websocket.lua index 008f6823..c94ea84a 100644 --- a/plugins/mod_websocket.lua +++ b/plugins/mod_websocket.lua @@ -80,7 +80,7 @@ local function session_close(session, reason) stream_error = reason; end end - log("debug", "Disconnecting client, <stream:error> is: %s", tostring(stream_error)); + log("debug", "Disconnecting client, <stream:error> is: %s", stream_error); session.send(stream_error); end @@ -272,6 +272,7 @@ function handle_request(event) end); add_filter(session, "stanzas/out", function(stanza) + stanza = st.clone(stanza); local attr = stanza.attr; attr.xmlns = attr.xmlns or xmlns_client; if stanza.name:find("^stream:") then diff --git a/plugins/muc/language.lib.lua b/plugins/muc/language.lib.lua index ee80806b..2ee2ba0f 100644 --- a/plugins/muc/language.lib.lua +++ b/plugins/muc/language.lib.lua @@ -32,6 +32,7 @@ local function add_form_option(event) label = "Language tag for room (e.g. 'en', 'de', 'fr' etc.)"; type = "text-single"; desc = "Indicate the primary language spoken in this room"; + datatype = "xs:language"; value = get_language(event.room) or ""; }); end |