aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ejabberd.yml.example1
-rw-r--r--src/ejabberd_sup.erl192
-rw-r--r--src/gen_mod.erl13
-rw-r--r--src/mod_configure.erl7
-rw-r--r--src/mod_muc_room.erl2
-rw-r--r--src/mod_pubsub.erl51
-rw-r--r--src/mod_push_keepalive.erl12
-rw-r--r--src/mod_stream_mgmt.erl6
8 files changed, 122 insertions, 162 deletions
diff --git a/ejabberd.yml.example b/ejabberd.yml.example
index 49506ed9c..28b238057 100644
--- a/ejabberd.yml.example
+++ b/ejabberd.yml.example
@@ -832,6 +832,7 @@ modules:
## and check your accessibility at https://check.messaging.one/
mod_s2s_dialback: {}
mod_http_api: {}
+ mod_fail2ban: {}
##
## Enable modules with custom options in a specific virtual host
diff --git a/src/ejabberd_sup.erl b/src/ejabberd_sup.erl
index e829ea61d..f692575c1 100644
--- a/src/ejabberd_sup.erl
+++ b/src/ejabberd_sup.erl
@@ -30,150 +30,58 @@
-export([start_link/0, init/1]).
+-define(SHUTDOWN_TIMEOUT, timer:seconds(30)).
+
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
- Hooks =
- {ejabberd_hooks,
- {ejabberd_hooks, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_hooks]},
- Cluster = {ejabberd_cluster,
- {ejabberd_cluster, start_link, []},
- permanent,
- 5000,
- worker,
- [ejabberd_cluster]},
- S2S =
- {ejabberd_s2s,
- {ejabberd_s2s, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_s2s]},
- Captcha =
- {ejabberd_captcha,
- {ejabberd_captcha, start_link, []},
- permanent,
- brutal_kill,
- worker,
- [ejabberd_captcha]},
- Listener =
- {ejabberd_listener,
- {ejabberd_listener, start_link, []},
- permanent,
- infinity,
- supervisor,
- [ejabberd_listener]},
- S2SInSupervisor =
- {ejabberd_s2s_in_sup,
- {ejabberd_tmp_sup, start_link,
- [ejabberd_s2s_in_sup, ejabberd_s2s_in]},
- permanent,
- infinity,
- supervisor,
- [ejabberd_tmp_sup]},
- S2SOutSupervisor =
- {ejabberd_s2s_out_sup,
- {ejabberd_tmp_sup, start_link,
- [ejabberd_s2s_out_sup, ejabberd_s2s_out]},
- permanent,
- infinity,
- supervisor,
- [ejabberd_tmp_sup]},
- ServiceSupervisor =
- {ejabberd_service_sup,
- {ejabberd_tmp_sup, start_link,
- [ejabberd_service_sup, ejabberd_service]},
- permanent,
- infinity,
- supervisor,
- [ejabberd_tmp_sup]},
- BackendSupervisor = {ejabberd_backend_sup,
- {ejabberd_backend_sup, start_link, []},
- permanent, infinity, supervisor,
- [ejabberd_backend_sup]},
- ACL = {acl, {acl, start_link, []},
- permanent, 5000, worker, [acl]},
- Shaper = {shaper, {shaper, start_link, []},
- permanent, 5000, worker, [shaper]},
- SQLSupervisor = {ejabberd_rdbms,
- {ejabberd_rdbms, start_link, []},
- permanent, infinity, supervisor, [ejabberd_rdbms]},
- RiakSupervisor = {ejabberd_riak_sup,
- {ejabberd_riak_sup, start_link, []},
- permanent, infinity, supervisor, [ejabberd_riak_sup]},
- RedisSupervisor = {ejabberd_redis_sup,
- {ejabberd_redis_sup, start_link, []},
- permanent, infinity, supervisor, [ejabberd_redis_sup]},
- Router = {ejabberd_router, {ejabberd_router, start_link, []},
- permanent, 5000, worker, [ejabberd_router]},
- RouterMulticast = {ejabberd_router_multicast,
- {ejabberd_router_multicast, start_link, []},
- permanent, 5000, worker, [ejabberd_router_multicast]},
- Local = {ejabberd_local, {ejabberd_local, start_link, []},
- permanent, 5000, worker, [ejabberd_local]},
- SM = {ejabberd_sm, {ejabberd_sm, start_link, []},
- permanent, 5000, worker, [ejabberd_sm]},
- GenModSupervisor = {ejabberd_gen_mod_sup, {gen_mod, start_link, []},
- permanent, infinity, supervisor, [gen_mod]},
- ExtMod = {ext_mod, {ext_mod, start_link, []},
- permanent, 5000, worker, [ext_mod]},
- Auth = {ejabberd_auth, {ejabberd_auth, start_link, []},
- permanent, 5000, worker, [ejabberd_auth]},
- OAuth = {ejabberd_oauth, {ejabberd_oauth, start_link, []},
- permanent, 5000, worker, [ejabberd_oauth]},
- Translation = {translate, {translate, start_link, []},
- permanent, 5000, worker, [translate]},
- AccessPerms = {ejabberd_access_permissions,
- {ejabberd_access_permissions, start_link, []},
- permanent, 5000, worker, [ejabberd_access_permissions]},
- Ctl = {ejabberd_ctl, {ejabberd_ctl, start_link, []},
- permanent, 5000, worker, [ejabberd_ctl]},
- Commands = {ejabberd_commands, {ejabberd_commands, start_link, []},
- permanent, 5000, worker, [ejabberd_commands]},
- Admin = {ejabberd_admin, {ejabberd_admin, start_link, []},
- permanent, 5000, worker, [ejabberd_admin]},
- CyrSASL = {cyrsasl, {cyrsasl, start_link, []},
- permanent, 5000, worker, [cyrsasl]},
- PKIX = {ejabberd_pkix, {ejabberd_pkix, start_link, []},
- permanent, 5000, worker, [ejabberd_pkix]},
- ACME = {ejabberd_acme, {ejabberd_acme, start_link, []},
- permanent, 5000, worker, [ejabberd_acme]},
- IQ = {ejabberd_iq, {ejabberd_iq, start_link, []},
- permanent, 5000, worker, [ejabberd_iq]},
{ok, {{one_for_one, 10, 1},
- [Hooks,
- Cluster,
- CyrSASL,
- Translation,
- AccessPerms,
- Ctl,
- Commands,
- Admin,
- PKIX,
- ACME,
- Listener,
- S2S,
- S2SInSupervisor,
- S2SOutSupervisor,
- ServiceSupervisor,
- ACL,
- Shaper,
- BackendSupervisor,
- SQLSupervisor,
- RiakSupervisor,
- RedisSupervisor,
- IQ,
- Router,
- RouterMulticast,
- Local,
- SM,
- Captcha,
- ExtMod,
- GenModSupervisor,
- Auth,
- OAuth]}}.
+ [worker(ejabberd_hooks),
+ worker(ejabberd_cluster),
+ worker(cyrsasl),
+ worker(translate),
+ worker(ejabberd_access_permissions),
+ worker(ejabberd_ctl),
+ worker(ejabberd_commands),
+ worker(ejabberd_admin),
+ worker(ejabberd_pkix),
+ worker(ejabberd_acme),
+ supervisor(ejabberd_listener),
+ worker(ejabberd_s2s),
+ simple_supervisor(ejabberd_s2s_in),
+ simple_supervisor(ejabberd_s2s_out),
+ simple_supervisor(ejabberd_service),
+ worker(acl),
+ worker(shaper),
+ supervisor(ejabberd_backend_sup),
+ supervisor(ejabberd_rdbms),
+ supervisor(ejabberd_riak_sup),
+ supervisor(ejabberd_redis_sup),
+ worker(ejabberd_iq),
+ worker(ejabberd_router),
+ worker(ejabberd_router_multicast),
+ worker(ejabberd_local),
+ worker(ejabberd_sm),
+ worker(ejabberd_captcha),
+ worker(ext_mod),
+ supervisor(ejabberd_gen_mod_sup, gen_mod),
+ worker(ejabberd_auth),
+ worker(ejabberd_oauth)]}}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+worker(Mod) ->
+ {Mod, {Mod, start_link, []}, permanent, ?SHUTDOWN_TIMEOUT, worker, [Mod]}.
+
+supervisor(Mod) ->
+ supervisor(Mod, Mod).
+
+supervisor(Name, Mod) ->
+ {Name, {Mod, start_link, []}, permanent, infinity, supervisor, [Mod]}.
+
+simple_supervisor(Mod) ->
+ Name = list_to_atom(atom_to_list(Mod) ++ "_sup"),
+ {Name, {ejabberd_tmp_sup, start_link, [Name, Mod]},
+ permanent, infinity, supervisor, [ejabberd_tmp_sup]}.
diff --git a/src/gen_mod.erl b/src/gen_mod.erl
index a477ec295..836e9dba8 100644
--- a/src/gen_mod.erl
+++ b/src/gen_mod.erl
@@ -555,7 +555,8 @@ validate_opts(Host, Module, Opts0) ->
undef ->
Opts;
Validators ->
- validate_opts(Host, Module, Opts, Required, Validators)
+ Opts1 = validate_opts(Host, Module, Opts, Required, Validators),
+ remove_duplicated_opts(Opts1)
end}
catch _:{missing_required_option, Opt} ->
ErrTxt = io_lib:format("Module '~s' is missing required option '~s'",
@@ -680,6 +681,16 @@ merge_opts(Opts, DefaultOpts) ->
end
end, Result, Opts).
+remove_duplicated_opts([{Opt, Val}, {Opt, _Default}|Opts]) ->
+ [{Opt, Val}|remove_duplicated_opts(Opts)];
+remove_duplicated_opts([{Opt, [{SubOpt, _}|_] = SubOpts}|Opts])
+ when is_atom(SubOpt) ->
+ [{Opt, remove_duplicated_opts(SubOpts)}|remove_duplicated_opts(Opts)];
+remove_duplicated_opts([OptVal|Opts]) ->
+ [OptVal|remove_duplicated_opts(Opts)];
+remove_duplicated_opts([]) ->
+ [].
+
-spec get_submodules(binary(), module(), opts()) -> [module()].
get_submodules(Host, Module, Opts) ->
try Module:mod_options(Host) of
diff --git a/src/mod_configure.erl b/src/mod_configure.erl
index db0780834..471e2bcdc 100644
--- a/src/mod_configure.erl
+++ b/src/mod_configure.erl
@@ -1528,8 +1528,11 @@ set_form(From, Host, ?NS_ADMINL(<<"add-user">>), _Lang,
true = lists:member(Server, ?MYHOSTS),
true = Server == Host orelse
get_permission_level(From) == global,
- ejabberd_auth:try_register(User, Server, Password),
- {result, undefined};
+ case ejabberd_auth:try_register(User, Server, Password) of
+ ok -> {result, undefined};
+ {error, exists} -> {error, xmpp:err_conflict()};
+ {error, not_allowed} -> {error, xmpp:err_not_allowed()}
+ end;
set_form(From, Host, ?NS_ADMINL(<<"delete-user">>),
_Lang, XData) ->
AccountStringList = get_values(<<"accountjids">>,
diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl
index 35ea746fd..87ae28797 100644
--- a/src/mod_muc_room.erl
+++ b/src/mod_muc_room.erl
@@ -3378,8 +3378,6 @@ remove_nonmembers(StateData) ->
-spec set_opts([{atom(), any()}], state()) -> state().
set_opts([], StateData) -> StateData;
-set_opts([{Opt, Val}, {Opt, _DefaultVal} | Opts], StateData) ->
- set_opts([{Opt, Val} | Opts], StateData);
set_opts([{Opt, Val} | Opts], StateData) ->
NSD = case Opt of
title ->
diff --git a/src/mod_pubsub.erl b/src/mod_pubsub.erl
index cd9aedef2..4a5b3b4a2 100644
--- a/src/mod_pubsub.erl
+++ b/src/mod_pubsub.erl
@@ -261,8 +261,8 @@ init([ServerHost, Opts]) ->
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
DefaultModule = plugin(Host, hd(Plugins)),
DefaultNodeCfg = merge_config(
- gen_mod:get_opt(default_node_config, Opts),
- DefaultModule:options()),
+ [gen_mod:get_opt(default_node_config, Opts),
+ DefaultModule:options()]),
lists:foreach(
fun(H) ->
T = gen_mod:get_module_proc(H, config),
@@ -1480,7 +1480,9 @@ create_node(Host, ServerHost, <<>>, Owner, Type, Access, Configuration) ->
end;
create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
Type = select_type(ServerHost, Host, Node, GivenType),
- NodeOptions = merge_config(Configuration, node_options(Host, Type)),
+ NodeOptions = merge_config(
+ [node_config(Node, ServerHost),
+ Configuration, node_options(Host, Type)]),
CreateNode =
fun() ->
Parent = case node_call(Host, Type, node_to_path, [Node]) of
@@ -3153,6 +3155,20 @@ node_owners_call(Host, Type, Nidx, []) ->
node_owners_call(_Host, _Type, _Nidx, Owners) ->
Owners.
+node_config(Node, ServerHost) ->
+ Opts = gen_mod:get_module_opt(ServerHost, ?MODULE, force_node_config),
+ node_config(Node, ServerHost, Opts).
+
+node_config(Node, ServerHost, [{RE, Opts}|NodeOpts]) ->
+ case re:run(Node, RE) of
+ {match, _} ->
+ Opts;
+ nomatch ->
+ node_config(Node, ServerHost, NodeOpts)
+ end;
+node_config(_, _, []) ->
+ [].
+
%% @spec (Host, Options) -> MaxItems
%% Host = host()
%% Options = [Option]
@@ -3215,7 +3231,9 @@ set_configure(Host, Node, From, Config, Lang) ->
[] -> node_options(Host, Type);
_ -> Options
end,
- NewOpts = merge_config(Config, OldOpts),
+ NewOpts = merge_config(
+ [node_config(Node, serverhost(Host)),
+ Config, OldOpts]),
case tree_call(Host,
set_node,
[N#pubsub_node{options = NewOpts}]) of
@@ -3238,12 +3256,9 @@ set_configure(Host, Node, From, Config, Lang) ->
Other
end.
--spec merge_config([proplists:property()], [proplists:property()]) -> [proplists:property()].
-merge_config(CustomConfig, DefaultConfig) ->
- lists:foldl(
- fun({Opt, Val}, Acc) ->
- lists:keystore(Opt, 1, Acc, {Opt, Val})
- end, DefaultConfig, CustomConfig).
+-spec merge_config([[proplists:property()]]) -> [proplists:property()].
+merge_config(ListOfConfigs) ->
+ lists:ukeysort(1, lists:flatten(ListOfConfigs)).
-spec decode_node_config(undefined | xdata(), binary(), binary()) ->
pubsub_node_config:result() |
@@ -3863,6 +3878,15 @@ mod_opt_type(max_subscriptions_node) ->
fun(A) when is_integer(A) andalso A >= 0 -> A;
(undefined) -> undefined
end;
+mod_opt_type(force_node_config) ->
+ fun(NodeOpts) ->
+ lists:map(
+ fun({Node, Opts}) ->
+ {ok, RE} = re:compile(
+ ejabberd_regexp:sh_to_awk(Node)),
+ {RE, lists:keysort(1, Opts)}
+ end, NodeOpts)
+ end;
mod_opt_type(default_node_config) ->
fun (A) when is_list(A) -> A end;
mod_opt_type(nodetree) ->
@@ -3885,4 +3909,9 @@ mod_options(Host) ->
{pep_mapping, []},
{plugins, [?STDNODE]},
{max_subscriptions_node, undefined},
- {default_node_config, []}].
+ {default_node_config, []},
+ %% Avoid using OMEMO by default because it
+ %% introduces a lot of hard-to-track problems
+ {force_node_config,
+ [{<<"eu.siacs.conversations.axolotl.*">>,
+ [{access_model, whitelist}]}]}].
diff --git a/src/mod_push_keepalive.erl b/src/mod_push_keepalive.erl
index 35932a815..750427ee1 100644
--- a/src/mod_push_keepalive.erl
+++ b/src/mod_push_keepalive.erl
@@ -156,9 +156,15 @@ c2s_session_resumed(State) ->
-spec c2s_copy_session(c2s_state(), c2s_state()) -> c2s_state().
c2s_copy_session(State, #{push_enabled := true,
push_resume_timeout := ResumeTimeout,
- push_wake_on_timeout := WakeOnTimeout}) ->
- State#{push_resume_timeout => ResumeTimeout,
- push_wake_on_timeout => WakeOnTimeout};
+ push_wake_on_timeout := WakeOnTimeout} = OldState) ->
+ State1 = case maps:find(push_resume_timeout_orig, OldState) of
+ {ok, Val} ->
+ State#{push_resume_timeout_orig => Val};
+ error ->
+ State
+ end,
+ State1#{push_resume_timeout => ResumeTimeout,
+ push_wake_on_timeout => WakeOnTimeout};
c2s_copy_session(State, _) ->
State.
diff --git a/src/mod_stream_mgmt.erl b/src/mod_stream_mgmt.erl
index 6ca5a8b39..a8aeaaef0 100644
--- a/src/mod_stream_mgmt.erl
+++ b/src/mod_stream_mgmt.erl
@@ -664,6 +664,8 @@ inherit_session_state(#{user := U, server := S,
exit:{normal, _} ->
{error, <<"Previous session PID has exited">>};
exit:{timeout, _} ->
+ ejabberd_sm:close_session(OldSID, U, S, R),
+ ejabberd_c2s:stop(OldPID),
{error, <<"Session state copying timed out">>}
end
end;
@@ -733,7 +735,9 @@ bounce_message_queue() ->
need_to_enqueue(State, Pkt) when ?is_stanza(Pkt) ->
{not xmpp:get_meta(Pkt, mgmt_is_resent, false), State};
need_to_enqueue(#{mgmt_force_enqueue := true} = State, #xmlel{}) ->
- {true, maps:remove(mgmt_is_resent, State)};
+ State1 = maps:remove(mgmt_force_enqueue, State),
+ State2 = maps:remove(mgmt_is_resent, State1),
+ {true, State2};
need_to_enqueue(State, _) ->
{false, State}.