diff options
-rw-r--r-- | ejabberd.service.template | 7 | ||||
-rw-r--r-- | include/ejabberd_oauth.hrl | 26 | ||||
-rw-r--r-- | src/acl.erl | 1 | ||||
-rw-r--r-- | src/ejabberd_app.erl | 7 | ||||
-rw-r--r-- | src/ejabberd_c2s.erl | 18 | ||||
-rw-r--r-- | src/ejabberd_oauth.erl | 67 | ||||
-rw-r--r-- | src/ejabberd_oauth_mnesia.erl | 65 | ||||
-rw-r--r-- | src/ext_mod.erl | 37 | ||||
-rw-r--r-- | src/mod_echo.erl | 2 | ||||
-rw-r--r-- | src/mod_http_upload_quota.erl | 6 | ||||
-rw-r--r-- | src/mod_irc.erl | 2 | ||||
-rw-r--r-- | src/mod_mix.erl | 2 | ||||
-rw-r--r-- | src/mod_muc.erl | 3 | ||||
-rw-r--r-- | src/mod_muc_log.erl | 2 | ||||
-rw-r--r-- | src/nodetree_tree_sql.erl | 6 |
15 files changed, 195 insertions, 56 deletions
diff --git a/ejabberd.service.template b/ejabberd.service.template index 80b15adbd..49ba14737 100644 --- a/ejabberd.service.template +++ b/ejabberd.service.template @@ -12,6 +12,13 @@ ExecStop=@ctlscriptpath@/ejabberdctl stop ExecReload=@ctlscriptpath@/ejabberdctl reload_config Type=oneshot RemainAfterExit=yes +# The CAP_DAC_OVERRIDE capability is required for pam authentication to work +CapabilityBoundingSet=CAP_DAC_OVERRIDE +PrivateTmp=true +PrivateDevices=true +ProtectHome=true +ProtectSystem=full +NoNewPrivileges=true [Install] WantedBy=multi-user.target diff --git a/include/ejabberd_oauth.hrl b/include/ejabberd_oauth.hrl new file mode 100644 index 000000000..6b5a9bcc8 --- /dev/null +++ b/include/ejabberd_oauth.hrl @@ -0,0 +1,26 @@ +%%%---------------------------------------------------------------------- +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License along +%%% with this program; if not, write to the Free Software Foundation, Inc., +%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +%%% +%%%---------------------------------------------------------------------- + +-record(oauth_token, { + token = <<"">> :: binary() | '_', + us = {<<"">>, <<"">>} :: {binary(), binary()} | '_', + scope = [] :: [binary()] | '_', + expire :: integer() | '$1' + }). diff --git a/src/acl.erl b/src/acl.erl index 834b85d97..897996976 100644 --- a/src/acl.erl +++ b/src/acl.erl @@ -35,6 +35,7 @@ transform_options/1, opt_type/1, acl_rule_matches/3, acl_rule_verify/1, access_matches/3, transform_access_rules_config/1, + parse_ip_netmask/1, access_rules_validator/1, shaper_rules_validator/1]). -include("ejabberd.hrl"). diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl index 703614f63..6f0b97fa3 100644 --- a/src/ejabberd_app.erl +++ b/src/ejabberd_app.erl @@ -45,6 +45,7 @@ start(normal, _Args) -> write_pid_file(), jid:start(), start_apps(), + start_elixir_application(), ejabberd:check_app(ejabberd), randoms:start(), db_init(), @@ -237,3 +238,9 @@ opt_type(modules) -> Mods) end; opt_type(_) -> [cluster_nodes, loglevel, modules, net_ticktime]. + +start_elixir_application() -> + case application:ensure_started(elixir) of + ok -> ok; + {error, _Msg} -> ?ERROR_MSG("Elixir application not started.", []) + end. diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 74ce74d62..24a2af56d 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1632,11 +1632,18 @@ handle_info({route, From, To, <<"groupchat">> -> ok; <<"headline">> -> ok; _ -> - Err = - jlib:make_error_reply(Packet, - ?ERR_SERVICE_UNAVAILABLE), - ejabberd_router:route(To, From, - Err) + case fxml:get_subtag_with_xmlns(Packet, + <<"x">>, + ?NS_MUC_USER) + of + false -> + Err = + jlib:make_error_reply(Packet, + ?ERR_SERVICE_UNAVAILABLE), + ejabberd_router:route(To, From, + Err); + _ -> ok + end end, {false, Attrs, StateData} end; @@ -1855,6 +1862,7 @@ send_text(StateData, Text) -> send_element(StateData, El) when StateData#state.mgmt_state == pending -> ?DEBUG("Cannot send element while waiting for resumption: ~p", [El]); send_element(StateData, El) when StateData#state.xml_socket -> + ?DEBUG("Send XML on stream = ~p", [fxml:element_to_binary(El)]), (StateData#state.sockmod):send_xml(StateData#state.socket, {xmlstreamelement, El}); send_element(StateData, El) -> diff --git a/src/ejabberd_oauth.erl b/src/ejabberd_oauth.erl index 531f27749..e4396260e 100644 --- a/src/ejabberd_oauth.erl +++ b/src/ejabberd_oauth.erl @@ -56,6 +56,7 @@ -include("ejabberd_http.hrl"). -include("ejabberd_web_admin.hrl"). +-include("ejabberd_oauth.hrl"). -include("ejabberd_commands.hrl"). @@ -64,23 +65,18 @@ %% * Using the web form/api results in the token being generated in behalf of the user providing the user/pass %% * Using the command line and oauth_issue_token command, the token is generated in behalf of ejabberd' sysadmin %% (as it has access to ejabberd command line). --record(oauth_token, { - token = {<<"">>, <<"">>} :: {binary(), binary()}, - us = {<<"">>, <<"">>} :: {binary(), binary()}, - scope = [] :: [binary()], - expire :: integer() - }). -define(EXPIRE, 31536000). start() -> - init_db(mnesia, ?MYNAME), + DBMod = get_db_backend(), + DBMod:init(), Expire = expire(), application:set_env(oauth2, backend, ejabberd_oauth), application:set_env(oauth2, expiry_time, Expire), application:start(oauth2), ChildSpec = {?MODULE, {?MODULE, start_link, []}, - temporary, 1000, worker, [?MODULE]}, + transient, 1000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec), ejabberd_commands:register_commands(get_commands_spec()), ok. @@ -172,15 +168,8 @@ handle_cast(_Msg, State) -> {noreply, State}. handle_info(clean, State) -> {MegaSecs, Secs, MiniSecs} = os:timestamp(), TS = 1000000 * MegaSecs + Secs, - F = fun() -> - Ts = mnesia:select( - oauth_token, - [{#oauth_token{expire = '$1', _ = '_'}, - [{'<', '$1', TS}], - ['$_']}]), - lists:foreach(fun mnesia:delete_object/1, Ts) - end, - mnesia:async_dirty(F), + DBMod = get_db_backend(), + DBMod:clean(TS), erlang:send_after(trunc(expire() * 1000 * (1 + MiniSecs / 1000000)), self(), clean), {noreply, State}; @@ -191,16 +180,6 @@ terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. -init_db(mnesia, _Host) -> - mnesia:create_table(oauth_token, - [{disc_copies, [node()]}, - {attributes, - record_info(fields, oauth_token)}]), - mnesia:add_table_copy(oauth_token, node(), disc_copies); -init_db(_, _) -> - ok. - - get_client_identity(Client, Ctx) -> {ok, {Ctx, {client, Client}}}. verify_redirection_uri(_, _, Ctx) -> {ok, Ctx}. @@ -305,7 +284,8 @@ associate_access_token(AccessToken, Context, AppContext) -> scope = Scope, expire = Expire }, - mnesia:dirty_write(R), + DBMod = get_db_backend(), + DBMod:store(R), {ok, AppContext}. associate_refresh_token(_RefreshToken, _Context, AppContext) -> @@ -315,10 +295,11 @@ associate_refresh_token(_RefreshToken, _Context, AppContext) -> check_token(User, Server, ScopeList, Token) -> LUser = jid:nodeprep(User), LServer = jid:nameprep(Server), - case catch mnesia:dirty_read(oauth_token, Token) of - [#oauth_token{us = {LUser, LServer}, - scope = TokenScope, - expire = Expire}] -> + DBMod = get_db_backend(), + case DBMod:lookup(Token) of + #oauth_token{us = {LUser, LServer}, + scope = TokenScope, + expire = Expire} -> {MegaSecs, Secs, _} = os:timestamp(), TS = 1000000 * MegaSecs + Secs, if @@ -335,10 +316,11 @@ check_token(User, Server, ScopeList, Token) -> end. check_token(ScopeList, Token) -> - case catch mnesia:dirty_read(oauth_token, Token) of - [#oauth_token{us = US, - scope = TokenScope, - expire = Expire}] -> + DBMod = get_db_backend(), + case DBMod:lookup(Token) of + #oauth_token{us = US, + scope = TokenScope, + expire = Expire} -> {MegaSecs, Secs, _} = os:timestamp(), TS = 1000000 * MegaSecs + Secs, if @@ -553,6 +535,15 @@ process(_Handlers, process(_Handlers, _Request) -> ejabberd_web:error(not_found). +-spec get_db_backend() -> module(). + +get_db_backend() -> + DBType = ejabberd_config:get_option( + oauth_db_type, + fun(T) -> ejabberd_config:v_db(?MODULE, T) end, + mnesia), + list_to_atom("ejabberd_oauth_" ++ atom_to_list(DBType)). + %% Headers as per RFC 6749 json_response(Code, Body) -> @@ -703,4 +694,6 @@ opt_type(oauth_expire) -> fun(I) when is_integer(I), I >= 0 -> I end; opt_type(oauth_access) -> fun acl:access_rules_validator/1; -opt_type(_) -> [oauth_expire, oauth_access]. +opt_type(oauth_db_type) -> + fun(T) -> ejabberd_config:v_db(?MODULE, T) end; +opt_type(_) -> [oauth_expire, oauth_access, oauth_db_type]. diff --git a/src/ejabberd_oauth_mnesia.erl b/src/ejabberd_oauth_mnesia.erl new file mode 100644 index 000000000..a23f443ed --- /dev/null +++ b/src/ejabberd_oauth_mnesia.erl @@ -0,0 +1,65 @@ +%%%------------------------------------------------------------------- +%%% File : ejabberd_oauth_mnesia.erl +%%% Author : Alexey Shchepin <alexey@process-one.net> +%%% Purpose : OAUTH2 mnesia backend +%%% Created : 20 Jul 2016 by Alexey Shchepin <alexey@process-one.net> +%%% +%%% +%%% ejabberd, Copyright (C) 2002-2016 ProcessOne +%%% +%%% This program is free software; you can redistribute it and/or +%%% modify it under the terms of the GNU General Public License as +%%% published by the Free Software Foundation; either version 2 of the +%%% License, or (at your option) any later version. +%%% +%%% This program is distributed in the hope that it will be useful, +%%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%%% General Public License for more details. +%%% +%%% You should have received a copy of the GNU General Public License +%%% along with this program; if not, write to the Free Software +%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +%%% 02111-1307 USA +%%% +%%%------------------------------------------------------------------- + +-module(ejabberd_oauth_mnesia). + +-export([init/0, + store/1, + lookup/1, + clean/1]). + +-include("ejabberd_oauth.hrl"). + +init() -> + mnesia:create_table(oauth_token, + [{disc_copies, [node()]}, + {attributes, + record_info(fields, oauth_token)}]), + mnesia:add_table_copy(oauth_token, node(), disc_copies), + ok. + +store(R) -> + mnesia:dirty_write(R). + +lookup(Token) -> + case catch mnesia:dirty_read(oauth_token, Token) of + [R] -> + R; + _ -> + false + end. + +clean(TS) -> + F = fun() -> + Ts = mnesia:select( + oauth_token, + [{#oauth_token{expire = '$1', _ = '_'}, + [{'<', '$1', TS}], + ['$_']}]), + lists:foreach(fun mnesia:delete_object/1, Ts) + end, + mnesia:async_dirty(F). + diff --git a/src/ext_mod.erl b/src/ext_mod.erl index 332d2c5e2..842bb09fc 100644 --- a/src/ext_mod.erl +++ b/src/ext_mod.erl @@ -484,17 +484,28 @@ compile_deps(_Module, _Spec, DestDir) -> filelib:ensure_dir(filename:join(Ebin, ".")), Result = lists:foldl(fun(Dep, Acc) -> Inc = filename:join(Dep, "include"), + Lib = filename:join(Dep, "lib"), Src = filename:join(Dep, "src"), Options = [{outdir, Ebin}, {i, Inc}], [file:copy(App, Ebin) || App <- filelib:wildcard(Src++"/*.app")], - Acc++[case compile:file(File, Options) of + + %% Compile erlang files + Acc1 = Acc ++ [case compile:file(File, Options) of {ok, _} -> ok; {ok, _, _} -> ok; {ok, _, _, _} -> ok; error -> {error, {compilation_failed, File}}; Error -> Error end - || File <- filelib:wildcard(Src++"/*.erl")] + || File <- filelib:wildcard(Src++"/*.erl")], + + %% Compile elixir files + Acc1 ++ [case compile_elixir_file(Ebin, File) of + {ok, _} -> ok; + {error, File} -> {error, {compilation_failed, File}} + end + || File <- filelib:wildcard(Lib ++ "/*.ex")] + end, [], filelib:wildcard("deps/*")), case lists:dropwhile( fun(ok) -> true; @@ -515,6 +526,8 @@ compile(_Module, _Spec, DestDir) -> verbose, report_errors, report_warnings] ++ ExtLib, [file:copy(App, Ebin) || App <- filelib:wildcard("src/*.app")], + + %% Compile erlang files Result = [case compile:file(File, Options) of {ok, _} -> ok; {ok, _, _} -> ok; @@ -523,14 +536,32 @@ compile(_Module, _Spec, DestDir) -> Error -> Error end || File <- filelib:wildcard("src/*.erl")], + + %% Compile elixir files + Result1 = Result ++ [case compile_elixir_file(Ebin, File) of + {ok, _} -> ok; + {error, File} -> {error, {compilation_failed, File}} + end + || File <- filelib:wildcard("lib/*.ex")], + case lists:dropwhile( fun(ok) -> true; (_) -> false - end, Result) of + end, Result1) of [] -> ok; [Error|_] -> Error end. +compile_elixir_file(Dest, File) when is_list(Dest) and is_list(File) -> + compile_elixir_file(list_to_binary(Dest), list_to_binary(File)); + +compile_elixir_file(Dest, File) -> + try 'Elixir.Kernel.ParallelCompiler':files_to_path([File], Dest, []) of + [Module] -> {ok, Module} + catch + _ -> {error, File} + end. + install(Module, Spec, DestDir) -> Errors = lists:dropwhile(fun({_, {ok, _}}) -> true; (_) -> false diff --git a/src/mod_echo.erl b/src/mod_echo.erl index ee904d798..96651aebf 100644 --- a/src/mod_echo.erl +++ b/src/mod_echo.erl @@ -63,7 +63,7 @@ start_link(Host, Opts) -> start(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, - temporary, 1000, worker, [?MODULE]}, + transient, 1000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec). stop(Host) -> diff --git a/src/mod_http_upload_quota.erl b/src/mod_http_upload_quota.erl index 35e266ddf..3051a4e87 100644 --- a/src/mod_http_upload_quota.erl +++ b/src/mod_http_upload_quota.erl @@ -251,7 +251,7 @@ terminate(Reason, #state{server_host = ServerHost, timers = Timers}) -> ?DEBUG("Stopping upload quota process for ~s: ~p", [ServerHost, Reason]), ejabberd_hooks:delete(http_upload_slot_request, ServerHost, ?MODULE, handle_slot_request, 50), - lists:foreach(fun(Timer) -> timer:cancel(Timer) end, Timers). + lists:foreach(fun timer:cancel/1, Timers). -spec code_change({down, _} | _, state(), _) -> {ok, state()}. @@ -299,7 +299,7 @@ enforce_quota(UserDir, SlotSize, _OldSize, MinSize, MaxSize) -> {[Path | AccFiles], AccSize + Size, NewSize} end, {[], 0, 0}, Files), if OldSize + SlotSize > MaxSize -> - lists:foreach(fun(File) -> del_file_and_dir(File) end, DelFiles), + lists:foreach(fun del_file_and_dir/1, DelFiles), file:del_dir(UserDir), % In case it's empty, now. NewSize + SlotSize; true -> @@ -314,7 +314,7 @@ delete_old_files(UserDir, CutOff) -> [] -> ok; OldFiles -> - lists:foreach(fun(File) -> del_file_and_dir(File) end, OldFiles), + lists:foreach(fun del_file_and_dir/1, OldFiles), file:del_dir(UserDir) % In case it's empty, now. end. diff --git a/src/mod_irc.erl b/src/mod_irc.erl index 2206028b7..e2203a306 100644 --- a/src/mod_irc.erl +++ b/src/mod_irc.erl @@ -90,7 +90,7 @@ start(Host, Opts) -> start_supervisor(Host), Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, - temporary, 1000, worker, [?MODULE]}, + transient, 1000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec). stop(Host) -> diff --git a/src/mod_mix.erl b/src/mod_mix.erl index b373ad13d..a81efd5ce 100644 --- a/src/mod_mix.erl +++ b/src/mod_mix.erl @@ -44,7 +44,7 @@ start_link(Host, Opts) -> start(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, - temporary, 5000, worker, [?MODULE]}, + transient, 5000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec). stop(Host) -> diff --git a/src/mod_muc.erl b/src/mod_muc.erl index a86f580d3..571f85926 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -95,7 +95,7 @@ start_link(Host, Opts) -> start(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, - temporary, 1000, worker, [?MODULE]}, + transient, 1000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec). stop(Host) -> @@ -225,6 +225,7 @@ init([Host, Opts]) -> public -> Bool; public_list -> Bool; mam -> Bool; + allow_subscription -> Bool; password -> fun iolist_to_binary/1; title -> fun iolist_to_binary/1; allow_private_messages_from_visitors -> diff --git a/src/mod_muc_log.erl b/src/mod_muc_log.erl index ec4711b43..d5ced9116 100644 --- a/src/mod_muc_log.erl +++ b/src/mod_muc_log.erl @@ -81,7 +81,7 @@ start_link(Host, Opts) -> start(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), ChildSpec = {Proc, {?MODULE, start_link, [Host, Opts]}, - temporary, 1000, worker, [?MODULE]}, + transient, 1000, worker, [?MODULE]}, supervisor:start_child(ejabberd_sup, ChildSpec). stop(Host) -> diff --git a/src/nodetree_tree_sql.erl b/src/nodetree_tree_sql.erl index edfdbc1d5..9f6b6d5a7 100644 --- a/src/nodetree_tree_sql.erl +++ b/src/nodetree_tree_sql.erl @@ -77,9 +77,9 @@ set_node(Record) when is_record(Record, pubsub_node) -> catch ejabberd_sql:sql_query_t( ?SQL("update pubsub_node set" - " host=%(H)s" - " node=%(Node)s" - " parent=%(Parent)s" + " host=%(H)s," + " node=%(Node)s," + " parent=%(Parent)s," " type=%(Type)s " "where nodeid=%(OldNidx)d")), OldNidx; |