diff options
-rw-r--r-- | ejabberd.yml.example | 1 | ||||
-rw-r--r-- | src/ejabberd_sup.erl | 192 | ||||
-rw-r--r-- | src/gen_mod.erl | 13 | ||||
-rw-r--r-- | src/mod_configure.erl | 7 | ||||
-rw-r--r-- | src/mod_muc_room.erl | 2 | ||||
-rw-r--r-- | src/mod_pubsub.erl | 51 | ||||
-rw-r--r-- | src/mod_push_keepalive.erl | 12 | ||||
-rw-r--r-- | src/mod_stream_mgmt.erl | 6 |
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}. |