S2S timeouts
rewrite S2S key validation
iq:browse (?)
-SRV DNS records
+more correctly work with SRV DNS records (priority, weight, etc...)
karma
SSL
+SASL
JEP-62,63 (?)
make roster set work in one transaction
<DT><TT>{user_regexp, <regexp>}</TT><DD> Matches local user with name that
mathes <TT><regexp></TT>. Example:
<PRE>
-{acl, tests, {user, "test.*"}}.
+{acl, tests, {user, "^test[0-9]*$"}}.
</PRE>
<DT><TT>{user_regexp, <regexp>, <server>}</TT><DD> Matches user with name
that mathes <TT><regexp></TT> and from server <TT><server></TT>. Example:
<PRE>
-{acl, tests, {user, "test.*", "localhost"}}.
+{acl, tests, {user, "^test", "localhost"}}.
</PRE>
<DT><TT>{server_regexp, <regexp>}</TT><DD> Matches any JID from server that
matches <TT><regexp></TT>. Example:
<PRE>
-{acl, icq, {server, "icq.*"}}.
+{acl, icq, {server, "^icq\\."}}.
</PRE>
<DT><TT>{node_regexp, <user_regexp>, <server_regexp>}</TT><DD> Matches user
with name that mathes <TT><user_regexp></TT> and from server that matches
<TT><server_regexp></TT>. Example:
<PRE>
-{acl, aleksey, {node_regexp, "aleksey.*", "jabber.(ru|org)"}}.
+{acl, aleksey, {node_regexp, "^aleksey", "^jabber.(ru|org)$"}}.
</PRE>
<DT><TT>{user_glob, <glob>}</TT><DD>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><!--TOC paragraph Node <TT>config/acls</TT>-->
<H5> Node <TT>config/acls</TT></H5><!--SEC END -->
-Via <TT>jabber:x:data</TT> queries to this node possible edit ACLs list. (See
+Via <TT>jabber:x:data</TT> queries to this node possible to edit ACLs list. (See
figure <A HREF="#fig:acls">2</A>)
<BLOCKQUOTE><DIV ALIGN=center><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
[acls editing window]
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></DIV></BLOCKQUOTE><!--TOC paragraph Node <TT>config/access</TT>-->
<H5> Node <TT>config/access</TT></H5><!--SEC END -->
-Via <TT>jabber:x:data</TT> queries to this node possible edit access rules.
-<B>Not work yet</B>.<BR>
+Via <TT>jabber:x:data</TT> queries to this node possible to edit access rules.<BR>
<BR>
<!--TOC paragraph Node <TT>config/remusers</TT>-->
\item[\texttt{\{user\_regexp, <regexp>\}}] Matches local user with name that
mathes \texttt{<regexp>}. Example:
\begin{verbatim}
-{acl, tests, {user, "test.*"}}.
+{acl, tests, {user, "^test[0-9]*$"}}.
\end{verbatim}
+%$
\item[\texttt{\{user\_regexp, <regexp>, <server>\}}] Matches user with name
that mathes \texttt{<regexp>} and from server \texttt{<server>}. Example:
\begin{verbatim}
-{acl, tests, {user, "test.*", "localhost"}}.
+{acl, tests, {user, "^test", "localhost"}}.
\end{verbatim}
\item[\texttt{\{server\_regexp, <regexp>\}}] Matches any JID from server that
matches \texttt{<regexp>}. Example:
\begin{verbatim}
-{acl, icq, {server, "icq.*"}}.
+{acl, icq, {server, "^icq\\."}}.
\end{verbatim}
\item[\texttt{\{node\_regexp, <user\_regexp>, <server\_regexp>\}}] Matches user
with name that mathes \texttt{<user\_regexp>} and from server that matches
\texttt{<server\_regexp>}. Example:
\begin{verbatim}
-{acl, aleksey, {node_regexp, "aleksey.*", "jabber.(ru|org)"}}.
+{acl, aleksey, {node_regexp, "^aleksey", "^jabber.(ru|org)$"}}.
\end{verbatim}
+%$
\item[\texttt{\{user\_glob, <glob>\}}]
\item[\texttt{\{user\_glob, <glob>, <server>\}}]
\paragraph{Node \texttt{config/acls}}
-Via \ns{jabber:x:data} queries to this node possible edit ACLs list. (See
+Via \ns{jabber:x:data} queries to this node possible to edit ACLs list. (See
figure~\ref{fig:acls})
\begin{figure}[htbp]
\centering
\paragraph{Node \texttt{config/access}}
-Via \ns{jabber:x:data} queries to this node possible edit access rules.
-\textbf{Not work yet}.
+Via \ns{jabber:x:data} queries to this node possible to edit access rules.
+
\paragraph{Node \texttt{config/remusers}}
ejabberd_mod_roster,
ejabberd_listeners
]},
- {applications, [kernel, stdlib, mnesia]},
+ {applications, [kernel, stdlib, mnesia, crypto, ssl]},
{env, []},
{mod, {ejabberd_app, []}}]}.
{host, "e.localhost"}.
{listen, [{5522, ejabberd_c2s, start, [{access, c2s}]},
+ %{5523, ejabberd_c2s, start,
+ % [{access, c2s}, {ssl, [{certfile, "./ssl.pem"}]}]},
{5269, ejabberd_s2s_in, start, []},
{8888, ejabberd_service, start,
[{host, "asd.e.localhost", [{password, "asdqwe"}]}]}
start() ->
application:start(mnesia),
+ application:start(crypto),
+ application:start(ssl),
application:start(ejabberd).
stop() ->
-behaviour(gen_fsm).
%% External exports
--export([start/2, receiver/2, sender/1, send_text/2, send_element/2]).
+-export([start/2, receiver/3, sender/2, send_text/2, send_element/2]).
%% gen_fsm callbacks
-export([init/1, wait_for_stream/2, wait_for_auth/2, session_established/2,
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
-start(Socket, Opts) ->
- gen_fsm:start(ejabberd_c2s, [Socket, Opts], ?FSMOPTS).
+start(SockData, Opts) ->
+ gen_fsm:start(ejabberd_c2s, [SockData, Opts], ?FSMOPTS).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%% ignore |
%% {stop, StopReason}
%%----------------------------------------------------------------------
-init([Socket, Opts]) ->
- SenderPid = spawn(?MODULE, sender, [Socket]),
- ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
+init([{SockMod, Socket}, Opts]) ->
+ SenderPid = spawn(?MODULE, sender, [Socket, SockMod]),
+ ReceiverPid = spawn(?MODULE, receiver, [Socket, SockMod, self()]),
Access = case lists:keysearch(access, 1, Opts) of
{value, {_, A}} ->
A;
%%% Internal functions
%%%----------------------------------------------------------------------
-receiver(Socket, C2SPid) ->
+receiver(Socket, SockMod, C2SPid) ->
XMLStreamPid = xml_stream:start(C2SPid),
- receiver(Socket, C2SPid, XMLStreamPid).
+ receiver(Socket, SockMod, C2SPid, XMLStreamPid).
-receiver(Socket, C2SPid, XMLStreamPid) ->
- case gen_tcp:recv(Socket, 0) of
+receiver(Socket, SockMod, C2SPid, XMLStreamPid) ->
+ case SockMod:recv(Socket, 0) of
{ok, Text} ->
xml_stream:send_text(XMLStreamPid, Text),
- receiver(Socket, C2SPid, XMLStreamPid);
+ receiver(Socket, SockMod, C2SPid, XMLStreamPid);
{error, Reason} ->
exit(XMLStreamPid, closed),
gen_fsm:send_event(C2SPid, closed),
ok
end.
-sender(Socket) ->
+sender(Socket, SockMod) ->
receive
{send_text, Text} ->
- gen_tcp:send(Socket,Text),
- sender(Socket);
+ SockMod:send(Socket,Text),
+ sender(Socket, SockMod);
close ->
- gen_tcp:close(Socket),
+ SockMod:close(Socket),
ok
end.
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
--export([start_link/0, init/1, start/4, init/4]).
+-export([start_link/0, init/1, start/4,
+ init/4,
+ init_ssl/5
+ ]).
start_link() ->
supervisor:start_link({local, ejabberd_listeners}, ?MODULE, []).
lists:map(
fun({Port, Module, Fun, Opts}) ->
{Port,
- {?MODULE, start, [Port, Module, Fun, [Opts]]},
+ {?MODULE, start, [Port, Module, Fun, Opts]},
permanent,
brutal_kill,
worker,
end.
-start(Port, Module, Fun, Args) ->
- {ok, spawn_link(?MODULE, init, [Port, Module, Fun, Args])}.
+start(Port, Module, Fun, Opts) ->
+ case lists:keysearch(ssl, 1, Opts) of
+ {value, {ssl, SSLOpts}} ->
+ {ok, spawn_link(?MODULE, init_ssl,
+ [Port, Module, Fun, Opts, SSLOpts])};
+ _ ->
+ {ok, spawn_link(?MODULE, init, [Port, Module, Fun, Opts])}
+ end.
-init(Port, Module, Fun, Args) ->
+init(Port, Module, Fun, Opts) ->
{ok, ListenSocket} = gen_tcp:listen(Port, [binary,
{packet, 0},
{active, false},
{reuseaddr, true}]),
- accept(ListenSocket, Module, Fun, Args).
+ accept(ListenSocket, Module, Fun, Opts).
-accept(ListenSocket, Module, Fun, Args) ->
+accept(ListenSocket, Module, Fun, Opts) ->
case gen_tcp:accept(ListenSocket) of
{ok,Socket} ->
- apply(Module, Fun, [Socket] ++ Args),
- %ejabberd_c2s:start(Socket),
- accept(ListenSocket, Module, Fun, Args)
+ apply(Module, Fun, [{gen_tcp, Socket}, Opts]),
+ accept(ListenSocket, Module, Fun, Opts)
+ end.
+
+
+init_ssl(Port, Module, Fun, Opts, SSLOpts) ->
+ {ok, ListenSocket} = ssl:listen(Port, [binary,
+ {packet, 0},
+ {active, false},
+ {nodelay, true},
+ {backlog, 0},
+ {cachetimout, 0} |
+ SSLOpts]),
+ accept_ssl(ListenSocket, Module, Fun, Opts).
+
+accept_ssl(ListenSocket, Module, Fun, Opts) ->
+ case ssl:accept(ListenSocket) of
+ {ok,Socket} ->
+ apply(Module, Fun, [{ssl, Socket}, Opts]),
+ accept_ssl(ListenSocket, Module, Fun, Opts)
end.
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
-start(Socket, Opts) ->
- gen_fsm:start(ejabberd_s2s_in, [Socket], ?FSMOPTS).
+start(SockData, Opts) ->
+ gen_fsm:start(ejabberd_s2s_in, [SockData], ?FSMOPTS).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%% ignore |
%% {stop, StopReason}
%%----------------------------------------------------------------------
-init([Socket]) ->
+init([{SockMod, Socket}]) ->
ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
{ok, wait_for_stream, #state{socket = Socket,
receiver = ReceiverPid,
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
-start(Socket, Opts) ->
- gen_fsm:start(ejabberd_service, [Socket, Opts], ?FSMOPTS).
+start(SockData, Opts) ->
+ gen_fsm:start(ejabberd_service, [SockData, Opts], ?FSMOPTS).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%% ignore |
%% {stop, StopReason}
%%----------------------------------------------------------------------
-init([Socket, Opts]) ->
+init([{SockMod, Socket}, Opts]) ->
{Host, Password} =
case lists:keysearch(host, 1, Opts) of
{value, {_, H, HOpts}} ->
lists:flatten(io_lib:format("~p.",
[ets:tab2list(acl)])),
"\n"))
- %{xmlelement, "value", [], [{xmlcdata, ?MYNAME}]}
+ }
+ ]};
+
+get_form(["config", "access"], Lang) ->
+ {result, [{xmlelement, "title", [],
+ [{xmlcdata,
+ translate:translate(
+ Lang, "Access Configuration")}]},
+ %{xmlelement, "instructions", [],
+ % [{xmlcdata,
+ % translate:translate(
+ % Lang, "")}]},
+ {xmlelement, "field", [{"type", "text-multi"},
+ {"label",
+ translate:translate(
+ Lang, "Access Rules")},
+ {"var", "access"}],
+ lists:map(fun(S) ->
+ {xmlelement, "value", [], [{xmlcdata, S}]}
+ end,
+ string:tokens(
+ lists:flatten(
+ io_lib:format(
+ "~p.",
+ [ets:select(config,
+ [{{config, {access, '$1'}, '$2'},
+ [],
+ [{{access, '$1', '$2'}}]}])
+ ])),
+ "\n"))
}
]};
set_form(["config", "acls"], Lang, XData) ->
case lists:keysearch("acls", 1, XData) of
{value, {_, Strings}} ->
- String = lists:foldl(fun(S, Res) ->
- Res ++ S ++ "\n"
- end, "", Strings),
- case erl_scan:string(String) of
- {ok, Tokens, _} ->
- case erl_parse:parse_term(Tokens) of
- {ok, ACLs} ->
- case acl:add_list(ACLs, true) of
- ok ->
- {result, []};
- _ ->
- {error, "406", "Not Acceptable"}
- end;
+ String = lists:foldl(fun(S, Res) ->
+ Res ++ S ++ "\n"
+ end, "", Strings),
+ case erl_scan:string(String) of
+ {ok, Tokens, _} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, ACLs} ->
+ case acl:add_list(ACLs, true) of
+ ok ->
+ {result, []};
_ ->
{error, "406", "Not Acceptable"}
end;
_ ->
{error, "406", "Not Acceptable"}
end;
+ _ ->
+ {error, "406", "Not Acceptable"}
+ end;
+ _ ->
+ {error, "406", "Not Acceptable"}
+ end;
+
+set_form(["config", "access"], Lang, XData) ->
+ SetAccess =
+ fun(Rs) ->
+ mnesia:transaction(
+ fun() ->
+ Os = mnesia:select(config,
+ [{{config, {access, '$1'}, '$2'},
+ [],
+ ['$_']}]),
+ lists:foreach(fun(O) ->
+ mnesia:delete_object(O)
+ end, Os),
+ lists:foreach(
+ fun({access, Name, Rules}) ->
+ mnesia:write({config,
+ {access, Name},
+ Rules})
+ end, Rs)
+ end)
+ end,
+ case lists:keysearch("access", 1, XData) of
+ {value, {_, Strings}} ->
+ String = lists:foldl(fun(S, Res) ->
+ Res ++ S ++ "\n"
+ end, "", Strings),
+ case erl_scan:string(String) of
+ {ok, Tokens, _} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, Rs} ->
+ case SetAccess(Rs) of
+ {atomic, _} ->
+ {result, []};
+ E ->
+ io:format("A: ~p~n", [E]),
+ {error, "406", "Not Acceptable"}
+ end;
+ _ ->
+ {error, "406", "Not Acceptable"}
+ end;
+ _ ->
+ {error, "406", "Not Acceptable"}
+ end;
_ ->
{error, "406", "Not Acceptable"}
end;