Software /
code /
prosody
Annotate
plugins/muc/occupant.lib.lua @ 12181:783056b4e448 0.11 0.11.12
util.xml: Do not allow doctypes, comments or processing instructions
Yes. This is as bad as it sounds. CVE pending.
In Prosody itself, this only affects mod_websocket, which uses util.xml
to parse the <open/> frame, thus allowing unauthenticated remote DoS
using Billion Laughs. However, third-party modules using util.xml may
also be affected by this.
This commit installs handlers which disallow the use of doctype
declarations and processing instructions without any escape hatch. It,
by default, also introduces such a handler for comments, however, there
is a way to enable comments nontheless.
This is because util.xml is used to parse human-facing data, where
comments are generally a desirable feature, and also because comments
are generally harmless.
author | Jonas Schäfer <jonas@wielicki.name> |
---|---|
date | Mon, 10 Jan 2022 18:23:54 +0100 |
parent | 7086:6cc7c9da29ed |
child | 12977:74b9e05af71e |
rev | line source |
---|---|
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
1 local pairs = pairs; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
2 local setmetatable = setmetatable; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
3 local st = require "util.stanza"; |
6271
006b0e0f0de2
plugins/muc: Move 'x' filtering from occupant to util
daurnimator <quae@daurnimator.com>
parents:
6251
diff
changeset
|
4 local util = module:require "muc/util"; |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
5 |
6271
006b0e0f0de2
plugins/muc: Move 'x' filtering from occupant to util
daurnimator <quae@daurnimator.com>
parents:
6251
diff
changeset
|
6 local function get_filtered_presence(stanza) |
006b0e0f0de2
plugins/muc: Move 'x' filtering from occupant to util
daurnimator <quae@daurnimator.com>
parents:
6251
diff
changeset
|
7 return util.filter_muc_x(st.clone(stanza)); |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
8 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
9 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
10 local occupant_mt = {}; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
11 occupant_mt.__index = occupant_mt; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
12 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
13 local function new_occupant(bare_real_jid, nick) |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
14 return setmetatable({ |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
15 bare_jid = bare_real_jid; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
16 nick = nick; -- in-room jid |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
17 sessions = {}; -- hash from real_jid to presence stanzas. stanzas should not be modified |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
18 role = nil; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
19 jid = nil; -- Primary session |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
20 }, occupant_mt); |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
21 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
22 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
23 -- Deep copy an occupant |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
24 local function copy_occupant(occupant) |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
25 local sessions = {}; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
26 for full_jid, presence_stanza in pairs(occupant.sessions) do |
6210
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
27 -- Don't keep unavailable presences, as they'll accumulate; unless they're the primary session |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
28 if presence_stanza.attr.type ~= "unavailable" or full_jid == occupant.jid then |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
29 sessions[full_jid] = presence_stanza; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
30 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
31 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
32 return setmetatable({ |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
33 bare_jid = occupant.bare_jid; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
34 nick = occupant.nick; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
35 sessions = sessions; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
36 role = occupant.role; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
37 jid = occupant.jid; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
38 }, occupant_mt); |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
39 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
40 |
6210
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
41 -- finds another session to be the primary (there might not be one) |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
42 function occupant_mt:choose_new_primary() |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
43 for jid, pr in self:each_session() do |
6251
41a5e5205fd9
plugins/muc/occupant: Check for type == nil rather than type ~= unavailable
daurnimator <quae@daurnimator.com>
parents:
6210
diff
changeset
|
44 if pr.attr.type == nil then |
6210
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
45 return jid; |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
46 end |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
47 end |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
48 return nil; |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
49 end |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
50 |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
51 function occupant_mt:set_session(real_jid, presence_stanza, replace_primary) |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
52 local pr = get_filtered_presence(presence_stanza); |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
53 pr.attr.from = self.nick; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
54 pr.attr.to = real_jid; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
55 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
56 self.sessions[real_jid] = pr; |
6210
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
57 if replace_primary then |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
58 self.jid = real_jid; |
6210
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
59 elseif self.jid == nil or (pr.attr.type == "unavailable" and self.jid == real_jid) then |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
60 -- Only leave an unavailable presence as primary when there are no other options |
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
61 self.jid = self:choose_new_primary() or real_jid; |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
62 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
63 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
64 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
65 function occupant_mt:remove_session(real_jid) |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
66 -- Delete original session |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
67 self.sessions[real_jid] = nil; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
68 if self.jid == real_jid then |
6210
e9d62fff82a8
plugins/muc/occupant.lib: Don't allow an unavailable session to be the primary jid
daurnimator <quae@daurnimator.com>
parents:
6179
diff
changeset
|
69 self.jid = self:choose_new_primary(); |
6179
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
70 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
71 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
72 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
73 function occupant_mt:each_session() |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
74 return pairs(self.sessions) |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
75 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
76 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
77 function occupant_mt:get_presence(real_jid) |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
78 return self.sessions[real_jid or self.jid] |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
79 end |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
80 |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
81 return { |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
82 new = new_occupant; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
83 copy = copy_occupant; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
84 mt = occupant_mt; |
e488a90195bc
plugins/muc: Massive refactor
daurnimator <quae@daurnimator.com>
parents:
diff
changeset
|
85 } |