aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ejabberd.service.template7
-rw-r--r--include/ejabberd_oauth.hrl26
-rw-r--r--src/acl.erl1
-rw-r--r--src/ejabberd_app.erl7
-rw-r--r--src/ejabberd_c2s.erl18
-rw-r--r--src/ejabberd_oauth.erl67
-rw-r--r--src/ejabberd_oauth_mnesia.erl65
-rw-r--r--src/ext_mod.erl37
-rw-r--r--src/mod_echo.erl2
-rw-r--r--src/mod_http_upload_quota.erl6
-rw-r--r--src/mod_irc.erl2
-rw-r--r--src/mod_mix.erl2
-rw-r--r--src/mod_muc.erl3
-rw-r--r--src/mod_muc_log.erl2
-rw-r--r--src/nodetree_tree_sql.erl6
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;