Compare commits
178 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c526b0e8ff | |||
| 35136f47ed | |||
| 8f2233eff7 | |||
| 8879d1d533 | |||
| 71ae7e9fd9 | |||
| 644873dae9 | |||
| 9a11db91f9 | |||
| af8c6d2428 | |||
| 87357c700f | |||
| 7881c5670c | |||
| 881e02632b | |||
| 47d117c1bf | |||
| cf6f540d53 | |||
| 557e6ecdd0 | |||
| 5dd3f4c22b | |||
| e7c3b57b8b | |||
| c907915695 | |||
| 911ed4a7ca | |||
| 499ae96254 | |||
| ac31c85866 | |||
| c4c91cc956 | |||
| d809aafba0 | |||
| 6ffb120fce | |||
| 55f8aa1b22 | |||
| 274e9fe7b5 | |||
| f465742f2c | |||
| 9e83c45b3c | |||
| 446e6e6f3b | |||
| 3a5d2dbed8 | |||
| aea6166efe | |||
| 23cc0f8c3c | |||
| 81f4dd0e6a | |||
| dee3081df1 | |||
| 6acac7c93f | |||
| c2f664f941 | |||
| 75127a0deb | |||
| bb76da03ea | |||
| 3099702039 | |||
| 3ec623f329 | |||
| 6c323b729b | |||
| 17b05ff4b7 | |||
| 7bd5c7fe59 | |||
| 7b04a625be | |||
| 49b08949b1 | |||
| 141be53c21 | |||
| fd8e07af47 | |||
| c3c75affa9 | |||
| 85f09b365f | |||
| 645f11d79d | |||
| 0a20e45690 | |||
| 0a9f522222 | |||
| 4f293751f0 | |||
| 6f481e3ceb | |||
| 00534d4566 | |||
| 40185b6bd3 | |||
| 1de407c420 | |||
| 815b95c623 | |||
| 8e1a13b259 | |||
| a4049d9418 | |||
| ba30ac8ce8 | |||
| 43c3134f55 | |||
| 67fc2015de | |||
| 548ef7b835 | |||
| 4337300fce | |||
| cab8005bf3 | |||
| 4fc8d1c4a4 | |||
| 1261502f6a | |||
| dacba3ec00 | |||
| 4f8af723c6 | |||
| 5e446d50a8 | |||
| 22d76659c0 | |||
| 0f9db50c8d | |||
| 52b8226671 | |||
| 3b9e6eaa95 | |||
| 2c18f89d5b | |||
| 0381ce1e75 | |||
| fc77051b68 | |||
| bfe2545c01 | |||
| c6a9c30f1c | |||
| 508f3ef88d | |||
| 97f7d99007 | |||
| 2bbfc0b79e | |||
| 10a5a5eb01 | |||
| 2e529f5826 | |||
| 4a4cc32650 | |||
| d2114be6f3 | |||
| db51d522e8 | |||
| 82c42051c3 | |||
| e4c106e0dd | |||
| b64e1d95d2 | |||
| c41bab9ca0 | |||
| 063737e4f5 | |||
| cb3bb710bd | |||
| c30715e67b | |||
| 27594db029 | |||
| 6ac8f6eaee | |||
| 338d27b45b | |||
| 35a076c251 | |||
| 680384c342 | |||
| 11ff2a1ccf | |||
| 3ac1675919 | |||
| de85c1718e | |||
| 46f47db512 | |||
| 6811b92a80 | |||
| 8766854870 | |||
| 61ae0ff02c | |||
| 5522403e8e | |||
| b23d5754e8 | |||
| b1a03cc346 | |||
| ca94cbfd31 | |||
| 410db89167 | |||
| 638f2d2e67 | |||
| 56ee6f0518 | |||
| 4e83fc41d4 | |||
| 4ea481d1dd | |||
| 0bd4d1aade | |||
| d49aa429ca | |||
| 316a19d600 | |||
| c43037887a | |||
| 538e0d4844 | |||
| f3795e9d03 | |||
| 3df919244c | |||
| 67773c5174 | |||
| 61dee97738 | |||
| 6774418a7f | |||
| ad6fcc7865 | |||
| ca28faa51a | |||
| 5b730cdbf2 | |||
| 9ed0357760 | |||
| 06ce884aa8 | |||
| 3fc0eb4f5b | |||
| 3bfa683586 | |||
| 5be49cc0fa | |||
| 42c029d5f7 | |||
| a567abcfdf | |||
| 265c7b62c7 | |||
| 332567693c | |||
| de7dc4affa | |||
| 48c5ab59f1 | |||
| b2855d63a7 | |||
| 0282cf64a0 | |||
| e5cb9dad40 | |||
| ec819b4002 | |||
| acc162f4f4 | |||
| b8505f3e78 | |||
| 8a71e2e4f7 | |||
| a5284229cb | |||
| d0f36537fb | |||
| 3cf4fbc7b0 | |||
| fe4b1a492c | |||
| c3b4b4ce4f | |||
| 95244c3b6f | |||
| 89d91b609a | |||
| d28064518b | |||
| 7627575856 | |||
| 99444f2d0e | |||
| 4c0f87b2ff | |||
| 54363f8476 | |||
| 094f586811 | |||
| 45a3c7e0ce | |||
| e2652ce02f | |||
| df651d893e | |||
| a2e1f5c882 | |||
| 7f5796fe31 | |||
| 5f1191b9f5 | |||
| 0041a11c4a | |||
| e17a16a300 | |||
| 7b3d26992b | |||
| 9373ad20ca | |||
| b283cfa6f2 | |||
| a84771fd14 | |||
| 2bb6782bee | |||
| ae151927ae | |||
| dfbdffad44 | |||
| d71bc73271 | |||
| ea9c3fd8f7 | |||
| 63dba3fd64 | |||
| ffe02c46e4 |
@@ -93,7 +93,6 @@ Moreover, ejabberd comes with a wide range of other state-of-the-art features:
|
||||
- Users Directory based on users vCards.
|
||||
- Publish-Subscribe component with support for Personal Eventing.
|
||||
- Support for web clients: HTTP Polling and HTTP Binding (BOSH).
|
||||
- IRC transport.
|
||||
- Component support: interface with networks such as AIM, ICQ and MSN.
|
||||
|
||||
|
||||
@@ -112,8 +111,6 @@ To compile ejabberd you need:
|
||||
- OpenSSL 1.0.0 or higher, for STARTTLS, SASL and SSL encryption.
|
||||
- Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
|
||||
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
|
||||
- GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not
|
||||
needed on systems with GNU Libc.
|
||||
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
|
||||
|
||||
If your system splits packages in libraries and development headers, you must
|
||||
|
||||
@@ -94,9 +94,6 @@ defmodule Ejabberd.ConfigFile do
|
||||
module :mod_disco do
|
||||
end
|
||||
|
||||
module :mod_irc do
|
||||
end
|
||||
|
||||
module :mod_http_bind do
|
||||
end
|
||||
|
||||
|
||||
@@ -565,7 +565,6 @@ modules:
|
||||
mod_configure: {} # requires mod_adhoc
|
||||
mod_disco: {}
|
||||
## mod_echo: {}
|
||||
mod_irc: {}
|
||||
mod_http_bind: {}
|
||||
## mod_http_fileserver:
|
||||
## docroot: "/var/www"
|
||||
|
||||
+2
-4
@@ -197,12 +197,12 @@ AC_ARG_ENABLE(elixir,
|
||||
esac],[if test "x$elixir" = "x"; then elixir=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(iconv,
|
||||
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: yes)])],
|
||||
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: no)])],
|
||||
[case "${enableval}" in
|
||||
yes) iconv=true ;;
|
||||
no) iconv=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-iconv) ;;
|
||||
esac],[if test "x$iconv" = "x"; then iconv=true; fi])
|
||||
esac],[if test "x$iconv" = "x"; then iconv=false; fi])
|
||||
|
||||
AC_ARG_ENABLE(debug,
|
||||
[AC_HELP_STRING([--enable-debug], [enable debug information (default: yes)])],
|
||||
@@ -275,8 +275,6 @@ if test "$ENABLEGROUP" != ""; then
|
||||
AC_SUBST([INSTALLGROUP], [$ENABLEGROUP])
|
||||
fi
|
||||
|
||||
ERLANG_DEPRECATED_TYPES_CHECK
|
||||
|
||||
if test "$sqlite" = "true"; then
|
||||
AX_LIB_SQLITE3([3.6.19])
|
||||
if test "x$SQLITE3_VERSION" = "x"; then
|
||||
|
||||
@@ -13,6 +13,7 @@ ExecStart=/bin/sh -c '@ctlscriptpath@/ejabberdctl start && @ctlscriptpath@/ejabb
|
||||
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
|
||||
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
|
||||
PrivateDevices=true
|
||||
TimeoutSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
+24
-24
@@ -64,14 +64,6 @@ log_rotate_count: 1
|
||||
## 100 is ejabberd's default.
|
||||
log_rate_limit: 100
|
||||
|
||||
##
|
||||
## watchdog_admins: Only useful for developers: if an ejabberd process
|
||||
## consumes a lot of memory, send live notifications to these XMPP
|
||||
## accounts.
|
||||
##
|
||||
## watchdog_admins:
|
||||
## - "bob@example.com"
|
||||
|
||||
###. ===============
|
||||
###' NODE PARAMETERS
|
||||
|
||||
@@ -169,6 +161,20 @@ listen:
|
||||
max_stanza_size: 65536
|
||||
shaper: c2s_shaper
|
||||
access: c2s
|
||||
##
|
||||
## Direct-TLS for C2S (XEP-0368). A good practice is to forward
|
||||
## traffic from port 443 to this port, possibly multiplexing it
|
||||
## with HTTP using e.g. sslh [https://wiki.xmpp.org/web/Tech_pages/XEP-0368],
|
||||
## so modern clients can bypass restrictive firewalls (in airports, hotels, etc.).
|
||||
##
|
||||
## -
|
||||
## port: 5223
|
||||
## ip: "::"
|
||||
## module: ejabberd_c2s
|
||||
## tls: true
|
||||
## max_stanza_size: 65536
|
||||
## shaper: c2s_shaper
|
||||
## access: c2s
|
||||
-
|
||||
port: 5269
|
||||
ip: "::"
|
||||
@@ -185,20 +191,6 @@ listen:
|
||||
web_admin: true
|
||||
## register: true
|
||||
captcha: true
|
||||
##
|
||||
## Direct-TLS for C2S (XEP-0368). A good practice is to forward
|
||||
## traffic from port 443 to this port, possibly multiplexing it
|
||||
## with HTTP using e.g. sslh [https://wiki.xmpp.org/web/Tech_pages/XEP-0368],
|
||||
## so modern clients can bypass restrictive firewalls (in airports, hotels, etc.).
|
||||
##
|
||||
## -
|
||||
## port: 5223
|
||||
## ip: "::"
|
||||
## module: ejabberd_c2s
|
||||
## tls: true
|
||||
## max_stanza_size: 65536
|
||||
## shaper: c2s_shaper
|
||||
## access: c2s
|
||||
|
||||
##
|
||||
## ejabberd_service: Interact with external components (transports, ...)
|
||||
@@ -450,6 +442,14 @@ auth_method: internal
|
||||
##
|
||||
## new_sql_schema: true
|
||||
|
||||
##
|
||||
## A database can also can be used to store information from several
|
||||
## modules. To enable storage to the database, just make sure it is
|
||||
## setup above and set default_db: sql if you want to use SQL for
|
||||
## all modules.
|
||||
##
|
||||
## default_db: sql
|
||||
|
||||
###. ===============
|
||||
###' TRAFFIC SHAPERS
|
||||
|
||||
@@ -734,7 +734,6 @@ modules:
|
||||
## mod_delegation: {} # for xep0356
|
||||
mod_disco: {}
|
||||
mod_echo: {}
|
||||
mod_irc: {}
|
||||
mod_bosh: {}
|
||||
## mod_http_fileserver:
|
||||
## docroot: "/var/www"
|
||||
@@ -783,7 +782,8 @@ modules:
|
||||
- "pep" # pep requires mod_caps
|
||||
force_node_config:
|
||||
## Avoid using OMEMO by default because it
|
||||
## introduces a lot of hard-to-track problems
|
||||
## introduces a lot of hard-to-track problems.
|
||||
## Comment out the following lines to enable OMEMO support
|
||||
"eu.siacs.conversations.axolotl.*":
|
||||
access_model: whitelist
|
||||
## Avoid buggy clients to make their bookmarks public
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
# from a client or from another Jabber server. So take this into
|
||||
# account when setting this limit.
|
||||
#
|
||||
# Default: 32000
|
||||
# Default: 65536 (or 8196 on Windows)
|
||||
# Maximum: 268435456
|
||||
#
|
||||
#ERL_MAX_PORTS=32000
|
||||
#ERL_MAX_PORTS=65536
|
||||
|
||||
#.
|
||||
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
|
||||
@@ -85,10 +85,10 @@
|
||||
# Erlang, and therefore not related to the operating system processes, you do
|
||||
# not have to worry about allowing a huge number of them.
|
||||
#
|
||||
# Default: 250000
|
||||
# Default: 262144
|
||||
# Maximum: 268435456
|
||||
#
|
||||
#ERL_PROCESSES=250000
|
||||
#ERL_PROCESSES=262144
|
||||
|
||||
#.
|
||||
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
|
||||
@@ -99,9 +99,9 @@
|
||||
# You can safely increase this limit when starting ejabberd. It impacts memory
|
||||
# consumption but the difference will be quite small.
|
||||
#
|
||||
# Default: 1400
|
||||
# Default: 2053
|
||||
#
|
||||
#ERL_MAX_ETS_TABLES=1400
|
||||
#ERL_MAX_ETS_TABLES=2053
|
||||
|
||||
#.
|
||||
#' ERL_OPTIONS: Additional Erlang options
|
||||
|
||||
+9
-11
@@ -41,19 +41,17 @@ case $(id -un) in
|
||||
esac
|
||||
|
||||
# parse command line parameters
|
||||
for arg; do
|
||||
case $arg in
|
||||
-n|--node) ERLANG_NODE_ARG=$2; shift;;
|
||||
-s|--spool) SPOOL_DIR=$2; shift;;
|
||||
-l|--logs) LOGS_DIR=$2; shift;;
|
||||
-f|--config) EJABBERD_CONFIG_PATH=$2; shift;;
|
||||
-c|--ctl-config) EJABBERDCTL_CONFIG_PATH=$2; shift;;
|
||||
-d|--config-dir) ETC_DIR=$2; shift;;
|
||||
-t|--no-timeout) NO_TIMEOUT="--no-timeout";;
|
||||
--) :;;
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
-n|--node) ERLANG_NODE_ARG=$2; shift 2;;
|
||||
-s|--spool) SPOOL_DIR=$2; shift 2;;
|
||||
-l|--logs) LOGS_DIR=$2; shift 2;;
|
||||
-f|--config) EJABBERD_CONFIG_PATH=$2; shift 2;;
|
||||
-c|--ctl-config) EJABBERDCTL_CONFIG_PATH=$2; shift 2;;
|
||||
-d|--config-dir) ETC_DIR=$2; shift 2;;
|
||||
-t|--no-timeout) NO_TIMEOUT="--no-timeout"; shift;;
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# define ejabberd variables if not already defined from the command line
|
||||
|
||||
@@ -70,7 +70,7 @@ done
|
||||
echo '7. compile ejabberd'
|
||||
|
||||
gmake
|
||||
for A in mod_irc mod_muc mod_pubsub; do
|
||||
for A in mod_muc mod_pubsub; do
|
||||
(cd $A; gmake)
|
||||
done
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ override_acls.
|
||||
{mod_offline, []},
|
||||
{mod_echo, [{host, "echo.jabber.dbc.mtview.ca.us"}]},
|
||||
{mod_private, []},
|
||||
% {mod_irc, []},
|
||||
{mod_muc, []},
|
||||
{mod_pubsub, []},
|
||||
{mod_time, []},
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2018 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.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-ifndef(EJABBERD_HRL).
|
||||
-define(EJABBERD_HRL, true).
|
||||
|
||||
-define(VERSION, ejabberd_config:get_version()).
|
||||
|
||||
-define(MYHOSTS, ejabberd_config:get_myhosts()).
|
||||
|
||||
-define(MYNAME, hd(ejabberd_config:get_myhosts())).
|
||||
|
||||
-define(MYLANG, ejabberd_config:get_mylang()).
|
||||
|
||||
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
|
||||
|
||||
-define(SQL_DIR, filename:join(["priv", "sql"])).
|
||||
|
||||
-define(CONFIG_PATH, <<"ejabberd.yml">>).
|
||||
|
||||
-define(LOG_PATH, "ejabberd.log").
|
||||
|
||||
-define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>).
|
||||
|
||||
-define(COPYRIGHT, "Copyright (c) ProcessOne").
|
||||
|
||||
%%-define(DBGFSM, true).
|
||||
|
||||
-record(scram,
|
||||
{storedkey = <<"">>,
|
||||
serverkey = <<"">>,
|
||||
salt = <<"">>,
|
||||
iterationcount = 0 :: integer()}).
|
||||
|
||||
-type scram() :: #scram{}.
|
||||
|
||||
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
|
||||
|
||||
-ifdef(ERL_DEPRECATED_TYPES).
|
||||
|
||||
-define(TDICT, dict()).
|
||||
-define(TGB_TREE, gb_tree()).
|
||||
-define(TGB_SET, gb_set()).
|
||||
-define(TQUEUE, queue()).
|
||||
|
||||
-else.
|
||||
|
||||
-define(TDICT, dict:dict()).
|
||||
-define(TGB_TREE, gb_trees:tree()).
|
||||
-define(TGB_SET, gb_sets:set()).
|
||||
-define(TQUEUE, queue:queue()).
|
||||
|
||||
-endif.
|
||||
|
||||
-endif.
|
||||
@@ -31,7 +31,10 @@
|
||||
port = 5280 :: inet:port_number(),
|
||||
opts = [] :: list(),
|
||||
tp = http :: protocol(),
|
||||
headers = [] :: [{atom() | binary(), binary()}]}).
|
||||
headers = [] :: [{atom() | binary(), binary()}],
|
||||
length = 0 :: non_neg_integer(),
|
||||
sockmod :: gen_tcp | fast_tls,
|
||||
socket :: inet:socket() | fast_tls:tls_socket()}).
|
||||
|
||||
-record(ws,
|
||||
{socket :: inet:socket() | fast_tls:tls_socket(),
|
||||
@@ -46,6 +49,6 @@
|
||||
buf :: binary(),
|
||||
http_opts = [] :: list()}).
|
||||
|
||||
-type method() :: 'GET' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'PUT' | 'POST' | 'TRACE'.
|
||||
-type method() :: 'GET' | 'HEAD' | 'DELETE' | 'OPTIONS' | 'PUT' | 'POST' | 'TRACE' | 'PATCH'.
|
||||
-type protocol() :: http | https.
|
||||
-type http_request() :: #request{}.
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2018 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.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-include("ns.hrl").
|
||||
-include("fxml.hrl").
|
||||
|
||||
-define(STANZA_ERROR(Code, Type, Condition),
|
||||
#xmlel{name = <<"error">>,
|
||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
|
||||
children = []}]}).
|
||||
|
||||
-define(ERR_BAD_FORMAT,
|
||||
?STANZA_ERROR(<<"406">>, <<"modify">>,
|
||||
<<"bad-format">>)).
|
||||
|
||||
-define(ERR_BAD_REQUEST,
|
||||
?STANZA_ERROR(<<"400">>, <<"modify">>,
|
||||
<<"bad-request">>)).
|
||||
|
||||
-define(ERR_CONFLICT,
|
||||
?STANZA_ERROR(<<"409">>, <<"cancel">>, <<"conflict">>)).
|
||||
|
||||
-define(ERR_FEATURE_NOT_IMPLEMENTED,
|
||||
?STANZA_ERROR(<<"501">>, <<"cancel">>,
|
||||
<<"feature-not-implemented">>)).
|
||||
|
||||
-define(ERR_FORBIDDEN,
|
||||
?STANZA_ERROR(<<"403">>, <<"auth">>, <<"forbidden">>)).
|
||||
|
||||
-define(ERR_GONE,
|
||||
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"gone">>)).
|
||||
|
||||
-define(ERR_INTERNAL_SERVER_ERROR,
|
||||
?STANZA_ERROR(<<"500">>, <<"wait">>,
|
||||
<<"internal-server-error">>)).
|
||||
|
||||
-define(ERR_ITEM_NOT_FOUND,
|
||||
?STANZA_ERROR(<<"404">>, <<"cancel">>,
|
||||
<<"item-not-found">>)).
|
||||
|
||||
-define(ERR_JID_MALFORMED,
|
||||
?STANZA_ERROR(<<"400">>, <<"modify">>,
|
||||
<<"jid-malformed">>)).
|
||||
|
||||
-define(ERR_NOT_ACCEPTABLE,
|
||||
?STANZA_ERROR(<<"406">>, <<"modify">>,
|
||||
<<"not-acceptable">>)).
|
||||
|
||||
-define(ERR_NOT_ALLOWED,
|
||||
?STANZA_ERROR(<<"405">>, <<"cancel">>,
|
||||
<<"not-allowed">>)).
|
||||
|
||||
-define(ERR_NOT_AUTHORIZED,
|
||||
?STANZA_ERROR(<<"401">>, <<"auth">>,
|
||||
<<"not-authorized">>)).
|
||||
|
||||
-define(ERR_PAYMENT_REQUIRED,
|
||||
?STANZA_ERROR(<<"402">>, <<"auth">>,
|
||||
<<"payment-required">>)).
|
||||
|
||||
-define(ERR_RECIPIENT_UNAVAILABLE,
|
||||
?STANZA_ERROR(<<"404">>, <<"wait">>,
|
||||
<<"recipient-unavailable">>)).
|
||||
|
||||
-define(ERR_REDIRECT,
|
||||
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"redirect">>)).
|
||||
|
||||
-define(ERR_REGISTRATION_REQUIRED,
|
||||
?STANZA_ERROR(<<"407">>, <<"auth">>,
|
||||
<<"registration-required">>)).
|
||||
|
||||
-define(ERR_REMOTE_SERVER_NOT_FOUND,
|
||||
?STANZA_ERROR(<<"404">>, <<"cancel">>,
|
||||
<<"remote-server-not-found">>)).
|
||||
|
||||
-define(ERR_REMOTE_SERVER_TIMEOUT,
|
||||
?STANZA_ERROR(<<"504">>, <<"wait">>,
|
||||
<<"remote-server-timeout">>)).
|
||||
|
||||
-define(ERR_RESOURCE_CONSTRAINT,
|
||||
?STANZA_ERROR(<<"500">>, <<"wait">>,
|
||||
<<"resource-constraint">>)).
|
||||
|
||||
-define(ERR_SERVICE_UNAVAILABLE,
|
||||
?STANZA_ERROR(<<"503">>, <<"cancel">>,
|
||||
<<"service-unavailable">>)).
|
||||
|
||||
-define(ERR_SUBSCRIPTION_REQUIRED,
|
||||
?STANZA_ERROR(<<"407">>, <<"auth">>,
|
||||
<<"subscription-required">>)).
|
||||
|
||||
-define(ERR_UNEXPECTED_REQUEST,
|
||||
?STANZA_ERROR(<<"400">>, <<"wait">>,
|
||||
<<"unexpected-request">>)).
|
||||
|
||||
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
|
||||
?STANZA_ERROR(<<"401">>, <<"cancel">>,
|
||||
<<"unexpected-request">>)).
|
||||
|
||||
%-define(ERR_,
|
||||
% ?STANZA_ERROR("", "", "")).
|
||||
|
||||
-define(STANZA_ERRORT(Code, Type, Condition, Lang,
|
||||
Text),
|
||||
#xmlel{name = <<"error">>,
|
||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
|
||||
#xmlel{name = <<"text">>,
|
||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
|
||||
children =
|
||||
[{xmlcdata,
|
||||
translate:translate(Lang, Text)}]}]}).
|
||||
|
||||
-define(ERRT_BAD_FORMAT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"406">>, <<"modify">>,
|
||||
<<"bad-format">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_BAD_REQUEST(Lang, Text),
|
||||
?STANZA_ERRORT(<<"400">>, <<"modify">>,
|
||||
<<"bad-request">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_CONFLICT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"409">>, <<"cancel">>, <<"conflict">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"501">>, <<"cancel">>,
|
||||
<<"feature-not-implemented">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_FORBIDDEN(Lang, Text),
|
||||
?STANZA_ERRORT(<<"403">>, <<"auth">>, <<"forbidden">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_GONE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"gone">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
||||
?STANZA_ERRORT(<<"500">>, <<"wait">>,
|
||||
<<"internal-server-error">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_ITEM_NOT_FOUND(Lang, Text),
|
||||
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
|
||||
<<"item-not-found">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_JID_MALFORMED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"400">>, <<"modify">>,
|
||||
<<"jid-malformed">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_NOT_ACCEPTABLE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"406">>, <<"modify">>,
|
||||
<<"not-acceptable">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_NOT_ALLOWED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"405">>, <<"cancel">>,
|
||||
<<"not-allowed">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_NOT_AUTHORIZED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"401">>, <<"auth">>,
|
||||
<<"not-authorized">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_PAYMENT_REQUIRED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"402">>, <<"auth">>,
|
||||
<<"payment-required">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_RECIPIENT_UNAVAILABLE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"404">>, <<"wait">>,
|
||||
<<"recipient-unavailable">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_REDIRECT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"redirect">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(ERRT_REGISTRATION_REQUIRED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"407">>, <<"auth">>,
|
||||
<<"registration-required">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_REMOTE_SERVER_NOT_FOUND(Lang, Text),
|
||||
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
|
||||
<<"remote-server-not-found">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_REMOTE_SERVER_TIMEOUT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"504">>, <<"wait">>,
|
||||
<<"remote-server-timeout">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_RESOURCE_CONSTRAINT(Lang, Text),
|
||||
?STANZA_ERRORT(<<"500">>, <<"wait">>,
|
||||
<<"resource-constraint">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_SERVICE_UNAVAILABLE(Lang, Text),
|
||||
?STANZA_ERRORT(<<"503">>, <<"cancel">>,
|
||||
<<"service-unavailable">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_SUBSCRIPTION_REQUIRED(Lang, Text),
|
||||
?STANZA_ERRORT(<<"407">>, <<"auth">>,
|
||||
<<"subscription-required">>, Lang, Text)).
|
||||
|
||||
-define(ERRT_UNEXPECTED_REQUEST(Lang, Text),
|
||||
?STANZA_ERRORT(<<"400">>, <<"wait">>,
|
||||
<<"unexpected-request">>, Lang, Text)).
|
||||
|
||||
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
|
||||
?ERRT_NOT_ACCEPTABLE(Lang, <<"No resource provided">>)).
|
||||
|
||||
-define(ERR_AUTH_BAD_RESOURCE_FORMAT(Lang),
|
||||
?ERRT_NOT_ACCEPTABLE(Lang,
|
||||
<<"Illegal resource format">>)).
|
||||
|
||||
-define(ERR_AUTH_RESOURCE_CONFLICT(Lang),
|
||||
?ERRT_CONFLICT(Lang, <<"Resource conflict">>)).
|
||||
|
||||
-define(STREAM_ERROR(Condition, Cdata),
|
||||
#xmlel{name = <<"stream:error">>, attrs = [],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
|
||||
children = [{xmlcdata, Cdata}]}]}).
|
||||
|
||||
-define(SERR_BAD_FORMAT,
|
||||
?STREAM_ERROR(<<"bad-format">>, <<"">>)).
|
||||
|
||||
-define(SERR_BAD_NAMESPACE_PREFIX,
|
||||
?STREAM_ERROR(<<"bad-namespace-prefix">>, <<"">>)).
|
||||
|
||||
-define(SERR_CONFLICT,
|
||||
?STREAM_ERROR(<<"conflict">>, <<"">>)).
|
||||
|
||||
-define(SERR_CONNECTION_TIMEOUT,
|
||||
?STREAM_ERROR(<<"connection-timeout">>, <<"">>)).
|
||||
|
||||
-define(SERR_HOST_GONE,
|
||||
?STREAM_ERROR(<<"host-gone">>, <<"">>)).
|
||||
|
||||
-define(SERR_HOST_UNKNOWN,
|
||||
?STREAM_ERROR(<<"host-unknown">>, <<"">>)).
|
||||
|
||||
-define(SERR_IMPROPER_ADDRESSING,
|
||||
?STREAM_ERROR(<<"improper-addressing">>, <<"">>)).
|
||||
|
||||
-define(SERR_INTERNAL_SERVER_ERROR,
|
||||
?STREAM_ERROR(<<"internal-server-error">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_FROM,
|
||||
?STREAM_ERROR(<<"invalid-from">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_ID,
|
||||
?STREAM_ERROR(<<"invalid-id">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_NAMESPACE,
|
||||
?STREAM_ERROR(<<"invalid-namespace">>, <<"">>)).
|
||||
|
||||
-define(SERR_INVALID_XML,
|
||||
?STREAM_ERROR(<<"invalid-xml">>, <<"">>)).
|
||||
|
||||
-define(SERR_NOT_AUTHORIZED,
|
||||
?STREAM_ERROR(<<"not-authorized">>, <<"">>)).
|
||||
|
||||
-define(SERR_POLICY_VIOLATION,
|
||||
?STREAM_ERROR(<<"policy-violation">>, <<"">>)).
|
||||
|
||||
-define(SERR_REMOTE_CONNECTION_FAILED,
|
||||
?STREAM_ERROR(<<"remote-connection-failed">>, <<"">>)).
|
||||
|
||||
-define(SERR_RESOURSE_CONSTRAINT,
|
||||
?STREAM_ERROR(<<"resource-constraint">>, <<"">>)).
|
||||
|
||||
-define(SERR_RESTRICTED_XML,
|
||||
?STREAM_ERROR(<<"restricted-xml">>, <<"">>)).
|
||||
|
||||
-define(SERR_SEE_OTHER_HOST(Host),
|
||||
?STREAM_ERROR(<<"see-other-host">>, Host)).
|
||||
|
||||
-define(SERR_SYSTEM_SHUTDOWN,
|
||||
?STREAM_ERROR(<<"system-shutdown">>, <<"">>)).
|
||||
|
||||
-define(SERR_UNSUPPORTED_ENCODING,
|
||||
?STREAM_ERROR(<<"unsupported-encoding">>, <<"">>)).
|
||||
|
||||
-define(SERR_UNSUPPORTED_STANZA_TYPE,
|
||||
?STREAM_ERROR(<<"unsupported-stanza-type">>, <<"">>)).
|
||||
|
||||
-define(SERR_UNSUPPORTED_VERSION,
|
||||
?STREAM_ERROR(<<"unsupported-version">>, <<"">>)).
|
||||
|
||||
-define(SERR_XML_NOT_WELL_FORMED,
|
||||
?STREAM_ERROR(<<"xml-not-well-formed">>, <<"">>)).
|
||||
|
||||
%-define(SERR_,
|
||||
% ?STREAM_ERROR("", "")).
|
||||
|
||||
-define(STREAM_ERRORT(Condition, Cdata, Lang, Text),
|
||||
#xmlel{name = <<"stream:error">>, attrs = [],
|
||||
children =
|
||||
[#xmlel{name = Condition,
|
||||
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
|
||||
children = [{xmlcdata, Cdata}]},
|
||||
#xmlel{name = <<"text">>,
|
||||
attrs =
|
||||
[{<<"xml:lang">>, Lang},
|
||||
{<<"xmlns">>, ?NS_STREAMS}],
|
||||
children =
|
||||
[{xmlcdata,
|
||||
translate:translate(Lang, Text)}]}]}).
|
||||
|
||||
-define(SERRT_BAD_FORMAT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"bad-format">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
|
||||
?STREAM_ERRORT(<<"bad-namespace-prefix">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_CONFLICT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"conflict">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"connection-timeout">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_HOST_GONE(Lang, Text),
|
||||
?STREAM_ERRORT(<<"host-gone">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_HOST_UNKNOWN(Lang, Text),
|
||||
?STREAM_ERRORT(<<"host-unknown">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
|
||||
?STREAM_ERRORT(<<"improper-addressing">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
||||
?STREAM_ERRORT(<<"internal-server-error">>, <<"">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(SERRT_INVALID_FROM(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-from">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_INVALID_ID(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-id">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-namespace">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_INVALID_XML(Lang, Text),
|
||||
?STREAM_ERRORT(<<"invalid-xml">>, <<"">>, Lang, Text)).
|
||||
|
||||
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
|
||||
?STREAM_ERRORT(<<"not-authorized">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_POLICY_VIOLATION(Lang, Text),
|
||||
?STREAM_ERRORT(<<"policy-violation">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
|
||||
?STREAM_ERRORT(<<"remote-connection-failed">>, <<"">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
|
||||
?STREAM_ERRORT(<<"resource-constraint">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_RESTRICTED_XML(Lang, Text),
|
||||
?STREAM_ERRORT(<<"restricted-xml">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_SEE_OTHER_HOST(Host, Lang, Text),
|
||||
?STREAM_ERRORT(<<"see-other-host">>, Host, Lang, Text)).
|
||||
|
||||
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
|
||||
?STREAM_ERRORT(<<"system-shutdown">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
|
||||
?STREAM_ERRORT(<<"unsupported-encoding">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
|
||||
?STREAM_ERRORT(<<"unsupported-stanza-type">>, <<"">>,
|
||||
Lang, Text)).
|
||||
|
||||
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
|
||||
?STREAM_ERRORT(<<"unsupported-version">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
|
||||
?STREAM_ERRORT(<<"xml-not-well-formed">>, <<"">>, Lang,
|
||||
Text)).
|
||||
|
||||
-record(jid, {user = <<"">> :: binary(),
|
||||
server = <<"">> :: binary(),
|
||||
resource = <<"">> :: binary(),
|
||||
luser = <<"">> :: binary(),
|
||||
lserver = <<"">> :: binary(),
|
||||
lresource = <<"">> :: binary()}).
|
||||
|
||||
-type(jid() :: #jid{}).
|
||||
|
||||
-type(ljid() :: {binary(), binary(), binary()}).
|
||||
|
||||
-record(iq, {id = <<"">> :: binary(),
|
||||
type = get :: get | set | result | error,
|
||||
xmlns = <<"">> :: binary(),
|
||||
lang = <<"">> :: binary(),
|
||||
sub_el = #xmlel{} :: xmlel() | [xmlel()]}).
|
||||
|
||||
-type(iq_get()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: get,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: xmlel()
|
||||
}
|
||||
).
|
||||
|
||||
-type(iq_set()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: set,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: xmlel()
|
||||
}
|
||||
).
|
||||
|
||||
-type iq_request() :: iq_get() | iq_set().
|
||||
|
||||
-type(iq_result()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: result,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: [xmlel()]
|
||||
}
|
||||
).
|
||||
|
||||
-type(iq_error()
|
||||
:: #iq{
|
||||
id :: binary(),
|
||||
type :: error,
|
||||
xmlns :: binary(),
|
||||
lang :: binary(),
|
||||
sub_el :: [xmlel()]
|
||||
}
|
||||
).
|
||||
|
||||
-type iq_reply() :: iq_result() | iq_error() .
|
||||
|
||||
-type(iq() :: iq_request() | iq_reply()).
|
||||
|
||||
-record(rsm_in, {max :: integer() | error | undefined,
|
||||
direction :: before | aft | undefined,
|
||||
id :: binary() | undefined,
|
||||
index :: integer() | error | undefined}).
|
||||
|
||||
-record(rsm_out, {count :: integer() | undefined,
|
||||
index :: integer() | undefined,
|
||||
first :: binary() | undefined,
|
||||
last :: binary() | undefined}).
|
||||
|
||||
-type(rsm_in() :: #rsm_in{}).
|
||||
|
||||
-type(rsm_out() :: #rsm_out{}).
|
||||
|
||||
-type broadcast() :: {broadcast, broadcast_data()}.
|
||||
|
||||
-type broadcast_data() ::
|
||||
{rebind, pid(), binary()} | %% ejabberd_c2s
|
||||
{item, ljid(), mod_roster:subscription()} | %% mod_roster/mod_shared_roster
|
||||
{exit, binary()} | %% mod_roster/mod_shared_roster
|
||||
{privacy_list, mod_privacy:userlist(), binary()} | %% mod_privacy
|
||||
{blocking, unblock_all | {block | unblock, [ljid()]}}. %% mod_blocking
|
||||
|
||||
-record(xmlelement, {name = "" :: string(),
|
||||
attrs = [] :: [{string(), string()}],
|
||||
children = [] :: [{xmlcdata, iodata()} | xmlelement()]}).
|
||||
|
||||
-type xmlelement() :: #xmlelement{}.
|
||||
@@ -42,3 +42,6 @@
|
||||
false -> ok;
|
||||
_ -> 'Elixir.Logger':bare_log(error, io_lib:format(Format, Args), [?MODULE])
|
||||
end).
|
||||
|
||||
%% Uncomment if you want to debug p1_fsm/gen_fsm
|
||||
%%-define(DBGFSM, true).
|
||||
|
||||
+10
-10
@@ -18,8 +18,6 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
-define(MAX_USERS_DEFAULT, 200).
|
||||
|
||||
-define(SETS, gb_sets).
|
||||
@@ -63,9 +61,11 @@
|
||||
max_users = ?MAX_USERS_DEFAULT :: non_neg_integer() | none,
|
||||
logging = false :: boolean(),
|
||||
vcard = <<"">> :: binary(),
|
||||
captcha_whitelist = (?SETS):empty() :: ?TGB_SET,
|
||||
vcard_xupdate = undefined :: undefined | external | binary(),
|
||||
captcha_whitelist = (?SETS):empty() :: gb_sets:set(),
|
||||
mam = false :: boolean(),
|
||||
pubsub = <<"">> :: binary()
|
||||
pubsub = <<"">> :: binary(),
|
||||
lang = ejabberd_config:get_mylang() :: binary()
|
||||
}).
|
||||
|
||||
-type config() :: #config{}.
|
||||
@@ -105,13 +105,13 @@
|
||||
access = {none,none,none,none} :: {atom(), atom(), atom(), atom()},
|
||||
jid = #jid{} :: jid(),
|
||||
config = #config{} :: config(),
|
||||
users = (?DICT):new() :: ?TDICT,
|
||||
subscribers = (?DICT):new() :: ?TDICT,
|
||||
subscriber_nicks = (?DICT):new() :: ?TDICT,
|
||||
users = (?DICT):new() :: dict:dict(),
|
||||
subscribers = (?DICT):new() :: dict:dict(),
|
||||
subscriber_nicks = (?DICT):new() :: dict:dict(),
|
||||
last_voice_request_time = treap:empty() :: treap:treap(),
|
||||
robots = (?DICT):new() :: ?TDICT,
|
||||
nicks = (?DICT):new() :: ?TDICT,
|
||||
affiliations = (?DICT):new() :: ?TDICT,
|
||||
robots = (?DICT):new() :: dict:dict(),
|
||||
nicks = (?DICT):new() :: dict:dict(),
|
||||
affiliations = (?DICT):new() :: dict:dict(),
|
||||
history :: lqueue(),
|
||||
subject = [] :: [text()],
|
||||
subject_author = <<"">> :: binary(),
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
%% -------------------------------
|
||||
%% Pubsub constants
|
||||
-define(ERR_EXTENDED(E, C), mod_pubsub:extended_error(E, C)).
|
||||
|
||||
@@ -18,18 +18,11 @@
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-type conn_param() :: {binary(), binary(), inet:port_number(), binary()} |
|
||||
{binary(), binary(), inet:port_number()} |
|
||||
{binary(), binary()} |
|
||||
{binary()}.
|
||||
-record(scram, {storedkey = <<"">> :: binary(),
|
||||
serverkey = <<"">> :: binary(),
|
||||
salt = <<"">> :: binary(),
|
||||
iterationcount = 0 :: integer()}).
|
||||
|
||||
-type irc_data() :: [{username, binary()} | {connections_params, [conn_param()]}].
|
||||
-type scram() :: #scram{}.
|
||||
|
||||
-record(irc_connection,
|
||||
{jid_server_host = {#jid{}, <<"">>, <<"">>} :: {jid(), binary(), binary()},
|
||||
pid = self() :: pid()}).
|
||||
|
||||
-record(irc_custom,
|
||||
{us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()},
|
||||
binary()},
|
||||
data = [] :: irc_data()}).
|
||||
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
|
||||
@@ -84,20 +84,3 @@ EOF
|
||||
AC_MSG_RESULT([ok])
|
||||
fi
|
||||
]) dnl ERLANG_VERSION_CHECK
|
||||
|
||||
AC_DEFUN([ERLANG_DEPRECATED_TYPES_CHECK],
|
||||
[ AC_MSG_CHECKING([whether Erlang is using deprecated types])
|
||||
cat > conftest.erl <<EOF
|
||||
-module(conftest).
|
||||
|
||||
-record(state, {host = dict:new() :: dict:dict()}).
|
||||
EOF
|
||||
|
||||
if $ERLC conftest.erl > /dev/null 2>&1; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_SUBST(erlang_deprecated_types, false)
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_SUBST(erlang_deprecated_types, true)
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
|
||||
|
||||
def project do
|
||||
[app: :ejabberd,
|
||||
version: "18.3.0",
|
||||
version: "18.6.0",
|
||||
description: description(),
|
||||
elixir: "~> 1.4",
|
||||
elixirc_paths: ["lib"],
|
||||
@@ -61,7 +61,7 @@ defmodule Ejabberd.Mixfile do
|
||||
[{:lager, "~> 3.4.0"},
|
||||
{:p1_utils, "~> 1.0"},
|
||||
{:fast_xml, "~> 1.1"},
|
||||
{:xmpp, "~> 1.1"},
|
||||
{:xmpp, "~> 1.2"},
|
||||
{:cache_tab, "~> 1.0"},
|
||||
{:stringprep, "~> 1.0"},
|
||||
{:fast_yaml, "~> 1.0"},
|
||||
@@ -125,7 +125,7 @@ defmodule Ejabberd.Mixfile do
|
||||
defp vars do
|
||||
case :file.consult("vars.config") do
|
||||
{:ok,config} -> config
|
||||
_ -> [zlib: true, iconv: true]
|
||||
_ -> [zlib: true, iconv: false]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
%{
|
||||
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
|
||||
"cache_tab": {:hex, :cache_tab, "1.0.13", "e09857af9b7ba89428227d3801256852cb0d51a4de47e4edcb160d96cc96f8eb", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"distillery": {:hex, :distillery, "1.5.2", "eec18b2d37b55b0bcb670cf2bcf64228ed38ce8b046bb30a9b636a6f5a4c0080", [:mix], [], "hexpm"},
|
||||
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"},
|
||||
"eimp": {:hex, :eimp, "1.0.3", "e40108d622d672cf6003d279d98fc46a98df182dbe8756857896ffd28883090d", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"cache_tab": {:hex, :cache_tab, "1.0.14", "e68d24789ff596a7cb4f08780f72a725f3f18e93dee486559b261df904234871", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"distillery": {:hex, :distillery, "1.5.3", "b2f4fc34ec71ab4f1202a796f9290e068883b042319aa8c9aa45377ecac8597a", [:mix], [], "hexpm"},
|
||||
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"},
|
||||
"eimp": {:hex, :eimp, "1.0.6", "087fc92daf7b03bac4aada8ea6063d9034d4b9088be24e050ff73323c8444a04", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"epam": {:hex, :epam, "1.0.4", "2a5e40cbf9b2cf41df515782894c3b33c81b8ad32fff2fc847c3f725071dfaed", [:rebar3], [], "hexpm"},
|
||||
"eredis": {:hex, :eredis, "1.1.0", "8d8d74496f35216679b97726b75fb1c8715e99dd7f3ef9f9824a2264c3e0aac0", [:rebar3], [], "hexpm"},
|
||||
"esip": {:hex, :esip, "1.0.22", "3e387312614762fb84d3f77ba4f17650faf52510482521300b3d98ecdcbec21d", [:rebar3], [{:fast_tls, "1.0.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.21", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"esip": {:hex, :esip, "1.0.24", "c14efd0817012721dad3d1c36816e4d113adc86d185503f8c08f7faa11082018", [:rebar3], [{:fast_tls, "1.0.23", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.23", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"ezlib": {:hex, :ezlib, "1.0.4", "2434e4bb549cb060d5ac02261ba48fbe1a69b2ae4e1bf7485a3b27b3f3ec618d", [:rebar3], [], "hexpm"},
|
||||
"fast_tls": {:hex, :fast_tls, "1.0.21", "7005fe030c0472643314c9c31e7627bb296dcb96a9ce0b5dd8ccb34273f4c1ff", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"fast_xml": {:hex, :fast_xml, "1.1.29", "c6356d28f0f76ffefc68b5eb65916f0b8ca513bab71db8ad95bd8577c47e30e2", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"fast_yaml": {:hex, :fast_yaml, "1.0.13", "adcb8db20bb96d4e56b63b48c75d47ca15a6bd409da0200ffbd32db382131e22", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"fast_tls": {:hex, :fast_tls, "1.0.23", "5fd44b84b60f1caeb82270aae842599997e2ef70a628c954e494a6613cc6f026", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"fast_xml": {:hex, :fast_xml, "1.1.31", "7d85dd50533737adbaa95472c962ff8ad3d434ced1dbd04b83465edc2a4363b6", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"fast_yaml": {:hex, :fast_yaml, "1.0.15", "55a8ff117e2bb44fda5ca96c53473799f864c865dc63a3b598cb626001207cab", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"},
|
||||
"hamcrest": {:hex, :basho_hamcrest, "0.4.1", "fb7b2c92d252a1e9db936750b86089addaebeb8f87967fb4bbdda61e8863338e", [:make, :mix, :rebar3], [], "hexpm"},
|
||||
"iconv": {:hex, :iconv, "1.0.7", "f81eb6b8c977b1fd078515937fdce64292d64c6102353fbbfe57db580f4689d1", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"iconv": {:hex, :iconv, "1.0.8", "772a19153e9546b9f17206931ece321220feccfd0b3f5a5509dc92108326c2f9", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"jiffy": {:hex, :jiffy, "0.14.13", "225a9a35e26417832c611526567194b4d3adc4f0dfa5f2f7008f4684076f2a01", [:rebar3], [], "hexpm"},
|
||||
"jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"lager": {:hex, :lager, "3.4.2", "150b9a17b23ae6d3265cc10dc360747621cf217b7a22b8cddf03b2909dbf7aa5", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"luerl": {:hex, :luerl, "0.3.1", "5412807630aac1aaf59ffe5a1bc09259c447b4faeb1d3fe2d4ef41b87676cb04", [:rebar3], [], "hexpm"},
|
||||
"meck": {:hex, :meck, "0.8.9", "64c5c0bd8bcca3a180b44196265c8ed7594e16bcc845d0698ec6b4e577f48188", [:rebar3], [], "hexpm"},
|
||||
"meck": {:hex, :meck, "0.8.10", "455aaef8403be46752272206613e7a15467c014d40994b22fb54cde4d1ff7075", [:rebar3], [], "hexpm"},
|
||||
"moka": {:git, "https://github.com/processone/moka.git", "3eed3a6dd7dedb70a6cd18f86c7561a18626eb3b", [tag: "1.0.5c"]},
|
||||
"p1_mysql": {:hex, :p1_mysql, "1.0.5", "2a9644d27050a6aa9e7eb70a0620043f93655212b15f3620dc12f2fbd1a8c43a", [:rebar3], [], "hexpm"},
|
||||
"p1_oauth2": {:hex, :p1_oauth2, "0.6.2", "cc381038920e3d34ef32aa10ba7eb637bdff38a946748c4fd99329ff484a3889", [:rebar3], [], "hexpm"},
|
||||
"p1_pgsql": {:hex, :p1_pgsql, "1.1.5", "1e1bef6e6d906e10552a608b9fe5ef39b3099caf0f44c07d3d9e18ac4dee34d1", [:rebar3], [], "hexpm"},
|
||||
"p1_utils": {:hex, :p1_utils, "1.0.11", "a471f80644d4b464fa67572affddda7e95df5d4b099624b8907f5726e8a1769c", [:rebar3], [], "hexpm"},
|
||||
"p1_mysql": {:hex, :p1_mysql, "1.0.6", "1fb48a907a7fe214a78be15a08f8ebfae2db424c4d9886891a298a395cc3afce", [:rebar3], [], "hexpm"},
|
||||
"p1_oauth2": {:hex, :p1_oauth2, "0.6.3", "fbd91ba86bd7f03d2a4f6e62affa86bab9930abfd6b473d61eefb148f246cd46", [:rebar3], [], "hexpm"},
|
||||
"p1_pgsql": {:hex, :p1_pgsql, "1.1.6", "631004602b06ca6f55d759001f180185685c7097e583f3b0f7dd9b8e05ba5db1", [:rebar3], [], "hexpm"},
|
||||
"p1_utils": {:hex, :p1_utils, "1.0.12", "4304223a2b78d8031e980ae18d6b6d83f764cf2a91c779b2df7cbdfde73acbf8", [:rebar3], [], "hexpm"},
|
||||
"riak_pb": {:hex, :riak_pb, "2.3.2", "48ffbf66dbb3f136ab9a7134bac4e496754baa5ef58c4f50a61326736d996390", [:make, :mix, :rebar3], [{:hamcrest, "~> 0.4.1", [hex: :basho_hamcrest, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"riakc": {:hex, :riakc, "2.5.3", "6132d9e687a0dfd314b2b24c4594302ca8b55568a5d733c491d8fb6cd4004763", [:make, :mix, :rebar3], [{:riak_pb, "~> 2.3", [hex: :riak_pb, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"samerlib": {:git, "https://github.com/processone/samerlib", "fbbba035b1548ac4e681df00d61bf609645333a0", [tag: "0.8.0c"]},
|
||||
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"},
|
||||
"stringprep": {:hex, :stringprep, "1.0.11", "002e6972ab36c35f3dd88c11725014e62608c45a00399c083681879973fa8026", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"stun": {:hex, :stun, "1.0.21", "087fb20497081927690ef9d70b5bd6f9f4bea256ad758c500842722c0b6bb6ab", [:rebar3], [{:fast_tls, "1.0.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"xmpp": {:hex, :xmpp, "1.1.20", "33ddcc698518061f5051b98a6f731eef9342799f0c276a9debdfffe85c32fe6d", [:rebar3], [{:fast_xml, "1.1.29", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.11", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"stringprep": {:hex, :stringprep, "1.0.12", "3364897b9a376b2fb5e429944fd34ca0b562b44c9e5acf4e0299564371a6fbef", [:rebar3], [{:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"stun": {:hex, :stun, "1.0.23", "79982f6a26dc65b58bb24082e8bbfba83a5228ddd6407753e9c3092fb45ba916", [:rebar3], [{:fast_tls, "1.0.23", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
"xmpp": {:hex, :xmpp, "1.2.1", "9c94ab556559dc6c3bf4963f756a02e9771dd220f5891d57fc30b76c3d71cb06", [:rebar3], [{:fast_xml, "1.1.31", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.12", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.12", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
|
||||
}
|
||||
|
||||
+1707
-1251
File diff suppressed because it is too large
Load Diff
+15
-19
@@ -20,23 +20,23 @@
|
||||
|
||||
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager",
|
||||
{tag, {if_version_above, "17", "3.4.2", "3.2.1"}}}},
|
||||
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.11"}}},
|
||||
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.13"}}},
|
||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.21"}}},
|
||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.11"}}},
|
||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.29"}}},
|
||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.20"}}},
|
||||
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.13"}}},
|
||||
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.12"}}},
|
||||
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.14"}}},
|
||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.23"}}},
|
||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.12"}}},
|
||||
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.31"}}},
|
||||
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.2.1"}}},
|
||||
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.15"}}},
|
||||
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
|
||||
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.2"}}},
|
||||
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}},
|
||||
{jose, ".*", {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.8.4"}}},
|
||||
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.3"}}},
|
||||
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.21"}}}},
|
||||
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.22"}}}},
|
||||
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.6"}}},
|
||||
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.23"}}}},
|
||||
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.24"}}}},
|
||||
{if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
|
||||
{tag, "1.0.5"}}}},
|
||||
{tag, "1.0.6"}}}},
|
||||
{if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
|
||||
{tag, "1.1.5"}}}},
|
||||
{tag, "1.1.6"}}}},
|
||||
{if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
|
||||
{tag, "1.1.6"}}}},
|
||||
{if_var_true, pam, {epam, ".*", {git, "https://github.com/processone/epam",
|
||||
@@ -52,13 +52,13 @@
|
||||
{if_not_rebar3, {if_var_true, elixir, {rebar_elixir_plugin, ".*",
|
||||
{git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}},
|
||||
{if_var_true, iconv, {iconv, ".*", {git, "https://github.com/processone/iconv",
|
||||
{tag, "1.0.7"}}}},
|
||||
{tag, "1.0.8"}}}},
|
||||
{if_var_true, tools, {luerl, ".*", {git, "https://github.com/rvirding/luerl",
|
||||
{tag, "v0.3"}}}},
|
||||
{if_var_true, tools, {meck, "0.8.*", {git, "https://github.com/eproxus/meck",
|
||||
{tag, "0.8.4"}}}},
|
||||
{if_var_true, tools, {moka, ".*", {git, "https://github.com/processone/moka",
|
||||
{tag, "1.0.5c"}}}},
|
||||
{tag, "1.0.5d"}}}},
|
||||
{if_var_true, redis, {eredis, ".*", {git, "https://github.com/wooga/eredis",
|
||||
{tag, "v1.0.8"}}}}]}.
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
|
||||
{if_var_match, db_type, mssql, {d, 'mssql'}},
|
||||
{if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},
|
||||
{if_var_true, erlang_deprecated_types, {d, 'ERL_DEPRECATED_TYPES'}},
|
||||
{if_have_fun, {crypto, strong_rand_bytes, 1}, {d, 'STRONG_RAND_BYTES'}},
|
||||
{if_have_fun, {rand, uniform, 1}, {d, 'RAND_UNIFORM'}},
|
||||
{if_have_fun, {gb_sets, iterator_from, 2}, {d, 'GB_SETS_ITERATOR_FROM'}},
|
||||
@@ -165,9 +164,6 @@
|
||||
{if_var_true, zlib, {"ezlib", []}},
|
||||
{if_var_true, iconv, {"iconv", []}}]}.
|
||||
|
||||
{port_env, [{"CFLAGS", "-g -O2 -Wall"}]}.
|
||||
|
||||
{port_specs, [{"priv/lib/jid.so", ["c_src/jid.c"]}]}.
|
||||
%% Local Variables:
|
||||
%% mode: erlang
|
||||
%% End:
|
||||
|
||||
+2
-12
@@ -259,8 +259,8 @@ CREATE TABLE pubsub_item (
|
||||
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
|
||||
itemid text NOT NULL,
|
||||
publisher text NOT NULL,
|
||||
creation text NOT NULL,
|
||||
modification text NOT NULL,
|
||||
creation varchar(32) NOT NULL,
|
||||
modification varchar(32) NOT NULL,
|
||||
payload text NOT NULL DEFAULT ''
|
||||
);
|
||||
CREATE INDEX i_pubsub_item_itemid ON pubsub_item (itemid);
|
||||
@@ -329,16 +329,6 @@ CREATE TABLE muc_room_subscribers (
|
||||
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers(host, jid);
|
||||
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers(host, room, jid);
|
||||
|
||||
CREATE TABLE irc_custom (
|
||||
jid text NOT NULL,
|
||||
host text NOT NULL,
|
||||
server_host text NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom (jid, host);
|
||||
|
||||
CREATE TABLE motd (
|
||||
username text NOT NULL,
|
||||
server_host text NOT NULL,
|
||||
|
||||
+2
-11
@@ -236,8 +236,8 @@ CREATE TABLE pubsub_item (
|
||||
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
|
||||
itemid text NOT NULL,
|
||||
publisher text NOT NULL,
|
||||
creation text NOT NULL,
|
||||
modification text NOT NULL,
|
||||
creation varchar(32) NOT NULL,
|
||||
modification varchar(32) NOT NULL,
|
||||
payload text NOT NULL DEFAULT ''
|
||||
);
|
||||
CREATE INDEX i_pubsub_item_itemid ON pubsub_item (itemid);
|
||||
@@ -302,15 +302,6 @@ CREATE TABLE muc_room_subscribers (
|
||||
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers(host, jid);
|
||||
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers(host, room, jid);
|
||||
|
||||
CREATE TABLE irc_custom (
|
||||
jid text NOT NULL,
|
||||
host text NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom (jid, host);
|
||||
|
||||
CREATE TABLE motd (
|
||||
username text PRIMARY KEY,
|
||||
xml text,
|
||||
|
||||
+2
-12
@@ -72,16 +72,6 @@ CREATE TABLE [dbo].[caps_features] (
|
||||
CREATE CLUSTERED INDEX [caps_features_node_subnode] ON [caps_features] (node, subnode)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
||||
|
||||
CREATE TABLE [dbo].[irc_custom] (
|
||||
[jid] [varchar] (255) NOT NULL,
|
||||
[host] [varchar] (255) NOT NULL,
|
||||
[data] [text] NOT NULL,
|
||||
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
|
||||
) TEXTIMAGE_ON [PRIMARY];
|
||||
|
||||
CREATE UNIQUE CLUSTERED INDEX [irc_custom_jid_host] ON [irc_custom] (jid, host)
|
||||
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
|
||||
|
||||
CREATE TABLE [dbo].[last] (
|
||||
[username] [varchar] (250) NOT NULL,
|
||||
[seconds] [text] NOT NULL,
|
||||
@@ -220,8 +210,8 @@ CREATE TABLE [dbo].[pubsub_item] (
|
||||
[nodeid] [bigint] NULL,
|
||||
[itemid] [varchar] (255) NOT NULL,
|
||||
[publisher] [text] NOT NULL,
|
||||
[creation] [text] NOT NULL,
|
||||
[modification] [varchar] (255) NOT NULL,
|
||||
[creation] [varchar] (32) NOT NULL,
|
||||
[modification] [varchar] (32) NOT NULL,
|
||||
[payload] [text] NOT NULL DEFAULT ''
|
||||
) TEXTIMAGE_ON [PRIMARY];
|
||||
|
||||
|
||||
+2
-12
@@ -274,8 +274,8 @@ CREATE TABLE pubsub_item (
|
||||
nodeid bigint,
|
||||
itemid text NOT NULL,
|
||||
publisher text NOT NULL,
|
||||
creation text NOT NULL,
|
||||
modification text NOT NULL,
|
||||
creation varchar(32) NOT NULL,
|
||||
modification varchar(32) NOT NULL,
|
||||
payload text NOT NULL
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE INDEX i_pubsub_item_itemid ON pubsub_item(itemid(36));
|
||||
@@ -345,16 +345,6 @@ CREATE TABLE muc_room_subscribers (
|
||||
|
||||
CREATE INDEX i_muc_room_subscribers_host_jid USING BTREE ON muc_room_subscribers(host, jid);
|
||||
|
||||
CREATE TABLE irc_custom (
|
||||
jid text NOT NULL,
|
||||
host text NOT NULL,
|
||||
server_host text NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE UNIQUE INDEX i_irc_custom_jid_host USING BTREE ON irc_custom(jid(75), host(75));
|
||||
|
||||
CREATE TABLE motd (
|
||||
username varchar(191) NOT NULL,
|
||||
server_host text NOT NULL,
|
||||
|
||||
+2
-11
@@ -251,8 +251,8 @@ CREATE TABLE pubsub_item (
|
||||
nodeid bigint,
|
||||
itemid text NOT NULL,
|
||||
publisher text NOT NULL,
|
||||
creation text NOT NULL,
|
||||
modification text NOT NULL,
|
||||
creation varchar(32) NOT NULL,
|
||||
modification varchar(32) NOT NULL,
|
||||
payload text NOT NULL
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE INDEX i_pubsub_item_itemid ON pubsub_item(itemid(36));
|
||||
@@ -318,15 +318,6 @@ CREATE TABLE muc_room_subscribers (
|
||||
|
||||
CREATE INDEX i_muc_room_subscribers_host_jid USING BTREE ON muc_room_subscribers(host, jid);
|
||||
|
||||
CREATE TABLE irc_custom (
|
||||
jid text NOT NULL,
|
||||
host text NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE UNIQUE INDEX i_irc_custom_jid_host USING BTREE ON irc_custom(jid(75), host(75));
|
||||
|
||||
CREATE TABLE motd (
|
||||
username varchar(191) PRIMARY KEY,
|
||||
xml text,
|
||||
|
||||
+2
-15
@@ -144,9 +144,6 @@
|
||||
-- ALTER TABLE muc_online_users ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
|
||||
-- ALTER TABLE muc_online_users ALTER COLUMN server_host DROP DEFAULT;
|
||||
|
||||
-- ALTER TABLE irc_custom ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
|
||||
-- ALTER TABLE irc_custom ALTER COLUMN server_host DROP DEFAULT;
|
||||
|
||||
-- ALTER TABLE motd ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
|
||||
-- ALTER TABLE motd DROP CONSTRAINT motd_pkey;
|
||||
-- ALTER TABLE motd ADD PRIMARY KEY (server_host, username);
|
||||
@@ -428,8 +425,8 @@ CREATE TABLE pubsub_item (
|
||||
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
|
||||
itemid text NOT NULL,
|
||||
publisher text NOT NULL,
|
||||
creation text NOT NULL,
|
||||
modification text NOT NULL,
|
||||
creation varchar(32) NOT NULL,
|
||||
modification varchar(32) NOT NULL,
|
||||
payload text NOT NULL DEFAULT ''
|
||||
);
|
||||
CREATE INDEX i_pubsub_item_itemid ON pubsub_item USING btree (itemid);
|
||||
@@ -498,16 +495,6 @@ CREATE TABLE muc_room_subscribers (
|
||||
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
|
||||
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
|
||||
|
||||
CREATE TABLE irc_custom (
|
||||
jid text NOT NULL,
|
||||
host text NOT NULL,
|
||||
server_host text NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom USING btree (jid, host);
|
||||
|
||||
CREATE TABLE motd (
|
||||
username text NOT NULL,
|
||||
server_host text NOT NULL,
|
||||
|
||||
+2
-11
@@ -254,8 +254,8 @@ CREATE TABLE pubsub_item (
|
||||
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
|
||||
itemid text NOT NULL,
|
||||
publisher text NOT NULL,
|
||||
creation text NOT NULL,
|
||||
modification text NOT NULL,
|
||||
creation varchar(32) NOT NULL,
|
||||
modification varchar(32) NOT NULL,
|
||||
payload text NOT NULL DEFAULT ''
|
||||
);
|
||||
CREATE INDEX i_pubsub_item_itemid ON pubsub_item USING btree (itemid);
|
||||
@@ -320,15 +320,6 @@ CREATE TABLE muc_room_subscribers (
|
||||
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
|
||||
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
|
||||
|
||||
CREATE TABLE irc_custom (
|
||||
jid text NOT NULL,
|
||||
host text NOT NULL,
|
||||
data text NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom USING btree (jid, host);
|
||||
|
||||
CREATE TABLE motd (
|
||||
username text PRIMARY KEY,
|
||||
xml text,
|
||||
|
||||
+23
-12
@@ -36,14 +36,13 @@
|
||||
any_rules_allowed/3, 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,
|
||||
parse_ip_netmask/1, ip_matches_mask/3,
|
||||
access_rules_validator/1, shaper_rules_validator/1,
|
||||
normalize_spec/1, resolve_access/2]).
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("jid.hrl").
|
||||
|
||||
@@ -195,7 +194,7 @@ add_access(Host, Access, Rules) ->
|
||||
-spec load_from_config() -> ok.
|
||||
|
||||
load_from_config() ->
|
||||
Hosts = [global|?MYHOSTS],
|
||||
Hosts = [global|ejabberd_config:get_myhosts()],
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ACLs = ejabberd_config:get_option(
|
||||
@@ -447,13 +446,13 @@ acl_rule_matches({acl, Name}, Data, Host) ->
|
||||
RawACLs = lists:map(fun(#acl{aclspec = R}) -> R end, ACLs),
|
||||
any_acl_rules_matches(RawACLs, Data, Host);
|
||||
acl_rule_matches({ip, {Net, Mask}}, #{ip := {IP, _Port}}, _Host) ->
|
||||
is_ip_match(IP, Net, Mask);
|
||||
ip_matches_mask(IP, Net, Mask);
|
||||
acl_rule_matches({ip, {Net, Mask}}, #{ip := IP}, _Host) ->
|
||||
is_ip_match(IP, Net, Mask);
|
||||
ip_matches_mask(IP, Net, Mask);
|
||||
acl_rule_matches({user, {U, S}}, #{usr := {U, S, _}}, _Host) ->
|
||||
true;
|
||||
acl_rule_matches({user, U}, #{usr := {U, S, _}}, _Host) ->
|
||||
lists:member(S, ?MYHOSTS);
|
||||
lists:member(S, ejabberd_config:get_myhosts());
|
||||
acl_rule_matches({server, S}, #{usr := {_, S, _}}, _Host) ->
|
||||
true;
|
||||
acl_rule_matches({resource, R}, #{usr := {_, _, R}}, _Host) ->
|
||||
@@ -467,7 +466,7 @@ acl_rule_matches({shared_group, G}, #{usr := {U, S, _}}, Host) ->
|
||||
acl_rule_matches({user_regexp, {UR, S}}, #{usr := {U, S, _}}, _Host) ->
|
||||
is_regexp_match(U, UR);
|
||||
acl_rule_matches({user_regexp, UR}, #{usr := {U, S, _}}, _Host) ->
|
||||
lists:member(S, ?MYHOSTS) andalso is_regexp_match(U, UR);
|
||||
lists:member(S, ejabberd_config:get_myhosts()) andalso is_regexp_match(U, UR);
|
||||
acl_rule_matches({server_regexp, SR}, #{usr := {_, S, _}}, _Host) ->
|
||||
is_regexp_match(S, SR);
|
||||
acl_rule_matches({resource_regexp, RR}, #{usr := {_, _, R}}, _Host) ->
|
||||
@@ -477,7 +476,7 @@ acl_rule_matches({node_regexp, {UR, SR}}, #{usr := {U, S, _}}, _Host) ->
|
||||
acl_rule_matches({user_glob, {UR, S}}, #{usr := {U, S, _}}, _Host) ->
|
||||
is_glob_match(U, UR);
|
||||
acl_rule_matches({user_glob, UR}, #{usr := {U, S, _}}, _Host) ->
|
||||
lists:member(S, ?MYHOSTS) andalso is_glob_match(U, UR);
|
||||
lists:member(S, ejabberd_config:get_myhosts()) andalso is_glob_match(U, UR);
|
||||
acl_rule_matches({server_glob, SR}, #{usr := {_, S, _}}, _Host) ->
|
||||
is_glob_match(S, SR);
|
||||
acl_rule_matches({resource_glob, RR}, #{usr := {_, _, R}}, _Host) ->
|
||||
@@ -549,18 +548,30 @@ is_glob_match(String, Glob) ->
|
||||
is_regexp_match(String,
|
||||
ejabberd_regexp:sh_to_awk(Glob)).
|
||||
|
||||
is_ip_match({_, _, _, _} = IP, {_, _, _, _} = Net, Mask) ->
|
||||
ip_matches_mask({_, _, _, _} = IP, {_, _, _, _} = Net, Mask) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (32 - Mask) - 1),
|
||||
IPInt band M =:= NetInt band M;
|
||||
is_ip_match({_, _, _, _, _, _, _, _} = IP,
|
||||
{_, _, _, _, _, _, _, _} = Net, Mask) ->
|
||||
ip_matches_mask({_, _, _, _, _, _, _, _} = IP,
|
||||
{_, _, _, _, _, _, _, _} = Net, Mask) ->
|
||||
IPInt = ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (128 - Mask) - 1),
|
||||
IPInt band M =:= NetInt band M;
|
||||
is_ip_match(_, _, _) ->
|
||||
ip_matches_mask({_, _, _, _} = IP,
|
||||
{0, 0, 0, 0, 0, 16#FFFF, _, _} = Net, Mask) ->
|
||||
IPInt = ip_to_integer({0, 0, 0, 0, 0, 16#FFFF, 0, 0}) + ip_to_integer(IP),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (128 - Mask) - 1),
|
||||
IPInt band M =:= NetInt band M;
|
||||
ip_matches_mask({0, 0, 0, 0, 0, 16#FFFF, _, _} = IP,
|
||||
{_, _, _, _} = Net, Mask) ->
|
||||
IPInt = ip_to_integer(IP) - ip_to_integer({0, 0, 0, 0, 0, 16#FFFF, 0, 0}),
|
||||
NetInt = ip_to_integer(Net),
|
||||
M = bnot (1 bsl (32 - Mask) - 1),
|
||||
IPInt band M =:= NetInt band M;
|
||||
ip_matches_mask(_, _, _) ->
|
||||
false.
|
||||
|
||||
ip_to_integer({IP1, IP2, IP3, IP4}) ->
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
%% 3. tls-sni-01: https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-7.4
|
||||
%% 4. (?) oob-01: https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-7.5
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-record(state, {}).
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
-export([start/1, stop/0, mech_new/4, mech_step/2,
|
||||
parse/1, format_error/1, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-behaviour(cyrsasl).
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
-export([start/1, stop/0, mech_new/4, mech_step/2, format_error/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("scram.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-behaviour(cyrsasl).
|
||||
|
||||
+8
-3
@@ -25,6 +25,7 @@
|
||||
|
||||
-module(ejabberd).
|
||||
-author('alexey@process-one.net').
|
||||
-compile({no_auto_import, [{halt, 0}]}).
|
||||
|
||||
-protocol({xep, 4, '2.9'}).
|
||||
-protocol({xep, 86, '1.0'}).
|
||||
@@ -36,7 +37,7 @@
|
||||
-protocol({xep, 243, '1.0'}).
|
||||
-protocol({xep, 270, '1.0'}).
|
||||
|
||||
-export([start/0, stop/0, start_app/1, start_app/2,
|
||||
-export([start/0, stop/0, halt/0, start_app/1, start_app/2,
|
||||
get_pid_file/0, check_app/1, module_name/1]).
|
||||
|
||||
-include("logger.hrl").
|
||||
@@ -49,6 +50,11 @@ stop() ->
|
||||
application:stop(ejabberd).
|
||||
%%ejabberd_cover:stop().
|
||||
|
||||
halt() ->
|
||||
application:stop(lager),
|
||||
application:stop(sasl),
|
||||
erlang:halt(1, [{flush, true}]).
|
||||
|
||||
%% @spec () -> false | string()
|
||||
get_pid_file() ->
|
||||
case os:getenv("EJABBERD_PID_PATH") of
|
||||
@@ -131,8 +137,7 @@ exit_or_halt(Reason, StartFlag) ->
|
||||
?CRITICAL_MSG(Reason, []),
|
||||
if StartFlag ->
|
||||
%% Wait for the critical message is written in the console/log
|
||||
timer:sleep(1000),
|
||||
halt(string:substr(lists:flatten(Reason), 1, 199));
|
||||
halt();
|
||||
true ->
|
||||
erlang:error(application_start_failed)
|
||||
end.
|
||||
|
||||
@@ -506,7 +506,7 @@ is_valid_command_name2(<<>>) ->
|
||||
true;
|
||||
is_valid_command_name2(<<K:8, Rest/binary>>) when (K >= $a andalso K =< $z)
|
||||
orelse (K >= $0 andalso K =< $9)
|
||||
orelse K == $_ ->
|
||||
orelse K == $_ orelse K == $- ->
|
||||
is_valid_command_name2(Rest);
|
||||
is_valid_command_name2(_) ->
|
||||
false.
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
terminate/2, code_change/3]).
|
||||
-export([start_link/0, opt_type/1, register_certfiles/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
%% delete_authz/3
|
||||
]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
|
||||
@@ -412,7 +411,7 @@ stop_kindly(DelaySeconds, AnnouncementTextString) ->
|
||||
ejabberd_listener, stop_listeners, []},
|
||||
{"Sending announcement to connected users",
|
||||
mod_announce, send_announcement_to_all,
|
||||
[?MYNAME, Subject, AnnouncementText]},
|
||||
[ejabberd_config:get_myname(), Subject, AnnouncementText]},
|
||||
{"Sending service message to MUC rooms",
|
||||
ejabberd_admin, send_service_message_all_mucs,
|
||||
[Subject, AnnouncementText]},
|
||||
@@ -446,7 +445,7 @@ send_service_message_all_mucs(Subject, AnnouncementText) ->
|
||||
ServerHost, mod_muc, <<"conference.@HOST@">>),
|
||||
mod_muc:broadcast_service_message(ServerHost, MUCHost, Message)
|
||||
end,
|
||||
?MYHOSTS).
|
||||
ejabberd_config:get_myhosts()).
|
||||
|
||||
%%%
|
||||
%%% ejabberd_update
|
||||
@@ -499,7 +498,7 @@ registered_users(Host) ->
|
||||
lists:map(fun({U, _S}) -> U end, SUsers).
|
||||
|
||||
registered_vhosts() ->
|
||||
?MYHOSTS.
|
||||
ejabberd_config:get_myhosts().
|
||||
|
||||
reload_config() ->
|
||||
ejabberd_config:reload_file().
|
||||
@@ -549,13 +548,13 @@ delete_expired_messages() ->
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
{atomic, ok} = mod_offline:remove_expired_messages(Host)
|
||||
end, ?MYHOSTS).
|
||||
end, ejabberd_config:get_myhosts()).
|
||||
|
||||
delete_old_messages(Days) ->
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
{atomic, _} = mod_offline:remove_old_messages(Days, Host)
|
||||
end, ?MYHOSTS).
|
||||
end, ejabberd_config:get_myhosts()).
|
||||
|
||||
%%%
|
||||
%%% Mnesia management
|
||||
@@ -622,13 +621,12 @@ keep_tables() ->
|
||||
%% loaded modules
|
||||
keep_modules_tables() ->
|
||||
lists:map(fun(Module) -> module_tables(Module) end,
|
||||
gen_mod:loaded_modules(?MYNAME)).
|
||||
gen_mod:loaded_modules(ejabberd_config:get_myname())).
|
||||
|
||||
%% TODO: This mapping should probably be moved to a callback function in each
|
||||
%% module.
|
||||
%% Mapping between modules and their tables
|
||||
module_tables(mod_announce) -> [motd, motd_users];
|
||||
module_tables(mod_irc) -> [irc_custom];
|
||||
module_tables(mod_last) -> [last_activity];
|
||||
module_tables(mod_muc) -> [muc_room, muc_registered];
|
||||
module_tables(mod_offline) -> [offline_msg];
|
||||
|
||||
+25
-20
@@ -31,7 +31,6 @@
|
||||
|
||||
-export([start/2, prep_stop/1, stop/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%%
|
||||
@@ -46,24 +45,29 @@ start(normal, _Args) ->
|
||||
start_elixir_application(),
|
||||
ejabberd:check_app(ejabberd),
|
||||
setup_if_elixir_conf_used(),
|
||||
ejabberd_config:start(),
|
||||
ejabberd_mnesia:start(),
|
||||
file_queue_init(),
|
||||
maybe_add_nameservers(),
|
||||
ejabberd_system_monitor:start(),
|
||||
case ejabberd_sup:start_link() of
|
||||
{ok, SupPid} ->
|
||||
register_elixir_config_hooks(),
|
||||
ejabberd_cluster:wait_for_sync(infinity),
|
||||
{T2, _} = statistics(wall_clock),
|
||||
?INFO_MSG("ejabberd ~s is started in the node ~p in ~.2fs",
|
||||
[?VERSION, node(), (T2-T1)/1000]),
|
||||
lists:foreach(fun erlang:garbage_collect/1, processes()),
|
||||
{ok, SupPid};
|
||||
Err ->
|
||||
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Err]),
|
||||
timer:sleep(1000),
|
||||
halt("Refer to ejabberd log files to diagnose the problem")
|
||||
case ejabberd_config:start() of
|
||||
ok ->
|
||||
ejabberd_mnesia:start(),
|
||||
file_queue_init(),
|
||||
maybe_add_nameservers(),
|
||||
case ejabberd_sup:start_link() of
|
||||
{ok, SupPid} ->
|
||||
ejabberd_system_monitor:start(),
|
||||
register_elixir_config_hooks(),
|
||||
ejabberd_cluster:wait_for_sync(infinity),
|
||||
{T2, _} = statistics(wall_clock),
|
||||
?INFO_MSG("ejabberd ~s is started in the node ~p in ~.2fs",
|
||||
[ejabberd_config:get_version(),
|
||||
node(), (T2-T1)/1000]),
|
||||
lists:foreach(fun erlang:garbage_collect/1, processes()),
|
||||
{ok, SupPid};
|
||||
Err ->
|
||||
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Err]),
|
||||
ejabberd:halt()
|
||||
end;
|
||||
{error, Reason} ->
|
||||
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Reason]),
|
||||
ejabberd:halt()
|
||||
end;
|
||||
start(_, _) ->
|
||||
{error, badarg}.
|
||||
@@ -79,7 +83,8 @@ prep_stop(State) ->
|
||||
|
||||
%% All the processes were killed when this function is called
|
||||
stop(_State) ->
|
||||
?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]),
|
||||
?INFO_MSG("ejabberd ~s is stopped in the node ~p",
|
||||
[ejabberd_config:get_version(), node()]),
|
||||
delete_pid_file(),
|
||||
%%ejabberd_debug:stop(),
|
||||
ok.
|
||||
|
||||
+54
-28
@@ -48,7 +48,7 @@
|
||||
|
||||
-export([auth_modules/1, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("scram.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(AUTH_CACHE, auth_cache).
|
||||
@@ -69,6 +69,7 @@
|
||||
|
||||
-callback start(binary()) -> any().
|
||||
-callback stop(binary()) -> any().
|
||||
-callback reload(binary()) -> any().
|
||||
-callback plain_password_required(binary()) -> boolean().
|
||||
-callback store_type(binary()) -> plain | external | scram.
|
||||
-callback set_password(binary(), binary(), binary()) -> ok | {error, atom()}.
|
||||
@@ -82,7 +83,8 @@
|
||||
-callback use_cache(binary()) -> boolean().
|
||||
-callback cache_nodes(binary()) -> boolean().
|
||||
|
||||
-optional_callbacks([set_password/3,
|
||||
-optional_callbacks([reload/1,
|
||||
set_password/3,
|
||||
remove_user/2,
|
||||
user_exists/2,
|
||||
check_password/4,
|
||||
@@ -105,7 +107,7 @@ init([]) ->
|
||||
fun(Host, Acc) ->
|
||||
Modules = auth_modules(Host),
|
||||
maps:put(Host, Modules, Acc)
|
||||
end, #{}, ?MYHOSTS),
|
||||
end, #{}, ejabberd_config:get_myhosts()),
|
||||
lists:foreach(
|
||||
fun({Host, Modules}) ->
|
||||
start(Host, Modules)
|
||||
@@ -130,14 +132,16 @@ handle_cast({host_down, Host}, #state{host_modules = HostModules} = State) ->
|
||||
init_cache(NewHostModules),
|
||||
{noreply, State#state{host_modules = NewHostModules}};
|
||||
handle_cast(config_reloaded, #state{host_modules = HostModules} = State) ->
|
||||
NewHostModules = lists:foldl(
|
||||
fun(Host, Acc) ->
|
||||
OldModules = maps:get(Host, HostModules, []),
|
||||
NewModules = auth_modules(Host),
|
||||
start(Host, NewModules -- OldModules),
|
||||
stop(Host, OldModules -- NewModules),
|
||||
maps:put(Host, NewModules, Acc)
|
||||
end, HostModules, ?MYHOSTS),
|
||||
NewHostModules =
|
||||
lists:foldl(
|
||||
fun(Host, Acc) ->
|
||||
OldModules = maps:get(Host, HostModules, []),
|
||||
NewModules = auth_modules(Host),
|
||||
start(Host, NewModules -- OldModules),
|
||||
stop(Host, OldModules -- NewModules),
|
||||
reload(Host, lists_intersection(OldModules, NewModules)),
|
||||
maps:put(Host, NewModules, Acc)
|
||||
end, HostModules, ejabberd_config:get_myhosts()),
|
||||
init_cache(NewHostModules),
|
||||
{noreply, State#state{host_modules = NewHostModules}};
|
||||
handle_cast(Msg, State) ->
|
||||
@@ -165,6 +169,15 @@ start(Host, Modules) ->
|
||||
stop(Host, Modules) ->
|
||||
lists:foreach(fun(M) -> M:stop(Host) end, Modules).
|
||||
|
||||
reload(Host, Modules) ->
|
||||
lists:foreach(
|
||||
fun(M) ->
|
||||
case erlang:function_exported(M, reload, 1) of
|
||||
true -> M:reload(Host);
|
||||
false -> ok
|
||||
end
|
||||
end, Modules).
|
||||
|
||||
host_up(Host) ->
|
||||
gen_server:cast(?MODULE, {host_up, Host}).
|
||||
|
||||
@@ -217,19 +230,22 @@ check_password_with_authmodule(User, AuthzId, Server, Password) ->
|
||||
check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGen) ->
|
||||
case validate_credentials(User, Server) of
|
||||
{ok, LUser, LServer} ->
|
||||
lists:foldl(
|
||||
fun(Mod, false) ->
|
||||
case db_check_password(
|
||||
LUser, AuthzId, LServer, Password,
|
||||
Digest, DigestGen, Mod) of
|
||||
true -> {true, Mod};
|
||||
false -> false
|
||||
end;
|
||||
(_, Acc) ->
|
||||
Acc
|
||||
end, false, auth_modules(LServer));
|
||||
_ ->
|
||||
false
|
||||
case jid:nodeprep(AuthzId) of
|
||||
error ->
|
||||
false;
|
||||
LAuthzId ->
|
||||
lists:foldl(
|
||||
fun(Mod, false) ->
|
||||
case db_check_password(
|
||||
LUser, LAuthzId, LServer, Password,
|
||||
Digest, DigestGen, Mod) of
|
||||
true -> {true, Mod};
|
||||
false -> false
|
||||
end;
|
||||
(_, Acc) ->
|
||||
Acc
|
||||
end, false, auth_modules(LServer))
|
||||
end
|
||||
end.
|
||||
|
||||
-spec set_password(binary(), binary(), password()) -> ok | {error, atom()}.
|
||||
@@ -545,8 +561,8 @@ db_user_exists(User, Server, Mod) ->
|
||||
{ok, _} ->
|
||||
true;
|
||||
error ->
|
||||
case Mod:store_type(Server) of
|
||||
external ->
|
||||
case {Mod:store_type(Server), use_cache(Mod, Server)} of
|
||||
{external, true} ->
|
||||
case ets_cache:lookup(
|
||||
?AUTH_CACHE, {User, Server},
|
||||
fun() ->
|
||||
@@ -559,8 +575,12 @@ db_user_exists(User, Server, Mod) ->
|
||||
{ok, _} ->
|
||||
true;
|
||||
error ->
|
||||
false
|
||||
false;
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end;
|
||||
{external, false} ->
|
||||
Mod:user_exists(User, Server);
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
@@ -744,7 +764,7 @@ auth_modules() ->
|
||||
lists:flatmap(
|
||||
fun(Host) ->
|
||||
[{Host, Mod} || Mod <- auth_modules(Host)]
|
||||
end, ?MYHOSTS).
|
||||
end, ejabberd_config:get_myhosts()).
|
||||
|
||||
-spec auth_modules(binary()) -> [module()].
|
||||
auth_modules(Server) ->
|
||||
@@ -814,6 +834,12 @@ validate_credentials(User, Server, Password) ->
|
||||
end
|
||||
end.
|
||||
|
||||
lists_intersection(L1, L2) ->
|
||||
lists:filter(
|
||||
fun(E) ->
|
||||
lists:member(E, L2)
|
||||
end, L1).
|
||||
|
||||
import_info() ->
|
||||
[{<<"users">>, 3}].
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
get_users/2, count_users/2, store_type/1,
|
||||
plain_password_required/1, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("jid.hrl").
|
||||
|
||||
|
||||
@@ -31,23 +31,24 @@
|
||||
|
||||
-behaviour(ejabberd_auth).
|
||||
|
||||
-export([start/1, stop/1, set_password/3, check_password/4,
|
||||
-export([start/1, stop/1, reload/1, set_password/3, check_password/4,
|
||||
try_register/3, user_exists/2, remove_user/2,
|
||||
store_type/1, plain_password_required/1, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(Host) ->
|
||||
Cmd = ejabberd_config:get_option({extauth_program, Host}, "extauth"),
|
||||
extauth:start(Host, Cmd).
|
||||
extauth:start(Host).
|
||||
|
||||
stop(Host) ->
|
||||
extauth:stop(Host).
|
||||
|
||||
reload(Host) ->
|
||||
extauth:reload(Host).
|
||||
|
||||
plain_password_required(_) -> true.
|
||||
|
||||
store_type(_) -> external.
|
||||
@@ -61,37 +62,48 @@ check_password(User, AuthzId, Server, Password) ->
|
||||
|
||||
set_password(User, Server, Password) ->
|
||||
case extauth:set_password(User, Server, Password) of
|
||||
true -> ok;
|
||||
_ -> {error, db_failure}
|
||||
Res when is_boolean(Res) -> ok;
|
||||
{error, Reason} -> failure(User, Server, set_password, Reason)
|
||||
end.
|
||||
|
||||
try_register(User, Server, Password) ->
|
||||
extauth:try_register(User, Server, Password).
|
||||
case extauth:try_register(User, Server, Password) of
|
||||
true -> ok;
|
||||
false -> {error, not_allowed};
|
||||
{error, Reason} -> failure(User, Server, try_register, Reason)
|
||||
end.
|
||||
|
||||
user_exists(User, Server) ->
|
||||
try extauth:user_exists(User, Server) of
|
||||
Res -> Res
|
||||
catch
|
||||
_:Error ->
|
||||
?ERROR_MSG("external authentication program failure: ~p",
|
||||
[Error]),
|
||||
{error, db_failure}
|
||||
case extauth:user_exists(User, Server) of
|
||||
Res when is_boolean(Res) -> Res;
|
||||
{error, Reason} -> failure(User, Server, user_exists, Reason)
|
||||
end.
|
||||
|
||||
remove_user(User, Server) ->
|
||||
case extauth:remove_user(User, Server) of
|
||||
false -> {error, not_allowed};
|
||||
true -> ok
|
||||
true -> ok;
|
||||
{error, Reason} -> failure(User, Server, remove_user, Reason)
|
||||
end.
|
||||
|
||||
check_password_extauth(User, _AuthzId, Server, Password) ->
|
||||
extauth:check_password(User, Server, Password) andalso
|
||||
Password /= <<"">>.
|
||||
if Password /= <<"">> ->
|
||||
case extauth:check_password(User, Server, Password) of
|
||||
Res when is_boolean(Res) -> Res;
|
||||
{error, Reason} ->
|
||||
failure(User, Server, check_password, Reason),
|
||||
false
|
||||
end;
|
||||
true ->
|
||||
false
|
||||
end.
|
||||
|
||||
-spec failure(binary(), binary(), atom(), any()) -> {error, db_failure}.
|
||||
failure(User, Server, Fun, Reason) ->
|
||||
?ERROR_MSG("External authentication program failed when calling "
|
||||
"'~s' for ~s@~s: ~p", [Fun, User, Server, Reason]),
|
||||
{error, db_failure}.
|
||||
|
||||
-spec opt_type(extauth_cache) -> fun((false | non_neg_integer()) ->
|
||||
false | non_neg_integer());
|
||||
(extauth_program) -> fun((binary()) -> string());
|
||||
(atom()) -> [atom()].
|
||||
opt_type(extauth_cache) ->
|
||||
?WARNING_MSG("option 'extauth_cache' is deprecated and has no effect, "
|
||||
"use authentication or global cache configuration "
|
||||
@@ -100,6 +112,15 @@ opt_type(extauth_cache) ->
|
||||
fun (false) -> false;
|
||||
(I) when is_integer(I), I >= 0 -> I
|
||||
end;
|
||||
opt_type(extauth_instances) ->
|
||||
?WARNING_MSG("option 'extauth_instances' is deprecated and has no effect, "
|
||||
"use 'extauth_pool_size'", []),
|
||||
fun (V) when is_integer(V), V > 0 -> V end;
|
||||
opt_type(extauth_program) ->
|
||||
fun (V) -> binary_to_list(iolist_to_binary(V)) end;
|
||||
opt_type(_) -> [extauth_cache, extauth_program].
|
||||
opt_type(extauth_pool_size) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
opt_type(_) ->
|
||||
[extauth_program, extauth_pool_size,
|
||||
%% Deprecated:
|
||||
extauth_cache, extauth_instances].
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
store_type/1, plain_password_required/1,
|
||||
opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("eldap.hrl").
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
plain_password_required/1, use_cache/1]).
|
||||
-export([need_transform/1, transform/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("scram.hrl").
|
||||
-include("ejabberd_auth.hrl").
|
||||
|
||||
-record(reg_users_counter, {vhost = <<"">> :: binary(),
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
plain_password_required/1]).
|
||||
-export([passwd_schema/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
-include("scram.hrl").
|
||||
-include("ejabberd_auth.hrl").
|
||||
|
||||
start(_Host) ->
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
remove_user/2, store_type/1, plain_password_required/1,
|
||||
convert_to_scram/1, opt_type/1, export/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("scram.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
-include("ejabberd_auth.hrl").
|
||||
|
||||
+12
-15
@@ -44,13 +44,9 @@
|
||||
handle_sync_event/4, handle_info/3, terminate/3,
|
||||
code_change/4]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
-include("bosh.hrl").
|
||||
|
||||
%%-define(DBGFSM, true).
|
||||
@@ -103,8 +99,8 @@
|
||||
prev_key = <<"">> :: binary(),
|
||||
prev_poll :: erlang:timestamp() | undefined,
|
||||
max_concat = unlimited :: unlimited | non_neg_integer(),
|
||||
responses = gb_trees:empty() :: ?TGB_TREE,
|
||||
receivers = gb_trees:empty() :: ?TGB_TREE,
|
||||
responses = gb_trees:empty() :: gb_trees:tree(),
|
||||
receivers = gb_trees:empty() :: gb_trees:tree(),
|
||||
shaped_receivers :: p1_queue:queue(),
|
||||
ip :: inet:ip_address(),
|
||||
max_requests = 1 :: non_neg_integer()}).
|
||||
@@ -452,7 +448,7 @@ active1(#body{attrs = Attrs} = Req, From, State) ->
|
||||
{next_state, active,
|
||||
do_reply(State, From, PrevBody, RID)};
|
||||
none ->
|
||||
State1 = drop_holding_receiver(State),
|
||||
State1 = drop_holding_receiver(State, RID),
|
||||
State2 = stop_inactivity_timer(State1),
|
||||
State3 = restart_wait_timer(State2),
|
||||
Receivers = gb_trees:insert(RID, {From, Req},
|
||||
@@ -688,15 +684,16 @@ reply_stop(State, Body, From, RID) ->
|
||||
{stop, normal, do_reply(State, From, Body, RID)}.
|
||||
|
||||
drop_holding_receiver(State) ->
|
||||
RID = State#state.prev_rid,
|
||||
drop_holding_receiver(State, State#state.prev_rid).
|
||||
drop_holding_receiver(State, RID) ->
|
||||
case gb_trees:lookup(RID, State#state.receivers) of
|
||||
{value, {From, Body}} ->
|
||||
State1 = restart_inactivity_timer(State),
|
||||
Receivers = gb_trees:delete_any(RID,
|
||||
State1#state.receivers),
|
||||
State2 = State1#state{receivers = Receivers},
|
||||
do_reply(State2, From, Body, RID);
|
||||
none -> State
|
||||
{value, {From, Body}} ->
|
||||
State1 = restart_inactivity_timer(State),
|
||||
Receivers = gb_trees:delete_any(RID,
|
||||
State1#state.receivers),
|
||||
State2 = State1#state{receivers = Receivers},
|
||||
do_reply(State2, From, Body, RID);
|
||||
none -> State
|
||||
end.
|
||||
|
||||
do_reply(State, From, Body, RID) ->
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
reply/2, copy_state/2, set_timeout/2, route/2,
|
||||
host_up/1, host_down/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("mod_roster.hrl").
|
||||
@@ -415,7 +414,7 @@ bind(R, #{user := U, server := S, access := Access, lang := Lang,
|
||||
handle_stream_start(StreamStart, #{lserver := LServer} = State) ->
|
||||
case ejabberd_router:is_my_host(LServer) of
|
||||
false ->
|
||||
send(State#{lserver => ?MYNAME}, xmpp:serr_host_unknown());
|
||||
send(State#{lserver => ejabberd_config:get_myname()}, xmpp:serr_host_unknown());
|
||||
true ->
|
||||
State1 = change_shaper(State),
|
||||
Opts = ejabberd_config:codec_options(LServer),
|
||||
@@ -526,9 +525,9 @@ init([State, Opts]) ->
|
||||
tls_verify => TLSVerify,
|
||||
pres_a => ?SETS:new(),
|
||||
zlib => Zlib,
|
||||
lang => ?MYLANG,
|
||||
server => ?MYNAME,
|
||||
lserver => ?MYNAME,
|
||||
lang => ejabberd_config:get_mylang(),
|
||||
server => ejabberd_config:get_myname(),
|
||||
lserver => ejabberd_config:get_myname(),
|
||||
access => Access,
|
||||
shaper => Shaper},
|
||||
State2 = xmpp_stream_in:set_timeout(State1, Timeout),
|
||||
@@ -1038,14 +1037,16 @@ listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(backlog) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(O) ->
|
||||
StreamOpts = mod_stream_mgmt:mod_options(?MYNAME),
|
||||
StreamOpts = mod_stream_mgmt:mod_options(ejabberd_config:get_myname()),
|
||||
case lists:keyfind(O, 1, StreamOpts) of
|
||||
false ->
|
||||
[access, shaper, certfile, ciphers, dhfile, cafile,
|
||||
protocol_options, tls, tls_compression, starttls,
|
||||
starttls_required, tls_verify, zlib, max_fsm_queue,
|
||||
backlog, inet, inet6];
|
||||
backlog, inet, inet6, accept_interval];
|
||||
_ ->
|
||||
?ERROR_MSG("Listening option '~s' is ignored: use '~s' "
|
||||
"option from mod_stream_mgmt module", [O, O]),
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
config_reloaded/0, process_iq/1]).
|
||||
|
||||
-include("xmpp.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
@@ -365,12 +364,12 @@ terminate(_Reason, #state{enabled = Enabled}) ->
|
||||
register_handlers() ->
|
||||
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
|
||||
ejabberd_hooks:add(host_down, ?MODULE, host_down, 50),
|
||||
lists:foreach(fun host_up/1, ?MYHOSTS).
|
||||
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()).
|
||||
|
||||
unregister_handlers() ->
|
||||
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50),
|
||||
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 50),
|
||||
lists:foreach(fun host_down/1, ?MYHOSTS).
|
||||
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) -> {ok, State}.
|
||||
|
||||
@@ -445,7 +444,7 @@ get_url(Str) ->
|
||||
<<TransferProt/binary, ":", Host/binary, ":",
|
||||
PortString/binary, "/captcha/", Str/binary>>;
|
||||
_ ->
|
||||
<<"http://", (?MYNAME)/binary, "/captcha/", Str/binary>>
|
||||
<<"http://", (ejabberd_config:get_myname())/binary, "/captcha/", Str/binary>>
|
||||
end.
|
||||
|
||||
get_transfer_protocol(PortString) ->
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
get_known_nodes/0, node_id/0, get_node_by_id/1,
|
||||
send/2, wait_for_sync/1, subscribe/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-spec init() -> ok.
|
||||
|
||||
@@ -240,7 +240,6 @@
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd_commands.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
-export([generate_md_output/3]).
|
||||
|
||||
-include("ejabberd_commands.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
-define(RAW(V), if HTMLOutput -> fxml:crypt(iolist_to_binary(V)); true -> iolist_to_binary(V) end).
|
||||
-define(TAG(N), if HTMLOutput -> [<<"<", ??N, "/>">>]; true -> md_tag(N, <<"">>) end).
|
||||
|
||||
+96
-67
@@ -28,7 +28,8 @@
|
||||
|
||||
-export([start/0, load_file/1, reload_file/0, read_file/1,
|
||||
get_option/1, get_option/2, add_option/2, has_option/1,
|
||||
get_version/0, get_myhosts/0, get_mylang/0, get_lang/1,
|
||||
get_version/0, get_myhosts/0, get_myname/0,
|
||||
get_mylang/0, get_lang/1, get_uri/0, get_copyright/0,
|
||||
get_ejabberd_config_path/0, is_using_elixir_config/0,
|
||||
prepare_opt_val/4, transform_options/1, collect_options/1,
|
||||
convert_to_yaml/1, convert_to_yaml/2, v_db/2,
|
||||
@@ -53,21 +54,15 @@
|
||||
{get_global_option, 3}, {get_local_option, 3},
|
||||
{get_option, 3}, {is_file_readable, 1}]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_config.hrl").
|
||||
-include_lib("kernel/include/file.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
-callback opt_type(atom()) -> function() | [atom()].
|
||||
-type bad_option() :: invalid_option | unknown_option.
|
||||
|
||||
%% @type macro() = {macro_key(), macro_value()}
|
||||
|
||||
%% @type macro_key() = atom().
|
||||
%% The atom must have all characters in uppercase.
|
||||
|
||||
%% @type macro_value() = term().
|
||||
|
||||
-spec start() -> ok | {error, bad_option()}.
|
||||
start() ->
|
||||
ConfigFile = get_ejabberd_config_path(),
|
||||
?INFO_MSG("Loading configuration from ~s", [ConfigFile]),
|
||||
@@ -75,17 +70,23 @@ start() ->
|
||||
[named_table, public, {read_concurrency, true}]),
|
||||
catch ets:new(ejabberd_db_modules,
|
||||
[named_table, public, {read_concurrency, true}]),
|
||||
State1 = load_file(ConfigFile),
|
||||
UnixTime = p1_time_compat:system_time(seconds),
|
||||
SharedKey = case erlang:get_cookie() of
|
||||
nocookie ->
|
||||
str:sha(randoms:get_string());
|
||||
Cookie ->
|
||||
str:sha(misc:atom_to_binary(Cookie))
|
||||
end,
|
||||
State2 = set_option({node_start, global}, UnixTime, State1),
|
||||
State3 = set_option({shared_key, global}, SharedKey, State2),
|
||||
set_opts(State3).
|
||||
case load_file(ConfigFile) of
|
||||
{ok, State1} ->
|
||||
UnixTime = p1_time_compat:system_time(seconds),
|
||||
SharedKey = case erlang:get_cookie() of
|
||||
nocookie ->
|
||||
str:sha(randoms:get_string());
|
||||
Cookie ->
|
||||
str:sha(misc:atom_to_binary(Cookie))
|
||||
end,
|
||||
State2 = set_option({node_start, global}, UnixTime, State1),
|
||||
State3 = set_option({shared_key, global}, SharedKey, State2),
|
||||
set_opts(State3),
|
||||
ok;
|
||||
{error, _} = Err ->
|
||||
?ERROR_MSG("Failed to load configuration file ~s", [ConfigFile]),
|
||||
Err
|
||||
end.
|
||||
|
||||
%% When starting ejabberd for testing, we sometimes want to start a
|
||||
%% subset of hosts from the one define in the config file.
|
||||
@@ -135,7 +136,7 @@ get_ejabberd_config_path() ->
|
||||
undefined ->
|
||||
case os:getenv("EJABBERD_CONFIG_PATH") of
|
||||
false ->
|
||||
?CONFIG_PATH;
|
||||
"ejabberd.yml";
|
||||
Path ->
|
||||
Path
|
||||
end
|
||||
@@ -189,7 +190,7 @@ read_file(File, Opts) ->
|
||||
State1 = lists:foldl(fun process_term/2, State, Head ++ Tail),
|
||||
State1#state{opts = compact(State1#state.opts)}.
|
||||
|
||||
-spec load_file(string()) -> #state{}.
|
||||
-spec load_file(string()) -> {ok, #state{}} | {error, bad_option()}.
|
||||
|
||||
load_file(File) ->
|
||||
State0 = read_file(File),
|
||||
@@ -199,23 +200,27 @@ load_file(File) ->
|
||||
ModOpts = get_modules_with_options(AllMods),
|
||||
validate_opts(State1, ModOpts).
|
||||
|
||||
-spec reload_file() -> ok.
|
||||
-spec reload_file() -> ok | {error, bad_option()}.
|
||||
|
||||
reload_file() ->
|
||||
Config = get_ejabberd_config_path(),
|
||||
OldHosts = get_myhosts(),
|
||||
State = load_file(Config),
|
||||
set_opts(State),
|
||||
NewHosts = get_myhosts(),
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ejabberd_hooks:run(host_up, [Host])
|
||||
end, NewHosts -- OldHosts),
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ejabberd_hooks:run(host_down, [Host])
|
||||
end, OldHosts -- NewHosts),
|
||||
ejabberd_hooks:run(config_reloaded, []).
|
||||
case load_file(Config) of
|
||||
{error, _} = Err ->
|
||||
Err;
|
||||
{ok, State} ->
|
||||
set_opts(State),
|
||||
NewHosts = get_myhosts(),
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ejabberd_hooks:run(host_up, [Host])
|
||||
end, NewHosts -- OldHosts),
|
||||
lists:foreach(
|
||||
fun(Host) ->
|
||||
ejabberd_hooks:run(host_down, [Host])
|
||||
end, OldHosts -- NewHosts),
|
||||
ejabberd_hooks:run(config_reloaded, [])
|
||||
end.
|
||||
|
||||
-spec convert_to_yaml(file:filename()) -> ok | {error, any()}.
|
||||
|
||||
@@ -455,8 +460,7 @@ get_config_lines2(Fd, Data, CurrLine, [NextWanted | LNumbers], R) when is_list(D
|
||||
exit_or_halt(ExitText) ->
|
||||
case [Vsn || {ejabberd, _Desc, Vsn} <- application:which_applications()] of
|
||||
[] ->
|
||||
timer:sleep(1000),
|
||||
halt(string:substr(ExitText, 1, 199));
|
||||
ejabberd:halt();
|
||||
[_] ->
|
||||
exit(ExitText)
|
||||
end.
|
||||
@@ -1018,33 +1022,39 @@ get_modules_with_options(Modules) ->
|
||||
end
|
||||
end, dict:new(), Modules).
|
||||
|
||||
-spec validate_opts(#state{}, dict:dict()) -> {ok, #state{}} | {error, bad_option()}.
|
||||
validate_opts(#state{opts = Opts} = State, ModOpts) ->
|
||||
NewOpts = lists:filtermap(
|
||||
fun(#local_config{key = {Opt, _Host}, value = Val} = In) ->
|
||||
case dict:find(Opt, ModOpts) of
|
||||
{ok, [Mod|_]} ->
|
||||
VFun = Mod:opt_type(Opt),
|
||||
try VFun(Val) of
|
||||
NewVal ->
|
||||
{true, In#local_config{value = NewVal}}
|
||||
catch {invalid_syntax, Error} ->
|
||||
?ERROR_MSG("ignoring option '~s' with "
|
||||
"invalid value: ~p: ~s",
|
||||
[Opt, Val, Error]),
|
||||
false;
|
||||
_:_ ->
|
||||
?ERROR_MSG("ignoring option '~s' with "
|
||||
"invalid value: ~p",
|
||||
[Opt, Val]),
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
?ERROR_MSG("unknown option '~s' will be likely"
|
||||
" ignored", [Opt]),
|
||||
true
|
||||
end
|
||||
end, Opts),
|
||||
State#state{opts = NewOpts}.
|
||||
try
|
||||
NewOpts = lists:map(
|
||||
fun(#local_config{key = {Opt, _Host}, value = Val} = In) ->
|
||||
case dict:find(Opt, ModOpts) of
|
||||
{ok, [Mod|_]} ->
|
||||
VFun = Mod:opt_type(Opt),
|
||||
try VFun(Val) of
|
||||
NewVal ->
|
||||
In#local_config{value = NewVal}
|
||||
catch {invalid_syntax, Error} ->
|
||||
?ERROR_MSG("Invalid value '~p' for "
|
||||
"option '~s': ~s",
|
||||
[Val, Opt, Error]),
|
||||
erlang:error(invalid_option);
|
||||
_:_ ->
|
||||
?ERROR_MSG("Invalid value '~p' for "
|
||||
"option '~s'",
|
||||
[Val, Opt]),
|
||||
erlang:error(invalid_option)
|
||||
end;
|
||||
_ ->
|
||||
?ERROR_MSG("Unknown option '~s'", [Opt]),
|
||||
erlang:error(unknown_option)
|
||||
end
|
||||
end, Opts),
|
||||
{ok, State#state{opts = NewOpts}}
|
||||
catch _:invalid_option ->
|
||||
{error, invalid_option};
|
||||
_:unknown_option ->
|
||||
{error, unknown_option}
|
||||
end.
|
||||
|
||||
%% @spec (Path::string()) -> true | false
|
||||
is_file_readable(Path) ->
|
||||
@@ -1060,9 +1070,16 @@ is_file_readable(Path) ->
|
||||
end.
|
||||
|
||||
get_version() ->
|
||||
case application:get_key(ejabberd, vsn) of
|
||||
undefined -> "";
|
||||
{ok, Vsn} -> list_to_binary(Vsn)
|
||||
case application:get_env(ejabberd, custom_vsn) of
|
||||
{ok, Vsn0} when is_list(Vsn0) ->
|
||||
list_to_binary(Vsn0);
|
||||
{ok, Vsn1} when is_binary(Vsn1) ->
|
||||
Vsn1;
|
||||
_ ->
|
||||
case application:get_key(ejabberd, vsn) of
|
||||
undefined -> "";
|
||||
{ok, Vsn} -> list_to_binary(Vsn)
|
||||
end
|
||||
end.
|
||||
|
||||
-spec get_myhosts() -> [binary()].
|
||||
@@ -1070,6 +1087,11 @@ get_version() ->
|
||||
get_myhosts() ->
|
||||
get_option(hosts).
|
||||
|
||||
-spec get_myname() -> binary().
|
||||
|
||||
get_myname() ->
|
||||
hd(get_myhosts()).
|
||||
|
||||
-spec get_mylang() -> binary().
|
||||
|
||||
get_mylang() ->
|
||||
@@ -1079,10 +1101,17 @@ get_mylang() ->
|
||||
get_lang(Host) ->
|
||||
get_option({language, Host}, <<"en">>).
|
||||
|
||||
-spec get_uri() -> binary().
|
||||
get_uri() ->
|
||||
<<"http://www.process-one.net/en/ejabberd/">>.
|
||||
|
||||
-spec get_copyright() -> binary().
|
||||
get_copyright() ->
|
||||
<<"Copyright (c) ProcessOne">>.
|
||||
|
||||
replace_module(mod_announce_odbc) -> {mod_announce, sql};
|
||||
replace_module(mod_blocking_odbc) -> {mod_blocking, sql};
|
||||
replace_module(mod_caps_odbc) -> {mod_caps, sql};
|
||||
replace_module(mod_irc_odbc) -> {mod_irc, sql};
|
||||
replace_module(mod_last_odbc) -> {mod_last, sql};
|
||||
replace_module(mod_muc_odbc) -> {mod_muc, sql};
|
||||
replace_module(mod_offline_odbc) -> {mod_offline, sql};
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
|
||||
-include("ejabberd_ctl.hrl").
|
||||
-include("ejabberd_commands.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(DEFAULT_VERSION, 1000000).
|
||||
|
||||
+234
-202
@@ -31,17 +31,15 @@
|
||||
|
||||
%% External exports
|
||||
-export([start/2, start_link/2, become_controller/1,
|
||||
socket_type/0, receive_headers/1, url_encode/1,
|
||||
socket_type/0, receive_headers/1, recv_file/2,
|
||||
transform_listen_option/2, listen_opt_type/1]).
|
||||
|
||||
-export([init/2, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
|
||||
-include("ejabberd_http.hrl").
|
||||
-include_lib("kernel/include/file.hrl").
|
||||
|
||||
-record(state, {sockmod,
|
||||
socket,
|
||||
@@ -50,7 +48,7 @@
|
||||
request_path,
|
||||
request_auth,
|
||||
request_keepalive,
|
||||
request_content_length,
|
||||
request_content_length = 0,
|
||||
request_lang = <<"en">>,
|
||||
%% XXX bard: request handlers are configured in
|
||||
%% ejabberd.cfg under the HTTP service. For example,
|
||||
@@ -85,6 +83,10 @@
|
||||
"org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
|
||||
"">>).
|
||||
|
||||
-define(RECV_BUF, 65536).
|
||||
-define(SEND_BUF, 65536).
|
||||
-define(MAX_POST_SIZE, 20971520). %% 20Mb
|
||||
|
||||
start(SockData, Opts) ->
|
||||
{ok,
|
||||
proc_lib:spawn(ejabberd_http, init,
|
||||
@@ -113,7 +115,7 @@ init({SockMod, Socket}, Opts) ->
|
||||
end,
|
||||
TLSOpts = [verify_none | TLSOpts3],
|
||||
{SockMod1, Socket1} = if TLSEnabled ->
|
||||
inet:setopts(Socket, [{recbuf, 8192}]),
|
||||
inet:setopts(Socket, [{recbuf, ?RECV_BUF}]),
|
||||
{ok, TLSSocket} = fast_tls:tcp_to_tls(Socket,
|
||||
TLSOpts),
|
||||
{fast_tls, TLSSocket};
|
||||
@@ -168,18 +170,44 @@ become_controller(_Pid) ->
|
||||
socket_type() ->
|
||||
raw.
|
||||
|
||||
send_text(_State, none) ->
|
||||
ok;
|
||||
send_text(State, Text) ->
|
||||
case catch
|
||||
(State#state.sockmod):send(State#state.socket, Text)
|
||||
of
|
||||
ok -> ok;
|
||||
{error, timeout} ->
|
||||
?INFO_MSG("Timeout on ~p:send", [State#state.sockmod]),
|
||||
exit(normal);
|
||||
Error ->
|
||||
?DEBUG("Error in ~p:send: ~p",
|
||||
[State#state.sockmod, Error]),
|
||||
exit(normal)
|
||||
case (State#state.sockmod):send(State#state.socket, Text) of
|
||||
ok -> ok;
|
||||
{error, timeout} ->
|
||||
?INFO_MSG("Timeout on ~p:send", [State#state.sockmod]),
|
||||
exit(normal);
|
||||
Error ->
|
||||
?DEBUG("Error in ~p:send: ~p",
|
||||
[State#state.sockmod, Error]),
|
||||
exit(normal)
|
||||
end.
|
||||
|
||||
send_file(State, Fd, Size, FileName) ->
|
||||
try
|
||||
case State#state.sockmod of
|
||||
gen_tcp ->
|
||||
case file:sendfile(Fd, State#state.socket, 0, Size, []) of
|
||||
{ok, _} -> ok
|
||||
end;
|
||||
_ ->
|
||||
case file:read(Fd, ?SEND_BUF) of
|
||||
{ok, Data} ->
|
||||
send_text(State, Data),
|
||||
send_file(State, Fd, Size, FileName);
|
||||
eof ->
|
||||
ok
|
||||
end
|
||||
end
|
||||
catch _:{case_clause, {error, Why}} ->
|
||||
if Why /= closed ->
|
||||
?INFO_MSG("Failed to read ~s: ~s",
|
||||
[FileName, file_format_error(Why)]),
|
||||
exit(normal);
|
||||
true ->
|
||||
ok
|
||||
end
|
||||
end.
|
||||
|
||||
receive_headers(#state{trail = Trail} = State) ->
|
||||
@@ -348,8 +376,8 @@ get_transfer_protocol(RE, SockMod, HostPort) ->
|
||||
%% matches the requested URL path, and pass control to it. If none is
|
||||
%% found, answer with HTTP 404.
|
||||
|
||||
process([], _, _, _, _) -> ejabberd_web:error(not_found);
|
||||
process(Handlers, Request, Socket, SockMod, Trail) ->
|
||||
process([], _) -> ejabberd_web:error(not_found);
|
||||
process(Handlers, Request) ->
|
||||
{HandlerPathPrefix, HandlerModule, HandlerOpts, HandlersLeft} =
|
||||
case Handlers of
|
||||
[{Pfx, Mod} | Tail] ->
|
||||
@@ -369,14 +397,14 @@ process(Handlers, Request, Socket, SockMod, Trail) ->
|
||||
LocalPath = lists:nthtail(length(HandlerPathPrefix), Request#request.path),
|
||||
R = try
|
||||
HandlerModule:socket_handoff(
|
||||
LocalPath, Request, Socket, SockMod, Trail, HandlerOpts)
|
||||
LocalPath, Request, HandlerOpts)
|
||||
catch error:undef ->
|
||||
HandlerModule:process(LocalPath, Request)
|
||||
end,
|
||||
ejabberd_hooks:run(http_request_debug, [{LocalPath, Request}]),
|
||||
R;
|
||||
false ->
|
||||
process(HandlersLeft, Request, Socket, SockMod, Trail)
|
||||
process(HandlersLeft, Request)
|
||||
end.
|
||||
|
||||
extract_path_query(#state{request_method = Method,
|
||||
@@ -398,24 +426,29 @@ extract_path_query(#state{request_method = Method,
|
||||
extract_path_query(#state{request_method = Method,
|
||||
request_path = {abs_path, Path},
|
||||
request_content_length = Len,
|
||||
trail = Trail,
|
||||
sockmod = _SockMod,
|
||||
socket = _Socket} = State)
|
||||
when (Method =:= 'POST' orelse Method =:= 'PUT') andalso
|
||||
is_integer(Len) ->
|
||||
case recv_data(State, Len) of
|
||||
error -> {State, false};
|
||||
{NewState, Data} ->
|
||||
?DEBUG("client data: ~p~n", [Data]),
|
||||
when (Method =:= 'POST' orelse Method =:= 'PUT') andalso Len>0 ->
|
||||
case catch url_decode_q_split(Path) of
|
||||
{'EXIT', _} -> {NewState, false};
|
||||
{'EXIT', _} -> {State, false};
|
||||
{NPath, _Query} ->
|
||||
LPath = normalize_path([NPE
|
||||
|| NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
|
||||
LQuery = case catch parse_urlencoded(Data) of
|
||||
{'EXIT', _Reason} -> [];
|
||||
LQ -> LQ
|
||||
end,
|
||||
{NewState, {LPath, LQuery, Data}}
|
||||
LPath = normalize_path(
|
||||
[NPE || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
|
||||
case Method of
|
||||
'PUT' ->
|
||||
{State, {LPath, [], Trail}};
|
||||
'POST' ->
|
||||
case recv_data(State) of
|
||||
{ok, Data} ->
|
||||
LQuery = case catch parse_urlencoded(Data) of
|
||||
{'EXIT', _Reason} -> [];
|
||||
LQ -> LQ
|
||||
end,
|
||||
{State, {LPath, LQuery, Data}};
|
||||
error ->
|
||||
{State, false}
|
||||
end
|
||||
end
|
||||
end;
|
||||
extract_path_query(State) ->
|
||||
@@ -428,16 +461,23 @@ process_request(#state{request_host = undefined,
|
||||
process_request(#state{request_method = Method,
|
||||
request_auth = Auth,
|
||||
request_lang = Lang,
|
||||
request_version = Version,
|
||||
sockmod = SockMod,
|
||||
socket = Socket,
|
||||
options = Options,
|
||||
request_host = Host,
|
||||
request_port = Port,
|
||||
request_tp = TP,
|
||||
request_content_length = Length,
|
||||
request_headers = RequestHeaders,
|
||||
request_handlers = RequestHandlers,
|
||||
custom_headers = CustomHeaders,
|
||||
trail = Trail} = State) ->
|
||||
custom_headers = CustomHeaders} = State) ->
|
||||
case proplists:get_value(<<"Expect">>, RequestHeaders, <<>>) of
|
||||
<<"100-", _/binary>> when Version == {1, 1} ->
|
||||
send_text(State, <<"HTTP/1.1 100 Continue\r\n\r\n">>);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
case extract_path_query(State) of
|
||||
{State2, false} ->
|
||||
{State2, make_bad_request(State)};
|
||||
@@ -459,7 +499,10 @@ process_request(#state{request_method = Method,
|
||||
path = LPath,
|
||||
q = LQuery,
|
||||
auth = Auth,
|
||||
data = Data,
|
||||
length = Length,
|
||||
sockmod = SockMod,
|
||||
socket = Socket,
|
||||
data = Data,
|
||||
lang = Lang,
|
||||
host = Host,
|
||||
port = Port,
|
||||
@@ -469,7 +512,7 @@ process_request(#state{request_method = Method,
|
||||
ip = IP},
|
||||
RequestHandlers1 = ejabberd_hooks:run_fold(
|
||||
http_request_handlers, RequestHandlers, [Host, Request]),
|
||||
Res = case process(RequestHandlers1, Request, Socket, SockMod, Trail) of
|
||||
Res = case process(RequestHandlers1, Request) of
|
||||
El when is_record(El, xmlel) ->
|
||||
make_xhtml_output(State, 200, CustomHeaders, El);
|
||||
{Status, Headers, El}
|
||||
@@ -482,6 +525,8 @@ process_request(#state{request_method = Method,
|
||||
when is_binary(Output) or is_list(Output) ->
|
||||
make_text_output(State, Status,
|
||||
Headers ++ CustomHeaders, Output);
|
||||
{Status, Headers, {file, FileName}} ->
|
||||
make_file_output(State, Status, Headers, FileName);
|
||||
{Status, Reason, Headers, Output}
|
||||
when is_binary(Output) or is_list(Output) ->
|
||||
make_text_output(State, Status, Reason,
|
||||
@@ -489,7 +534,7 @@ process_request(#state{request_method = Method,
|
||||
_ ->
|
||||
none
|
||||
end,
|
||||
{State2, Res}
|
||||
{State2#state{trail = <<>>}, Res}
|
||||
end.
|
||||
|
||||
make_bad_request(State) ->
|
||||
@@ -519,118 +564,96 @@ analyze_ip_xff({IPLast, Port}, XFF, Host) ->
|
||||
end,
|
||||
{IPClient, Port}.
|
||||
|
||||
is_ipchain_trusted([], _) -> false;
|
||||
is_ipchain_trusted(_UserIPs, all) -> true;
|
||||
is_ipchain_trusted(UserIPs, TrustedIPs) ->
|
||||
[] == UserIPs -- [<<"127.0.0.1">> | TrustedIPs].
|
||||
is_ipchain_trusted(UserIPs, Masks) ->
|
||||
lists:all(
|
||||
fun(IP) ->
|
||||
case inet:parse_address(binary_to_list(IP)) of
|
||||
{ok, IP2} ->
|
||||
lists:any(
|
||||
fun({Mask, MaskLen}) ->
|
||||
acl:ip_matches_mask(IP2, Mask, MaskLen)
|
||||
end, [{{127,0,0,1}, 8} | Masks]);
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end, UserIPs).
|
||||
|
||||
recv_data(State, Len) -> recv_data(State, Len, <<>>).
|
||||
|
||||
recv_data(State, 0, Acc) -> {State, Acc};
|
||||
recv_data(#state{trail = Trail} = State, Len, <<>>) when byte_size(Trail) > Len ->
|
||||
<<Data:Len/binary, Rest/binary>> = Trail,
|
||||
{State#state{trail = Rest}, Data};
|
||||
recv_data(State, Len, Acc) ->
|
||||
case State#state.trail of
|
||||
<<>> ->
|
||||
case (State#state.sockmod):recv(State#state.socket,
|
||||
min(Len, 16#4000000), 300000)
|
||||
of
|
||||
{ok, Data} ->
|
||||
recv_data(State, Len - byte_size(Data), <<Acc/binary, Data/binary>>);
|
||||
Err ->
|
||||
?DEBUG("Cannot receive HTTP data: ~p", [Err]),
|
||||
error
|
||||
recv_data(#state{request_content_length = Len}) when Len >= ?MAX_POST_SIZE ->
|
||||
error;
|
||||
recv_data(#state{request_content_length = Len, trail = Trail,
|
||||
sockmod = SockMod, socket = Socket}) ->
|
||||
NewLen = Len - byte_size(Trail),
|
||||
if NewLen > 0 ->
|
||||
case SockMod:recv(Socket, NewLen, 60000) of
|
||||
{ok, Data} -> {ok, <<Trail/binary, Data/binary>>};
|
||||
{error, _} -> error
|
||||
end;
|
||||
_ ->
|
||||
Trail = (State#state.trail),
|
||||
recv_data(State#state{trail = <<>>},
|
||||
Len - byte_size(Trail), <<Acc/binary, Trail/binary>>)
|
||||
true ->
|
||||
{ok, Trail}
|
||||
end.
|
||||
|
||||
make_xhtml_output(State, Status, Headers, XHTML) ->
|
||||
Data = case lists:member(html, Headers) of
|
||||
true ->
|
||||
iolist_to_binary([?HTML_DOCTYPE,
|
||||
fxml:element_to_binary(XHTML)]);
|
||||
_ ->
|
||||
iolist_to_binary([?XHTML_DOCTYPE,
|
||||
fxml:element_to_binary(XHTML)])
|
||||
end,
|
||||
Headers1 = case lists:keysearch(<<"Content-Type">>, 1,
|
||||
Headers)
|
||||
of
|
||||
{value, _} ->
|
||||
[{<<"Content-Length">>,
|
||||
integer_to_binary(byte_size(Data))}
|
||||
| Headers];
|
||||
_ ->
|
||||
[{<<"Content-Type">>, <<"text/html; charset=utf-8">>},
|
||||
{<<"Content-Length">>,
|
||||
integer_to_binary(byte_size(Data))}
|
||||
| Headers]
|
||||
recv_file(#request{length = Len, data = Trail,
|
||||
sockmod = SockMod, socket = Socket}, Path) ->
|
||||
case file:open(Path, [write, exclusive, raw]) of
|
||||
{ok, Fd} ->
|
||||
case file:write(Fd, Trail) of
|
||||
ok ->
|
||||
NewLen = max(0, Len - byte_size(Trail)),
|
||||
case do_recv_file(NewLen, SockMod, Socket, Fd) of
|
||||
ok ->
|
||||
ok;
|
||||
{error, _} = Err ->
|
||||
file:delete(Path),
|
||||
Err
|
||||
end;
|
||||
{error, _} = Err ->
|
||||
file:delete(Path),
|
||||
Err
|
||||
end;
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end.
|
||||
|
||||
do_recv_file(0, _SockMod, _Socket, Fd) ->
|
||||
file:close(Fd);
|
||||
do_recv_file(Len, SockMod, Socket, Fd) ->
|
||||
ChunkLen = min(Len, ?RECV_BUF),
|
||||
try
|
||||
{ok, Data} = SockMod:recv(Socket, ChunkLen, timer:seconds(30)),
|
||||
ok = file:write(Fd, Data),
|
||||
do_recv_file(Len-size(Data), SockMod, Socket, Fd)
|
||||
catch _:{badmatch, {error, _} = Err} ->
|
||||
file:close(Fd),
|
||||
Err
|
||||
end.
|
||||
|
||||
make_headers(State, Status, Reason, Headers, Data) ->
|
||||
Len = if is_integer(Data) -> Data;
|
||||
true -> iolist_size(Data)
|
||||
end,
|
||||
Headers1 = [{<<"Content-Length">>, integer_to_binary(Len)} | Headers],
|
||||
Headers2 = case lists:keyfind(<<"Content-Type">>, 1, Headers) of
|
||||
{_, _} ->
|
||||
Headers1;
|
||||
false ->
|
||||
[{<<"Content-Type">>, <<"text/html; charset=utf-8">>}
|
||||
| Headers1]
|
||||
end,
|
||||
HeadersOut = case {State#state.request_version,
|
||||
State#state.request_keepalive}
|
||||
of
|
||||
{{1, 1}, true} -> Headers1;
|
||||
{_, true} ->
|
||||
[{<<"Connection">>, <<"keep-alive">>} | Headers1];
|
||||
{_, false} ->
|
||||
[{<<"Connection">>, <<"close">>} | Headers1]
|
||||
State#state.request_keepalive} of
|
||||
{{1, 1}, true} -> Headers2;
|
||||
{_, true} ->
|
||||
[{<<"Connection">>, <<"keep-alive">>} | Headers2];
|
||||
{_, false} ->
|
||||
[{<<"Connection">>, <<"close">>} | Headers2]
|
||||
end,
|
||||
Version = case State#state.request_version of
|
||||
{1, 1} -> <<"HTTP/1.1 ">>;
|
||||
_ -> <<"HTTP/1.0 ">>
|
||||
{1, 1} -> <<"HTTP/1.1 ">>;
|
||||
_ -> <<"HTTP/1.0 ">>
|
||||
end,
|
||||
H = lists:map(fun ({Attr, Val}) ->
|
||||
[Attr, <<": ">>, Val, <<"\r\n">>];
|
||||
(_) -> []
|
||||
end,
|
||||
HeadersOut),
|
||||
SL = [Version,
|
||||
integer_to_binary(Status), <<" ">>,
|
||||
code_to_phrase(Status), <<"\r\n">>],
|
||||
Data2 = case State#state.request_method of
|
||||
'HEAD' -> <<"">>;
|
||||
_ -> Data
|
||||
end,
|
||||
[SL, H, <<"\r\n">>, Data2].
|
||||
|
||||
make_text_output(State, Status, Headers, Text) ->
|
||||
make_text_output(State, Status, <<"">>, Headers, Text).
|
||||
|
||||
make_text_output(State, Status, Reason, Headers, Text) ->
|
||||
Data = iolist_to_binary(Text),
|
||||
Headers1 = case lists:keysearch(<<"Content-Type">>, 1,
|
||||
Headers)
|
||||
of
|
||||
{value, _} ->
|
||||
[{<<"Content-Length">>,
|
||||
integer_to_binary(byte_size(Data))}
|
||||
| Headers];
|
||||
_ ->
|
||||
[{<<"Content-Type">>, <<"text/html; charset=utf-8">>},
|
||||
{<<"Content-Length">>,
|
||||
integer_to_binary(byte_size(Data))}
|
||||
| Headers]
|
||||
end,
|
||||
HeadersOut = case {State#state.request_version,
|
||||
State#state.request_keepalive}
|
||||
of
|
||||
{{1, 1}, true} -> Headers1;
|
||||
{_, true} ->
|
||||
[{<<"Connection">>, <<"keep-alive">>} | Headers1];
|
||||
{_, false} ->
|
||||
[{<<"Connection">>, <<"close">>} | Headers1]
|
||||
end,
|
||||
Version = case State#state.request_version of
|
||||
{1, 1} -> <<"HTTP/1.1 ">>;
|
||||
_ -> <<"HTTP/1.0 ">>
|
||||
end,
|
||||
H = lists:map(fun ({Attr, Val}) ->
|
||||
[Attr, <<": ">>, Val, <<"\r\n">>]
|
||||
end,
|
||||
HeadersOut),
|
||||
H = [[Attr, <<": ">>, Val, <<"\r\n">>] || {Attr, Val} <- HeadersOut],
|
||||
NewReason = case Reason of
|
||||
<<"">> -> code_to_phrase(Status);
|
||||
_ -> Reason
|
||||
@@ -638,11 +661,55 @@ make_text_output(State, Status, Reason, Headers, Text) ->
|
||||
SL = [Version,
|
||||
integer_to_binary(Status), <<" ">>,
|
||||
NewReason, <<"\r\n">>],
|
||||
[SL, H, <<"\r\n">>].
|
||||
|
||||
make_xhtml_output(State, Status, Headers, XHTML) ->
|
||||
Data = case State#state.request_method of
|
||||
'HEAD' -> <<"">>;
|
||||
_ ->
|
||||
DocType = case lists:member(html, Headers) of
|
||||
true -> ?HTML_DOCTYPE;
|
||||
false -> ?XHTML_DOCTYPE
|
||||
end,
|
||||
iolist_to_binary([DocType, fxml:element_to_binary(XHTML)])
|
||||
end,
|
||||
EncodedHdrs = make_headers(State, Status, <<"">>, Headers, Data),
|
||||
[EncodedHdrs, Data].
|
||||
|
||||
make_text_output(State, Status, Headers, Text) ->
|
||||
make_text_output(State, Status, <<"">>, Headers, Text).
|
||||
|
||||
make_text_output(State, Status, Reason, Headers, Text) ->
|
||||
Data = iolist_to_binary(Text),
|
||||
Data2 = case State#state.request_method of
|
||||
'HEAD' -> <<"">>;
|
||||
_ -> Data
|
||||
'HEAD' -> <<"">>;
|
||||
_ -> Data
|
||||
end,
|
||||
[SL, H, <<"\r\n">>, Data2].
|
||||
EncodedHdrs = make_headers(State, Status, Reason, Headers, Data2),
|
||||
[EncodedHdrs, Data2].
|
||||
|
||||
make_file_output(State, Status, Headers, FileName) ->
|
||||
case file:read_file_info(FileName) of
|
||||
{ok, #file_info{size = Size}} when State#state.request_method == 'HEAD' ->
|
||||
make_headers(State, Status, <<"">>, Headers, Size);
|
||||
{ok, #file_info{size = Size}} ->
|
||||
case file:open(FileName, [raw, read]) of
|
||||
{ok, Fd} ->
|
||||
EncodedHdrs = make_headers(State, Status, <<"">>, Headers, Size),
|
||||
send_text(State, EncodedHdrs),
|
||||
send_file(State, Fd, Size, FileName),
|
||||
file:close(Fd),
|
||||
none;
|
||||
{error, Why} ->
|
||||
Reason = file_format_error(Why),
|
||||
?ERROR_MSG("Failed to open ~s: ~s", [FileName, Reason]),
|
||||
make_text_output(State, 404, Reason, [], <<>>)
|
||||
end;
|
||||
{error, Why} ->
|
||||
Reason = file_format_error(Why),
|
||||
?ERROR_MSG("Failed to read info of ~s: ~s", [FileName, Reason]),
|
||||
make_text_output(State, 404, Reason, [], <<>>)
|
||||
end.
|
||||
|
||||
parse_lang(Langs) ->
|
||||
case str:tokens(Langs, <<",; ">>) of
|
||||
@@ -650,6 +717,12 @@ parse_lang(Langs) ->
|
||||
[] -> <<"en">>
|
||||
end.
|
||||
|
||||
file_format_error(Reason) ->
|
||||
case file:format_error(Reason) of
|
||||
"unknown POSIX error" -> atom_to_list(Reason);
|
||||
Text -> Text
|
||||
end.
|
||||
|
||||
% Code below is taken (with some modifications) from the yaws webserver, which
|
||||
% is distributed under the following license:
|
||||
%
|
||||
@@ -679,7 +752,7 @@ url_decode_q_split(<<>>, Ack) ->
|
||||
path_decode(Path) -> path_decode(Path, <<>>).
|
||||
|
||||
path_decode(<<$%, Hi, Lo, Tail/binary>>, Acc) ->
|
||||
Hex = hex_to_integer([Hi, Lo]),
|
||||
Hex = list_to_integer([Hi, Lo], 16),
|
||||
if Hex == 0 -> exit(badurl);
|
||||
true -> ok
|
||||
end,
|
||||
@@ -713,25 +786,10 @@ rest_dir(N, Path, <<_H, T/binary>>) -> rest_dir(N, Path, T).
|
||||
|
||||
expand_custom_headers(Headers) ->
|
||||
lists:map(fun({K, V}) ->
|
||||
{K, misc:expand_keyword(<<"@VERSION@">>, V, ?VERSION)}
|
||||
{K, misc:expand_keyword(<<"@VERSION@">>, V,
|
||||
ejabberd_config:get_version())}
|
||||
end, Headers).
|
||||
|
||||
%% hex_to_integer
|
||||
|
||||
hex_to_integer(Hex) ->
|
||||
case catch list_to_integer(Hex, 16) of
|
||||
{'EXIT', _} -> old_hex_to_integer(Hex);
|
||||
X -> X
|
||||
end.
|
||||
|
||||
old_hex_to_integer(Hex) ->
|
||||
DEHEX = fun (H) when H >= $a, H =< $f -> H - $a + 10;
|
||||
(H) when H >= $A, H =< $F -> H - $A + 10;
|
||||
(H) when H >= $0, H =< $9 -> H - $0
|
||||
end,
|
||||
lists:foldl(fun (E, Acc) -> Acc * 16 + DEHEX(E) end, 0,
|
||||
Hex).
|
||||
|
||||
code_to_phrase(100) -> <<"Continue">>;
|
||||
code_to_phrase(101) -> <<"Switching Protocols ">>;
|
||||
code_to_phrase(200) -> <<"OK">>;
|
||||
@@ -802,7 +860,7 @@ parse_urlencoded(S) ->
|
||||
|
||||
parse_urlencoded(<<$%, Hi, Lo, Tail/binary>>, Last, Cur,
|
||||
State) ->
|
||||
Hex = hex_to_integer([Hi, Lo]),
|
||||
Hex = list_to_integer([Hi, Lo], 16),
|
||||
parse_urlencoded(Tail, Last, <<Cur/binary, Hex>>, State);
|
||||
parse_urlencoded(<<$&, Tail/binary>>, _Last, Cur, key) ->
|
||||
[{Cur, <<"">>} | parse_urlencoded(Tail,
|
||||
@@ -822,41 +880,6 @@ parse_urlencoded(<<>>, Last, Cur, _State) ->
|
||||
[{Last, Cur}];
|
||||
parse_urlencoded(undefined, _, _, _) -> [].
|
||||
|
||||
|
||||
url_encode(A) ->
|
||||
url_encode(A, <<>>).
|
||||
|
||||
url_encode(<<H:8, T/binary>>, Acc) when
|
||||
(H >= $a andalso H =< $z) orelse
|
||||
(H >= $A andalso H =< $Z) orelse
|
||||
(H >= $0 andalso H =< $9) orelse
|
||||
H == $_ orelse
|
||||
H == $. orelse
|
||||
H == $- orelse
|
||||
H == $/ orelse
|
||||
H == $: ->
|
||||
url_encode(T, <<Acc/binary, H>>);
|
||||
url_encode(<<H:8, T/binary>>, Acc) ->
|
||||
case integer_to_hex(H) of
|
||||
[X, Y] -> url_encode(T, <<Acc/binary, $%, X, Y>>);
|
||||
[X] -> url_encode(T, <<Acc/binary, $%, $0, X>>)
|
||||
end;
|
||||
url_encode(<<>>, Acc) ->
|
||||
Acc.
|
||||
|
||||
|
||||
integer_to_hex(I) ->
|
||||
case catch erlang:integer_to_list(I, 16) of
|
||||
{'EXIT', _} -> old_integer_to_hex(I);
|
||||
Int -> Int
|
||||
end.
|
||||
|
||||
old_integer_to_hex(I) when I < 10 -> integer_to_list(I);
|
||||
old_integer_to_hex(I) when I < 16 -> [I - 10 + $A];
|
||||
old_integer_to_hex(I) when I >= 16 ->
|
||||
N = trunc(I / 16),
|
||||
old_integer_to_hex(N) ++ old_integer_to_hex(I rem 16).
|
||||
|
||||
% The following code is mostly taken from yaws_ssl.erl
|
||||
|
||||
toupper(C) when C >= $a andalso C =< $z -> C - 32;
|
||||
@@ -894,11 +917,11 @@ get_certfile(Opts) ->
|
||||
{_, CertFile} ->
|
||||
CertFile;
|
||||
false ->
|
||||
case ejabberd_pkix:get_certfile(?MYNAME) of
|
||||
case ejabberd_pkix:get_certfile(ejabberd_config:get_myname()) of
|
||||
{ok, CertFile} ->
|
||||
CertFile;
|
||||
error ->
|
||||
ejabberd_config:get_option({domain_certfile, ?MYNAME})
|
||||
ejabberd_config:get_option({domain_certfile, ejabberd_config:get_myname()})
|
||||
end
|
||||
end.
|
||||
|
||||
@@ -928,7 +951,14 @@ transform_listen_option(Opt, Opts) ->
|
||||
(atom()) -> [atom()].
|
||||
opt_type(trusted_proxies) ->
|
||||
fun (all) -> all;
|
||||
(TPs) -> [iolist_to_binary(TP) || TP <- TPs] end;
|
||||
(TPs) -> lists:filtermap(
|
||||
fun(TP) ->
|
||||
case acl:parse_ip_netmask(iolist_to_binary(TP)) of
|
||||
{ok, Ip, Mask} -> {true, {Ip, Mask}};
|
||||
_ -> false
|
||||
end
|
||||
end, TPs)
|
||||
end;
|
||||
opt_type(_) -> [trusted_proxies].
|
||||
|
||||
-spec listen_opt_type(tls) -> fun((boolean()) -> boolean());
|
||||
@@ -998,6 +1028,8 @@ listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(backlog) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(_) ->
|
||||
%% TODO
|
||||
fun(A) -> A end.
|
||||
|
||||
@@ -35,9 +35,8 @@
|
||||
terminate/3, send_xml/2, setopts/2, sockname/1,
|
||||
peername/1, controlling_process/2, become_controller/2,
|
||||
monitor/1, reset_stream/1, close/1, change_shaper/2,
|
||||
socket_handoff/6, opt_type/1]).
|
||||
socket_handoff/3, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
@@ -121,9 +120,8 @@ change_shaper({http_ws, _FsmRef, _IP}, _Shaper) ->
|
||||
%% TODO???
|
||||
ok.
|
||||
|
||||
socket_handoff(LocalPath, Request, Socket, SockMod, Buf, Opts) ->
|
||||
ejabberd_websocket:socket_handoff(LocalPath, Request, Socket, SockMod,
|
||||
Buf, Opts, ?MODULE, fun get_human_html_xmlel/0).
|
||||
socket_handoff(LocalPath, Request, Opts) ->
|
||||
ejabberd_websocket:socket_handoff(LocalPath, Request, Opts, ?MODULE, fun get_human_html_xmlel/0).
|
||||
|
||||
%%% Internal
|
||||
|
||||
@@ -134,14 +132,15 @@ init([{#ws{ip = IP, http_opts = HOpts}, _} = WS]) ->
|
||||
({resume_timeout, _}) -> true;
|
||||
({max_resume_timeout, _}) -> true;
|
||||
({resend_on_timeout, _}) -> true;
|
||||
({access, _}) -> true;
|
||||
(_) -> false
|
||||
end, HOpts),
|
||||
Opts = ejabberd_c2s_config:get_c2s_limits() ++ SOpts,
|
||||
PingInterval = ejabberd_config:get_option(
|
||||
{websocket_ping_interval, ?MYNAME},
|
||||
{websocket_ping_interval, ejabberd_config:get_myname()},
|
||||
?PING_INTERVAL) * 1000,
|
||||
WSTimeout = ejabberd_config:get_option(
|
||||
{websocket_timeout, ?MYNAME},
|
||||
{websocket_timeout, ejabberd_config:get_myname()},
|
||||
?WEBSOCKET_TIMEOUT) * 1000,
|
||||
Socket = {http_ws, self(), IP},
|
||||
?DEBUG("Client connected through websocket ~p",
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
add_listener/3, delete_listener/2, transform_options/1,
|
||||
validate_cfg/1, opt_type/1, config_reloaded/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%% We do not block on send anymore.
|
||||
@@ -256,36 +255,7 @@ get_ip_tuple(IPOpt, _IPVOpt) ->
|
||||
IPOpt.
|
||||
|
||||
accept(ListenSocket, Module, Opts) ->
|
||||
IntervalOpt =
|
||||
case proplists:get_value(accept_interval, Opts) of
|
||||
[{linear, [I1_, T1_, T2_, I2_]}] ->
|
||||
{linear, I1_, T1_, T2_, I2_};
|
||||
I_ -> I_
|
||||
end,
|
||||
Interval =
|
||||
case IntervalOpt of
|
||||
undefined ->
|
||||
0;
|
||||
I when is_integer(I), I >= 0 ->
|
||||
I;
|
||||
{linear, I1, T1, T2, I2}
|
||||
when is_integer(I1),
|
||||
is_integer(T1),
|
||||
is_integer(T2),
|
||||
is_integer(I2),
|
||||
I1 >= 0,
|
||||
I2 >= 0,
|
||||
T2 > 0 ->
|
||||
{MSec, Sec, _USec} = os:timestamp(),
|
||||
TS = MSec * 1000000 + Sec,
|
||||
{linear, I1, TS + T1, T2, I2};
|
||||
I ->
|
||||
?WARNING_MSG("There is a problem in the configuration: "
|
||||
"~p is a wrong accept_interval value. "
|
||||
"Using 0 as fallback",
|
||||
[I]),
|
||||
0
|
||||
end,
|
||||
Interval = proplists:get_value(accept_interval, Opts, 0),
|
||||
accept(ListenSocket, Module, Opts, Interval).
|
||||
|
||||
accept(ListenSocket, Module, Opts, Interval) ->
|
||||
|
||||
+6
-59
@@ -32,10 +32,8 @@
|
||||
%% API
|
||||
-export([start/0, start_link/0]).
|
||||
|
||||
-export([route/1, process_iq/1,
|
||||
-export([route/1,
|
||||
get_features/1,
|
||||
register_iq_handler/4,
|
||||
unregister_iq_handler/2,
|
||||
bounce_resource_packet/1,
|
||||
host_up/1, host_down/1]).
|
||||
|
||||
@@ -47,15 +45,12 @@
|
||||
-export([route_iq/2, route_iq/3]).
|
||||
-deprecated([{route_iq, 2}, {route_iq, 3}]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
-include("xmpp.hrl").
|
||||
|
||||
-record(state, {}).
|
||||
|
||||
-define(IQTABLE, local_iqtable).
|
||||
|
||||
%%====================================================================
|
||||
%% API
|
||||
%%====================================================================
|
||||
@@ -72,30 +67,6 @@ start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
|
||||
[]).
|
||||
|
||||
-spec process_iq(iq()) -> any().
|
||||
process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
|
||||
when T == get; T == set ->
|
||||
XMLNS = xmpp:get_ns(El),
|
||||
Host = To#jid.lserver,
|
||||
case ets:lookup(?IQTABLE, {Host, XMLNS}) of
|
||||
[{_, Module, Function}] ->
|
||||
gen_iq_handler:handle(Host, Module, Function, Packet);
|
||||
[] ->
|
||||
Txt = <<"No module is handling this query">>,
|
||||
Err = xmpp:err_service_unavailable(Txt, Lang),
|
||||
ejabberd_router:route_error(Packet, Err)
|
||||
end;
|
||||
process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
|
||||
when T == get; T == set ->
|
||||
Txt = case SubEls of
|
||||
[] -> <<"No child elements found">>;
|
||||
_ -> <<"Too many child elements">>
|
||||
end,
|
||||
Err = xmpp:err_bad_request(Txt, Lang),
|
||||
ejabberd_router:route_error(Packet, Err);
|
||||
process_iq(#iq{type = T}) when T == result; T == error ->
|
||||
ok.
|
||||
|
||||
-spec route(stanza()) -> any().
|
||||
route(Packet) ->
|
||||
try do_route(Packet)
|
||||
@@ -112,15 +83,6 @@ route_iq(IQ, Fun) ->
|
||||
route_iq(IQ, Fun, Timeout) ->
|
||||
ejabberd_router:route_iq(IQ, Fun, undefined, Timeout).
|
||||
|
||||
-spec register_iq_handler(binary(), binary(), module(), function()) -> ok.
|
||||
register_iq_handler(Host, XMLNS, Module, Fun) ->
|
||||
gen_server:cast(?MODULE,
|
||||
{register_iq_handler, Host, XMLNS, Module, Fun}).
|
||||
|
||||
-spec unregister_iq_handler(binary(), binary()) -> ok.
|
||||
unregister_iq_handler(Host, XMLNS) ->
|
||||
gen_server:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}).
|
||||
|
||||
-spec bounce_resource_packet(stanza()) -> ok | stop.
|
||||
bounce_resource_packet(#presence{to = #jid{lresource = <<"">>}}) ->
|
||||
ok;
|
||||
@@ -135,12 +97,7 @@ bounce_resource_packet(Packet) ->
|
||||
|
||||
-spec get_features(binary()) -> [binary()].
|
||||
get_features(Host) ->
|
||||
get_features(ets:next(?IQTABLE, {Host, <<"">>}), Host, []).
|
||||
|
||||
get_features({Host, XMLNS}, Host, XMLNSs) ->
|
||||
get_features(ets:next(?IQTABLE, {Host, XMLNS}), Host, [XMLNS|XMLNSs]);
|
||||
get_features(_, _, XMLNSs) ->
|
||||
XMLNSs.
|
||||
gen_iq_handler:get_features(?MODULE, Host).
|
||||
|
||||
%%====================================================================
|
||||
%% gen_server callbacks
|
||||
@@ -148,26 +105,16 @@ get_features(_, _, XMLNSs) ->
|
||||
|
||||
init([]) ->
|
||||
process_flag(trap_exit, true),
|
||||
lists:foreach(fun host_up/1, ?MYHOSTS),
|
||||
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
|
||||
ejabberd_hooks:add(host_up, ?MODULE, host_up, 10),
|
||||
ejabberd_hooks:add(host_down, ?MODULE, host_down, 100),
|
||||
catch ets:new(?IQTABLE, [named_table, public, ordered_set,
|
||||
{read_concurrency, true}]),
|
||||
gen_iq_handler:start(?MODULE),
|
||||
update_table(),
|
||||
{ok, #state{}}.
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
Reply = ok, {reply, Reply, State}.
|
||||
|
||||
handle_cast({register_iq_handler, Host, XMLNS, Module, Function},
|
||||
State) ->
|
||||
ets:insert(?IQTABLE,
|
||||
{{Host, XMLNS}, Module, Function}),
|
||||
{noreply, State};
|
||||
handle_cast({unregister_iq_handler, Host, XMLNS},
|
||||
State) ->
|
||||
ets:delete(?IQTABLE, {Host, XMLNS}),
|
||||
{noreply, State};
|
||||
handle_cast(_Msg, State) -> {noreply, State}.
|
||||
|
||||
handle_info({route, Packet}, State) ->
|
||||
@@ -178,7 +125,7 @@ handle_info(Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
lists:foreach(fun host_down/1, ?MYHOSTS),
|
||||
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()),
|
||||
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 10),
|
||||
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 100),
|
||||
ok.
|
||||
@@ -197,7 +144,7 @@ do_route(Packet) ->
|
||||
if To#jid.luser /= <<"">> ->
|
||||
ejabberd_sm:route(Packet);
|
||||
is_record(Packet, iq), To#jid.lresource == <<"">> ->
|
||||
process_iq(Packet);
|
||||
gen_iq_handler:handle(?MODULE, Packet);
|
||||
Type == result; Type == error ->
|
||||
ok;
|
||||
true ->
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
-export([start/0, restart/0, reopen_log/0, rotate_log/0, get/0, set/1,
|
||||
get_log_path/0, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
-type loglevel() :: 0 | 1 | 2 | 3 | 4 | 5.
|
||||
|
||||
@@ -59,7 +58,7 @@ get_log_path() ->
|
||||
undefined ->
|
||||
case os:getenv("EJABBERD_LOG_PATH") of
|
||||
false ->
|
||||
?LOG_PATH;
|
||||
"ejabberd.log";
|
||||
Path ->
|
||||
Path
|
||||
end
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
|
||||
-include("xmpp.hrl").
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
@@ -34,13 +34,12 @@
|
||||
clean/1,
|
||||
opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_oauth.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("jid.hrl").
|
||||
|
||||
init() ->
|
||||
rest:start(?MYNAME),
|
||||
rest:start(ejabberd_config:get_myname()),
|
||||
ok.
|
||||
|
||||
store(R) ->
|
||||
@@ -50,7 +49,7 @@ store(R) ->
|
||||
SJID = jid:encode({User, Server, <<"">>}),
|
||||
case rest:with_retry(
|
||||
post,
|
||||
[?MYNAME, Path, [],
|
||||
[ejabberd_config:get_myname(), Path, [],
|
||||
{[{<<"token">>, R#oauth_token.token},
|
||||
{<<"user">>, SJID},
|
||||
{<<"scope">>, R#oauth_token.scope},
|
||||
@@ -65,7 +64,7 @@ store(R) ->
|
||||
|
||||
lookup(Token) ->
|
||||
Path = path(<<"lookup">>),
|
||||
case rest:with_retry(post, [?MYNAME, Path, [],
|
||||
case rest:with_retry(post, [ejabberd_config:get_myname(), Path, [],
|
||||
{[{<<"token">>, Token}]}],
|
||||
2, 500) of
|
||||
{ok, 200, {Data}} ->
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
clean/1]).
|
||||
|
||||
-include("ejabberd_oauth.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
-include("jid.hrl").
|
||||
-include("logger.hrl").
|
||||
@@ -49,7 +48,7 @@ store(R) ->
|
||||
Scope = str:join(R#oauth_token.scope, <<" ">>),
|
||||
Expire = R#oauth_token.expire,
|
||||
case ?SQL_UPSERT(
|
||||
?MYNAME,
|
||||
ejabberd_config:get_myname(),
|
||||
"oauth_token",
|
||||
["!token=%(Token)s",
|
||||
"jid=%(SJID)s",
|
||||
@@ -63,7 +62,7 @@ store(R) ->
|
||||
|
||||
lookup(Token) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
?MYNAME,
|
||||
ejabberd_config:get_myname(),
|
||||
?SQL("select @(jid)s, @(scope)s, @(expire)d"
|
||||
" from oauth_token where token=%(Token)s")) of
|
||||
{selected, [{SJID, Scope, Expire}]} ->
|
||||
@@ -79,6 +78,6 @@ lookup(Token) ->
|
||||
|
||||
clean(TS) ->
|
||||
ejabberd_sql:sql_query(
|
||||
?MYNAME,
|
||||
ejabberd_config:get_myname(),
|
||||
?SQL("delete from oauth_token where expire < %(TS)d")).
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
-define(CHUNK_SIZE, 1024*20). %20k
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("scram.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("mod_privacy.hrl").
|
||||
@@ -92,7 +92,7 @@ import_file(FileName, State) ->
|
||||
|
||||
-spec export_server(binary()) -> any().
|
||||
export_server(Dir) ->
|
||||
export_hosts(?MYHOSTS, Dir).
|
||||
export_hosts(ejabberd_config:get_myhosts(), Dir).
|
||||
|
||||
-spec export_host(binary(), binary()) -> any().
|
||||
export_host(Dir, Host) ->
|
||||
@@ -404,6 +404,8 @@ process_user(#xmlel{name = <<"user">>, attrs = Attrs, children = Els},
|
||||
case ejabberd_auth:try_register(LUser, LServer, Pass) of
|
||||
ok ->
|
||||
process_user_els(Els, State#state{user = LUser});
|
||||
{error, invalid_password} when (Password == <<>>) ->
|
||||
process_user_els(Els, State#state{user = LUser});
|
||||
{error, Err} ->
|
||||
stop("Failed to create user '~s': ~p", [Name, Err])
|
||||
end
|
||||
|
||||
+161
-86
@@ -49,9 +49,10 @@
|
||||
-type bad_cert_reason() :: cert_expired | invalid_issuer | invalid_signature |
|
||||
name_not_permitted | missing_basic_constraint |
|
||||
invalid_key_usage | selfsigned_peer | unknown_sig_algo |
|
||||
unknown_ca | missing_priv_key.
|
||||
-type bad_cert() :: {bad_cert, bad_cert_reason()}.
|
||||
-type cert_error() :: not_cert | not_der | not_pem | encrypted.
|
||||
unknown_ca | missing_priv_key | unknown_key_algo |
|
||||
unknown_key_type | encrypted | not_der | not_cert |
|
||||
not_pem.
|
||||
-type cert_error() :: {bad_cert, bad_cert_reason()}.
|
||||
-export_type([cert_error/0]).
|
||||
|
||||
-define(CA_CACHE, ca_cache).
|
||||
@@ -76,13 +77,13 @@ route_registered(Route) ->
|
||||
gen_server:call(?MODULE, {route_registered, Route}).
|
||||
|
||||
-spec format_error(cert_error() | file:posix()) -> string().
|
||||
format_error(not_cert) ->
|
||||
format_error({bad_cert, not_cert}) ->
|
||||
"no PEM encoded certificates found";
|
||||
format_error(not_pem) ->
|
||||
format_error({bad_cert, not_pem}) ->
|
||||
"failed to decode from PEM format";
|
||||
format_error(not_der) ->
|
||||
format_error({bad_cert, not_der}) ->
|
||||
"failed to decode from DER format";
|
||||
format_error(encrypted) ->
|
||||
format_error({bad_cert, encrypted}) ->
|
||||
"encrypted certificate";
|
||||
format_error({bad_cert, cert_expired}) ->
|
||||
"certificate is no longer valid as its expiration date has passed";
|
||||
@@ -103,6 +104,10 @@ format_error({bad_cert, selfsigned_peer}) ->
|
||||
"self-signed certificate";
|
||||
format_error({bad_cert, unknown_sig_algo}) ->
|
||||
"certificate is signed using unknown algorithm";
|
||||
format_error({bad_cert, unknown_key_algo}) ->
|
||||
"unknown private key algorithm";
|
||||
format_error({bad_cert, unknown_key_type}) ->
|
||||
"private key is of unknown type";
|
||||
format_error({bad_cert, unknown_ca}) ->
|
||||
"certificate is signed by unknown CA";
|
||||
format_error({bad_cert, missing_priv_key}) ->
|
||||
@@ -172,6 +177,7 @@ config_reloaded() ->
|
||||
true -> init_cache();
|
||||
false -> delete_cache()
|
||||
end,
|
||||
fast_tls:clear_cache(),
|
||||
gen_server:call(?MODULE, config_reloaded, 60000).
|
||||
|
||||
opt_type(ca_path) ->
|
||||
@@ -328,7 +334,8 @@ get_certfiles_from_config_options(_State) ->
|
||||
Host <- ejabberd_config:get_myhosts()]),
|
||||
[iolist_to_binary(P) || P <- lists:usort(Local ++ Global)].
|
||||
|
||||
-spec add_certfiles(state()) -> {ok, state()} | {error, bad_cert()}.
|
||||
-spec add_certfiles(state()) -> {ok, state()} |
|
||||
{error, cert_error() | file:posix()}.
|
||||
add_certfiles(State) ->
|
||||
?DEBUG("Reading certificates", []),
|
||||
Paths = get_certfiles_from_config_options(State),
|
||||
@@ -342,7 +349,8 @@ add_certfiles(State) ->
|
||||
{error, _} = Err -> Err
|
||||
end.
|
||||
|
||||
-spec add_certfiles(binary(), state()) -> {ok, state()} | {error, bad_cert()}.
|
||||
-spec add_certfiles(binary(), state()) -> {ok, state()} |
|
||||
{error, cert_error() | file:posix()}.
|
||||
add_certfiles(Host, State) ->
|
||||
State1 = lists:foldl(
|
||||
fun(Opt, AccState) ->
|
||||
@@ -362,8 +370,8 @@ add_certfiles(Host, State) ->
|
||||
{ok, State}
|
||||
end.
|
||||
|
||||
-spec add_certfile(file:filename_all(), state()) -> {ok, state()} |
|
||||
{{error, cert_error()}, state()}.
|
||||
-spec add_certfile(file:filename_all(), state()) ->
|
||||
{ok, state()} | {{error, cert_error() | file:posix()}, state()}.
|
||||
add_certfile(Path, State) ->
|
||||
case lists:member(Path, State#state.paths) of
|
||||
true ->
|
||||
@@ -385,30 +393,14 @@ add_certfile(Path, State) ->
|
||||
end
|
||||
end.
|
||||
|
||||
-spec build_chain_and_check(state()) -> ok | {error, bad_cert()}.
|
||||
-spec build_chain_and_check(state()) -> ok | {error, cert_error() | file:posix()}.
|
||||
build_chain_and_check(State) ->
|
||||
?DEBUG("Building certificates graph", []),
|
||||
CertPaths = get_cert_paths(maps:keys(State#state.certs), State#state.graph),
|
||||
?DEBUG("Finding matched certificate keys", []),
|
||||
case match_cert_keys(CertPaths, State#state.keys) of
|
||||
{ok, Chains} ->
|
||||
?DEBUG("Storing certificate chains", []),
|
||||
CertFilesWithDomains = store_certs(Chains, []),
|
||||
ets:delete_all_objects(?MODULE),
|
||||
lists:foreach(
|
||||
fun({Path, Domain}) ->
|
||||
fast_tls:add_certfile(Domain, Path),
|
||||
ets:insert(?MODULE, {Domain, Path})
|
||||
end, CertFilesWithDomains),
|
||||
?DEBUG("Validating certificates", []),
|
||||
Errors = validate(CertPaths, State#state.validate),
|
||||
?DEBUG("Subscribing to file events", []),
|
||||
lists:foreach(
|
||||
fun({Cert, Why}) ->
|
||||
Path = maps:get(Cert, State#state.certs),
|
||||
?WARNING_MSG("Failed to validate certificate from ~s: ~s",
|
||||
[Path, format_error(Why)])
|
||||
end, Errors);
|
||||
InvalidCerts = validate(CertPaths, State),
|
||||
SortedChains = sort_chains(Chains, InvalidCerts),
|
||||
store_certs(SortedChains, State);
|
||||
{error, Cert, Why} ->
|
||||
Path = maps:get(Cert, State#state.certs),
|
||||
?ERROR_MSG("Failed to build certificate chain for ~s: ~s",
|
||||
@@ -416,9 +408,35 @@ build_chain_and_check(State) ->
|
||||
{error, Why}
|
||||
end.
|
||||
|
||||
-spec store_certs([{[cert()], priv_key()}],
|
||||
[{binary(), binary()}]) -> [{binary(), binary()}].
|
||||
store_certs([{Certs, Key}|Chains], Acc) ->
|
||||
-spec store_certs([{[cert()], priv_key()}], state()) -> ok | {error, file:posix()}.
|
||||
store_certs(Chains, State) ->
|
||||
?DEBUG("Storing certificate chains", []),
|
||||
Res = lists:foldl(
|
||||
fun(_, {error, _} = Err) ->
|
||||
Err;
|
||||
({Certs, Key}, Acc) ->
|
||||
case store_cert(Certs, Key, State) of
|
||||
{ok, FileDoms} ->
|
||||
Acc ++ FileDoms;
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end
|
||||
end, [], Chains),
|
||||
case Res of
|
||||
{error, Why} ->
|
||||
{error, Why};
|
||||
FileDomains ->
|
||||
ets:delete_all_objects(?MODULE),
|
||||
lists:foreach(
|
||||
fun({Path, Domain}) ->
|
||||
fast_tls:add_certfile(Domain, Path),
|
||||
ets:insert(?MODULE, {Domain, Path})
|
||||
end, FileDomains)
|
||||
end.
|
||||
|
||||
-spec store_cert([cert()], priv_key(), state()) -> {ok, [{binary(), binary()}]} |
|
||||
{error, file:posix()}.
|
||||
store_cert(Certs, Key, State) ->
|
||||
CertPEMs = public_key:pem_encode(
|
||||
lists:map(
|
||||
fun(Cert) ->
|
||||
@@ -432,20 +450,51 @@ store_certs([{Certs, Key}|Chains], Acc) ->
|
||||
not_encrypted}]),
|
||||
PEMs = <<CertPEMs/binary, KeyPEM/binary>>,
|
||||
Cert = hd(Certs),
|
||||
Domains = xmpp_stream_pkix:get_cert_domains(Cert),
|
||||
FileName = filename:join(certs_dir(), str:sha(PEMs)),
|
||||
case file:write_file(FileName, PEMs) of
|
||||
ok ->
|
||||
file:change_mode(FileName, 8#600),
|
||||
NewAcc = [{FileName, Domain} || Domain <- Domains] ++ Acc,
|
||||
store_certs(Chains, NewAcc);
|
||||
{error, Why} ->
|
||||
case xmpp_stream_pkix:get_cert_domains(Cert) of
|
||||
[] ->
|
||||
Path = maps:get(Cert, State#state.certs),
|
||||
?WARNING_MSG("Certificate from ~s doesn't define "
|
||||
"any domain names", [Path]),
|
||||
{ok, [{FileName, <<"">>}]};
|
||||
Domains ->
|
||||
{ok, [{FileName, Domain} || Domain <- Domains]}
|
||||
end;
|
||||
{error, Why} = Err ->
|
||||
?ERROR_MSG("Failed to write to ~s: ~s",
|
||||
[FileName, file:format_error(Why)]),
|
||||
store_certs(Chains, [])
|
||||
end;
|
||||
store_certs([], Acc) ->
|
||||
Acc.
|
||||
Err
|
||||
end.
|
||||
|
||||
-spec sort_chains([{[cert()], priv_key()}], [cert()]) -> [{[cert()], priv_key()}].
|
||||
sort_chains(Chains, InvalidCerts) ->
|
||||
lists:sort(
|
||||
fun({[Cert1|_], _}, {[Cert2|_], _}) ->
|
||||
IsValid1 = not lists:member(Cert1, InvalidCerts),
|
||||
IsValid2 = not lists:member(Cert2, InvalidCerts),
|
||||
if IsValid1 and not IsValid2 ->
|
||||
false;
|
||||
IsValid2 and not IsValid1 ->
|
||||
true;
|
||||
true ->
|
||||
compare_expiration_date(Cert1, Cert2)
|
||||
end
|
||||
end, Chains).
|
||||
|
||||
%% Returns true if the first certificate has sooner expiration date
|
||||
-spec compare_expiration_date(cert(), cert()) -> boolean().
|
||||
compare_expiration_date(#'OTPCertificate'{
|
||||
tbsCertificate =
|
||||
#'OTPTBSCertificate'{
|
||||
validity = #'Validity'{notAfter = After1}}},
|
||||
#'OTPCertificate'{
|
||||
tbsCertificate =
|
||||
#'OTPTBSCertificate'{
|
||||
validity = #'Validity'{notAfter = After2}}}) ->
|
||||
get_timestamp(After1) =< get_timestamp(After2).
|
||||
|
||||
-spec load_certfile(file:filename_all()) -> {ok, [cert()], [priv_key()]} |
|
||||
{error, cert_error() | file:posix()}.
|
||||
@@ -471,57 +520,69 @@ pem_decode(Data) ->
|
||||
(_) -> false
|
||||
end, Objects) of
|
||||
{[], []} ->
|
||||
{error, not_cert};
|
||||
{error, {bad_cert, not_cert}};
|
||||
{Certs, PrivKeys} ->
|
||||
{ok, Certs, PrivKeys}
|
||||
end
|
||||
end
|
||||
catch _:_ ->
|
||||
{error, not_pem}
|
||||
catch E:R ->
|
||||
St = erlang:get_stacktrace(),
|
||||
?DEBUG("PEM decoding stacktrace: ~p", [{E, {R, St}}]),
|
||||
{error, {bad_cert, not_pem}}
|
||||
end.
|
||||
|
||||
-spec decode_certs([public_key:pem_entry()]) -> {[cert()], [priv_key()]} |
|
||||
{error, not_der | encrypted}.
|
||||
-spec decode_certs([public_key:pem_entry()]) -> [cert() | priv_key()] |
|
||||
{error, cert_error()}.
|
||||
decode_certs(PemEntries) ->
|
||||
try lists:foldr(
|
||||
fun(_, {error, _} = Err) ->
|
||||
Err;
|
||||
({_, _, Flag}, _) when Flag /= not_encrypted ->
|
||||
{error, encrypted};
|
||||
({'Certificate', Der, _}, Acc) ->
|
||||
[public_key:pkix_decode_cert(Der, otp)|Acc];
|
||||
({'PrivateKeyInfo', Der, not_encrypted}, Acc) ->
|
||||
#'PrivateKeyInfo'{privateKeyAlgorithm =
|
||||
#'PrivateKeyInfo_privateKeyAlgorithm'{
|
||||
algorithm = Algo},
|
||||
privateKey = Key} =
|
||||
public_key:der_decode('PrivateKeyInfo', Der),
|
||||
case Algo of
|
||||
?'rsaEncryption' ->
|
||||
[public_key:der_decode(
|
||||
'RSAPrivateKey', iolist_to_binary(Key))|Acc];
|
||||
?'id-dsa' ->
|
||||
[public_key:der_decode(
|
||||
'DSAPrivateKey', iolist_to_binary(Key))|Acc];
|
||||
?'id-ecPublicKey' ->
|
||||
[public_key:der_decode(
|
||||
'ECPrivateKey', iolist_to_binary(Key))|Acc];
|
||||
_ ->
|
||||
Acc
|
||||
end;
|
||||
({Tag, Der, _}, Acc) when Tag == 'RSAPrivateKey';
|
||||
Tag == 'DSAPrivateKey';
|
||||
Tag == 'ECPrivateKey' ->
|
||||
[public_key:der_decode(Tag, Der)|Acc];
|
||||
(_, Acc) ->
|
||||
Acc
|
||||
end, [], PemEntries)
|
||||
catch _:_ ->
|
||||
{error, not_der}
|
||||
try lists:flatmap(
|
||||
fun({Tag, Der, Flag}) ->
|
||||
decode_cert(Tag, Der, Flag)
|
||||
end, PemEntries)
|
||||
catch _:{bad_cert, _} = Err ->
|
||||
{error, Err};
|
||||
E:R ->
|
||||
St = erlang:get_stacktrace(),
|
||||
?DEBUG("DER decoding stacktrace: ~p", [{E, {R, St}}]),
|
||||
{error, {bad_cert, not_der}}
|
||||
end.
|
||||
|
||||
-spec validate([{path, [cert()]}], boolean()) -> [{cert(), bad_cert()}].
|
||||
validate(Paths, true) ->
|
||||
-spec decode_cert(atom(), binary(), atom()) -> [cert() | priv_key()].
|
||||
decode_cert(_, _, Flag) when Flag /= not_encrypted ->
|
||||
erlang:error({bad_cert, encrypted});
|
||||
decode_cert('Certificate', Der, _) ->
|
||||
[public_key:pkix_decode_cert(Der, otp)];
|
||||
decode_cert('PrivateKeyInfo', Der, not_encrypted) ->
|
||||
case public_key:der_decode('PrivateKeyInfo', Der) of
|
||||
#'PrivateKeyInfo'{privateKeyAlgorithm =
|
||||
#'PrivateKeyInfo_privateKeyAlgorithm'{
|
||||
algorithm = Algo},
|
||||
privateKey = Key} ->
|
||||
KeyBin = iolist_to_binary(Key),
|
||||
case Algo of
|
||||
?'rsaEncryption' ->
|
||||
[public_key:der_decode('RSAPrivateKey', KeyBin)];
|
||||
?'id-dsa' ->
|
||||
[public_key:der_decode('DSAPrivateKey', KeyBin)];
|
||||
?'id-ecPublicKey' ->
|
||||
[public_key:der_decode('ECPrivateKey', KeyBin)];
|
||||
_ ->
|
||||
erlang:error({bad_cert, unknown_key_algo})
|
||||
end;
|
||||
#'RSAPrivateKey'{} = Key -> [Key];
|
||||
#'DSAPrivateKey'{} = Key -> [Key];
|
||||
#'ECPrivateKey'{} = Key -> [Key];
|
||||
_ -> erlang:error({bad_cert, unknown_key_type})
|
||||
end;
|
||||
decode_cert(Tag, Der, _) when Tag == 'RSAPrivateKey';
|
||||
Tag == 'DSAPrivateKey';
|
||||
Tag == 'ECPrivateKey' ->
|
||||
[public_key:der_decode(Tag, Der)];
|
||||
decode_cert(_, _, _) ->
|
||||
[].
|
||||
|
||||
-spec validate([{path, [cert()]}], state()) -> [cert()].
|
||||
validate(Paths, #state{validate = true} = State) ->
|
||||
?DEBUG("Validating certificates", []),
|
||||
{ok, Re} = re:compile("^[a-f0-9]+\\.[0-9]+$", [unicode]),
|
||||
Hashes = case file:list_dir(ca_dir()) of
|
||||
{ok, Files} ->
|
||||
@@ -550,13 +611,16 @@ validate(Paths, true) ->
|
||||
ok ->
|
||||
false;
|
||||
{error, Cert, Reason} ->
|
||||
{true, {Cert, Reason}}
|
||||
File = maps:get(Cert, State#state.certs),
|
||||
?WARNING_MSG("Failed to validate certificate from ~s: ~s",
|
||||
[File, format_error(Reason)]),
|
||||
{true, Cert}
|
||||
end
|
||||
end, Paths);
|
||||
validate(_, _) ->
|
||||
[].
|
||||
|
||||
-spec validate_path([cert()], dict:dict()) -> ok | {error, cert(), bad_cert()}.
|
||||
-spec validate_path([cert()], dict:dict()) -> ok | {error, cert(), cert_error()}.
|
||||
validate_path([Cert|_] = Certs, Cache) ->
|
||||
case find_local_issuer(Cert, Cache) of
|
||||
{ok, IssuerCert} ->
|
||||
@@ -714,6 +778,7 @@ do_read_ca_file(Path) ->
|
||||
-spec match_cert_keys([{path, [cert()]}], [priv_key()])
|
||||
-> {ok, [{cert(), priv_key()}]} | {error, {bad_cert, missing_priv_key}}.
|
||||
match_cert_keys(CertPaths, PrivKeys) ->
|
||||
?DEBUG("Finding matched certificate keys", []),
|
||||
KeyPairs = [{pubkey_from_privkey(PrivKey), PrivKey} || PrivKey <- PrivKeys],
|
||||
match_cert_keys(CertPaths, KeyPairs, []).
|
||||
|
||||
@@ -762,6 +827,7 @@ pubkey_from_privkey(#'ECPrivateKey'{publicKey = Key}) ->
|
||||
|
||||
-spec get_cert_paths([cert()], digraph:graph()) -> [{path, [cert()]}].
|
||||
get_cert_paths(Certs, G) ->
|
||||
?DEBUG("Building certificates graph", []),
|
||||
{NewCerts, OldCerts} =
|
||||
lists:partition(
|
||||
fun(Cert) ->
|
||||
@@ -837,6 +903,15 @@ short_name_hash(_) ->
|
||||
"".
|
||||
-endif.
|
||||
|
||||
-spec get_timestamp({utcTime | generalTime, string()}) -> string().
|
||||
get_timestamp({utcTime, [Y1,Y2|T]}) ->
|
||||
case list_to_integer([Y1,Y2]) of
|
||||
N when N >= 50 -> [$1,$9,Y1,Y2|T];
|
||||
_ -> [$2,$0,Y1,Y2|T]
|
||||
end;
|
||||
get_timestamp({generalTime, TS}) ->
|
||||
TS.
|
||||
|
||||
wildcard(Path) when is_binary(Path) ->
|
||||
wildcard(binary_to_list(Path));
|
||||
wildcard(Path) ->
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
-export([start_link/0, init/1, opt_type/1,
|
||||
config_reloaded/0, start_host/1, stop_host/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
start_link() ->
|
||||
@@ -56,7 +55,7 @@ get_specs() ->
|
||||
{ok, Spec} -> [Spec];
|
||||
undefined -> []
|
||||
end
|
||||
end, ?MYHOSTS).
|
||||
end, ejabberd_config:get_myhosts()).
|
||||
|
||||
-spec get_spec(binary()) -> {ok, supervisor:child_spec()} | undefined.
|
||||
get_spec(Host) ->
|
||||
@@ -72,7 +71,7 @@ get_spec(Host) ->
|
||||
|
||||
-spec config_reloaded() -> ok.
|
||||
config_reloaded() ->
|
||||
lists:foreach(fun start_host/1, ?MYHOSTS).
|
||||
lists:foreach(fun start_host/1, ejabberd_config:get_myhosts()).
|
||||
|
||||
-spec start_host(binary()) -> ok.
|
||||
start_host(Host) ->
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
-define(CALL_TIMEOUT, 60*1000). %% 60 seconds
|
||||
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
-record(state, {connection :: pid() | undefined,
|
||||
num :: pos_integer(),
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(DEFAULT_POOL_SIZE, 10).
|
||||
@@ -98,7 +97,7 @@ init([]) ->
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
is_redis_configured() ->
|
||||
lists:any(fun is_redis_configured/1, ?MYHOSTS).
|
||||
lists:any(fun is_redis_configured/1, ejabberd_config:get_myhosts()).
|
||||
|
||||
is_redis_configured(Host) ->
|
||||
ServerConfigured = ejabberd_config:has_option({redis_server, Host}),
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-record(state, {pid = self() :: pid()}).
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
transform_options/1, get_random_pid/0,
|
||||
host_up/1, config_reloaded/0, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(DEFAULT_POOL_SIZE, 10).
|
||||
@@ -74,7 +73,7 @@ config_reloaded() ->
|
||||
end.
|
||||
|
||||
is_riak_configured() ->
|
||||
lists:any(fun is_riak_configured/1, ?MYHOSTS).
|
||||
lists:any(fun is_riak_configured/1, ejabberd_config:get_myhosts()).
|
||||
|
||||
is_riak_configured(Host) ->
|
||||
ServerConfigured = ejabberd_config:has_option({riak_server, Host}),
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
%% This value is used in SIP and Megaco for a transaction lifetime.
|
||||
-define(IQ_TIMEOUT, 32000).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_router.hrl").
|
||||
-include("xmpp.hrl").
|
||||
@@ -306,12 +305,8 @@ is_my_host(Domain) ->
|
||||
end.
|
||||
|
||||
-spec process_iq(iq()) -> any().
|
||||
process_iq(#iq{to = To} = IQ) ->
|
||||
if To#jid.luser == <<"">> ->
|
||||
ejabberd_local:process_iq(IQ);
|
||||
true ->
|
||||
ejabberd_sm:process_iq(IQ)
|
||||
end.
|
||||
process_iq(IQ) ->
|
||||
gen_iq_handler:handle(IQ).
|
||||
|
||||
-spec config_reloaded() -> ok.
|
||||
config_reloaded() ->
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
-export([init/1, handle_cast/2, handle_call/3, handle_info/2,
|
||||
terminate/2, code_change/3, start_link/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_router.hrl").
|
||||
-include("logger.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("xmpp.hrl").
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
-export([init/1, handle_cast/2, handle_call/3, handle_info/2,
|
||||
terminate/2, code_change/3, start_link/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_router.hrl").
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
-export([init/0, register_route/5, unregister_route/3, find_routes/1,
|
||||
get_all_routes/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
-include("ejabberd_router.hrl").
|
||||
@@ -41,7 +40,7 @@ init() ->
|
||||
Node = erlang:atom_to_binary(node(), latin1),
|
||||
?DEBUG("Cleaning SQL 'route' table...", []),
|
||||
case ejabberd_sql:sql_query(
|
||||
?MYNAME, ?SQL("delete from route where node=%(Node)s")) of
|
||||
ejabberd_config:get_myname(), ?SQL("delete from route where node=%(Node)s")) of
|
||||
{updated, _} ->
|
||||
ok;
|
||||
Err ->
|
||||
@@ -53,7 +52,7 @@ register_route(Domain, ServerHost, LocalHint, _, Pid) ->
|
||||
PidS = misc:encode_pid(Pid),
|
||||
LocalHintS = enc_local_hint(LocalHint),
|
||||
Node = erlang:atom_to_binary(node(Pid), latin1),
|
||||
case ?SQL_UPSERT(?MYNAME, "route",
|
||||
case ?SQL_UPSERT(ejabberd_config:get_myname(), "route",
|
||||
["!domain=%(Domain)s",
|
||||
"!server_host=%(ServerHost)s",
|
||||
"!node=%(Node)s",
|
||||
@@ -69,7 +68,7 @@ unregister_route(Domain, _, Pid) ->
|
||||
PidS = misc:encode_pid(Pid),
|
||||
Node = erlang:atom_to_binary(node(Pid), latin1),
|
||||
case ejabberd_sql:sql_query(
|
||||
?MYNAME,
|
||||
ejabberd_config:get_myname(),
|
||||
?SQL("delete from route where domain=%(Domain)s "
|
||||
"and pid=%(PidS)s and node=%(Node)s")) of
|
||||
{updated, _} ->
|
||||
@@ -80,7 +79,7 @@ unregister_route(Domain, _, Pid) ->
|
||||
|
||||
find_routes(Domain) ->
|
||||
case ejabberd_sql:sql_query(
|
||||
?MYNAME,
|
||||
ejabberd_config:get_myname(),
|
||||
?SQL("select @(server_host)s, @(node)s, @(pid)s, @(local_hint)s "
|
||||
"from route where domain=%(Domain)s")) of
|
||||
{selected, Rows} ->
|
||||
@@ -94,7 +93,7 @@ find_routes(Domain) ->
|
||||
|
||||
get_all_routes() ->
|
||||
case ejabberd_sql:sql_query(
|
||||
?MYNAME,
|
||||
ejabberd_config:get_myname(),
|
||||
?SQL("select @(domain)s from route where domain <> server_host")) of
|
||||
{selected, Domains} ->
|
||||
{ok, [Domain || {Domain} <- Domains]};
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
-export([get_info_s2s_connections/1,
|
||||
transform_options/1, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
@@ -303,7 +302,7 @@ init([]) ->
|
||||
{attributes, record_info(fields, temporarily_blocked)}]),
|
||||
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
|
||||
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
|
||||
lists:foreach(fun host_up/1, ?MYHOSTS),
|
||||
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
|
||||
{ok, #state{}}.
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
@@ -322,7 +321,7 @@ handle_info(_Info, State) -> {noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
ejabberd_commands:unregister_commands(get_commands_spec()),
|
||||
lists:foreach(fun host_down/1, ?MYHOSTS),
|
||||
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()),
|
||||
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50),
|
||||
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60),
|
||||
ok.
|
||||
@@ -544,7 +543,7 @@ is_service(From, To) ->
|
||||
s2s -> % bypass RFC 3920 10.3
|
||||
false;
|
||||
local ->
|
||||
Hosts = (?MYHOSTS),
|
||||
Hosts = ejabberd_config:get_myhosts(),
|
||||
P = fun (ParentDomain) ->
|
||||
lists:member(ParentDomain, Hosts)
|
||||
end,
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
-export([stop/1, close/1, close/2, send/2, update_state/2, establish/1,
|
||||
host_up/1, host_down/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
@@ -263,10 +262,10 @@ init([State, Opts]) ->
|
||||
State1 = State#{tls_options => TLSOpts2,
|
||||
auth_domains => sets:new(),
|
||||
xmlns => ?NS_SERVER,
|
||||
lang => ?MYLANG,
|
||||
server => ?MYNAME,
|
||||
lserver => ?MYNAME,
|
||||
server_host => ?MYNAME,
|
||||
lang => ejabberd_config:get_mylang(),
|
||||
server => ejabberd_config:get_myname(),
|
||||
lserver => ejabberd_config:get_myname(),
|
||||
server_host => ejabberd_config:get_myname(),
|
||||
established => false,
|
||||
shaper => Shaper},
|
||||
State2 = xmpp_stream_in:set_timeout(State1, Timeout),
|
||||
@@ -388,6 +387,9 @@ listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(backlog) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(_) ->
|
||||
[shaper, certfile, ciphers, dhfile, cafile, protocol_options,
|
||||
tls_compression, tls, max_fsm_queue, backlog, inet, inet6].
|
||||
tls_compression, tls, max_fsm_queue, backlog, inet, inet6,
|
||||
accept_interval].
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
-export([start/3, start_link/3, connect/1, close/1, close/2, stop/1, send/2,
|
||||
route/2, establish/1, update_state/2, host_up/1, host_down/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
@@ -61,12 +60,12 @@ start(From, To, Opts) ->
|
||||
Res -> Res
|
||||
end;
|
||||
_ ->
|
||||
xmpp_stream_out:start(?MODULE, [xmpp_socket, From, To, Opts],
|
||||
xmpp_stream_out:start(?MODULE, [From, To, Opts],
|
||||
ejabberd_config:fsm_limit_opts([]))
|
||||
end.
|
||||
|
||||
start_link(From, To, Opts) ->
|
||||
xmpp_stream_out:start_link(?MODULE, [xmpp_socket, From, To, Opts],
|
||||
xmpp_stream_out:start_link(?MODULE, [From, To, Opts],
|
||||
ejabberd_config:fsm_limit_opts([])).
|
||||
|
||||
-spec connect(pid()) -> ok.
|
||||
@@ -274,7 +273,7 @@ init([#{server := LServer, remote_server := RServer} = State, Opts]) ->
|
||||
State1 = State#{on_route => queue,
|
||||
queue => p1_queue:new(QueueType, QueueLimit),
|
||||
xmlns => ?NS_SERVER,
|
||||
lang => ?MYLANG,
|
||||
lang => ejabberd_config:get_mylang(),
|
||||
server_host => ServerHost,
|
||||
shaper => none},
|
||||
State2 = xmpp_stream_out:set_timeout(State1, Timeout),
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
%% API
|
||||
-export([send/2]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("xmpp.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
@@ -106,8 +105,8 @@ init([State, Opts]) ->
|
||||
State2 = xmpp_stream_in:set_timeout(State1, Timeout),
|
||||
State3 = State2#{access => Access,
|
||||
xmlns => ?NS_COMPONENT,
|
||||
lang => ?MYLANG,
|
||||
server => ?MYNAME,
|
||||
lang => ejabberd_config:get_mylang(),
|
||||
server => ejabberd_config:get_myname(),
|
||||
host_opts => dict:from_list(HostOpts1),
|
||||
stream_version => undefined,
|
||||
tls_options => TLSOpts,
|
||||
@@ -170,7 +169,7 @@ handle_auth_success(_, Mech, _,
|
||||
end,
|
||||
lists:foreach(
|
||||
fun(H) ->
|
||||
ejabberd_router:register_route(H, ?MYNAME),
|
||||
ejabberd_router:register_route(H, ejabberd_config:get_myname()),
|
||||
ejabberd_hooks:run(component_connected, [H])
|
||||
end, Routes),
|
||||
State.
|
||||
@@ -191,8 +190,14 @@ handle_authenticated_packet(Pkt0, #{ip := {IP, _}, lang := Lang} = State)
|
||||
From = xmpp:get_from(Pkt),
|
||||
case check_from(From, State) of
|
||||
true ->
|
||||
ejabberd_router:route(Pkt),
|
||||
State;
|
||||
{Pkt2, State2} = ejabberd_hooks:run_fold(component_send_packet, {Pkt, State}, []),
|
||||
case Pkt2 of
|
||||
drop ->
|
||||
ok;
|
||||
_ ->
|
||||
ejabberd_router:route(Pkt2)
|
||||
end,
|
||||
State2;
|
||||
false ->
|
||||
Txt = <<"Improper domain part of 'from' attribute">>,
|
||||
Err = xmpp:serr_invalid_from(Txt, Lang),
|
||||
@@ -335,7 +340,9 @@ listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(backlog) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(_) ->
|
||||
[access, shaper_rule, certfile, ciphers, dhfile, cafile, tls,
|
||||
protocol_options, tls_compression, password, hosts, check_from,
|
||||
max_fsm_queue, global_routes, backlog, inet, inet6].
|
||||
max_fsm_queue, global_routes, backlog, inet, inet6, accept_interval].
|
||||
|
||||
@@ -44,7 +44,6 @@ start(_, _) ->
|
||||
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2,
|
||||
socket_type/0, listen_opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
@@ -71,11 +70,11 @@ set_certfile(Opts) ->
|
||||
true ->
|
||||
Opts;
|
||||
false ->
|
||||
case ejabberd_pkix:get_certfile(?MYNAME) of
|
||||
case ejabberd_pkix:get_certfile(ejabberd_config:get_myname()) of
|
||||
{ok, CertFile} ->
|
||||
[{certfile, CertFile}|Opts];
|
||||
error ->
|
||||
case ejabberd_config:get_option({domain_certfile, ?MYNAME}) of
|
||||
case ejabberd_config:get_option({domain_certfile, ejabberd_config:get_myname()}) of
|
||||
undefined ->
|
||||
Opts;
|
||||
CertFile ->
|
||||
@@ -93,8 +92,10 @@ listen_opt_type(certfile) ->
|
||||
end;
|
||||
listen_opt_type(tls) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(_) ->
|
||||
[tls, certfile].
|
||||
[tls, certfile, accept_interval].
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
|
||||
+32
-66
@@ -39,7 +39,6 @@
|
||||
stop/0,
|
||||
route/1,
|
||||
route/2,
|
||||
process_iq/1,
|
||||
open_session/5,
|
||||
open_session/6,
|
||||
close_session/4,
|
||||
@@ -58,13 +57,12 @@
|
||||
get_vh_session_list/1,
|
||||
get_vh_session_number/1,
|
||||
get_vh_by_backend/1,
|
||||
register_iq_handler/4,
|
||||
unregister_iq_handler/2,
|
||||
force_update_presence/1,
|
||||
connected_users/0,
|
||||
connected_users_number/0,
|
||||
user_resources/2,
|
||||
kick_user/2,
|
||||
kick_user/3,
|
||||
get_session_pid/3,
|
||||
get_session_sid/3,
|
||||
get_session_sids/2,
|
||||
@@ -87,7 +85,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
handle_info/2, terminate/2, code_change/3, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
@@ -245,10 +242,12 @@ get_user_info(User, Server) ->
|
||||
LServer = jid:nameprep(Server),
|
||||
Mod = get_sm_backend(LServer),
|
||||
Ss = online(get_sessions(Mod, LUser, LServer)),
|
||||
[{LResource, [{node, node(Pid)}|Info]}
|
||||
[{LResource, [{node, node(Pid)}, {ts, Ts}, {pid, Pid},
|
||||
{priority, Priority} | Info]}
|
||||
|| #session{usr = {_, _, LResource},
|
||||
priority = Priority,
|
||||
info = Info,
|
||||
sid = {_, Pid}} <- clean_session_list(Ss)].
|
||||
sid = {Ts, Pid}} <- clean_session_list(Ss)].
|
||||
|
||||
-spec get_user_info(binary(), binary(), binary()) -> info() | offline.
|
||||
|
||||
@@ -262,8 +261,11 @@ get_user_info(User, Server, Resource) ->
|
||||
offline;
|
||||
Ss ->
|
||||
Session = lists:max(Ss),
|
||||
Node = node(element(2, Session#session.sid)),
|
||||
[{node, Node}|Session#session.info]
|
||||
{Ts, Pid} = Session#session.sid,
|
||||
Node = node(Pid),
|
||||
Priority = Session#session.priority,
|
||||
[{node, Node}, {ts, Ts}, {pid, Pid}, {priority, Priority}
|
||||
|Session#session.info]
|
||||
end.
|
||||
|
||||
-spec set_presence(sid(), binary(), binary(), binary(),
|
||||
@@ -397,17 +399,6 @@ get_vh_session_number(Server) ->
|
||||
Mod = get_sm_backend(LServer),
|
||||
length(online(get_sessions(Mod, LServer))).
|
||||
|
||||
-spec register_iq_handler(binary(), binary(), atom(), atom()) -> ok.
|
||||
|
||||
register_iq_handler(Host, XMLNS, Module, Fun) ->
|
||||
?GEN_SERVER:cast(?MODULE,
|
||||
{register_iq_handler, Host, XMLNS, Module, Fun}).
|
||||
|
||||
-spec unregister_iq_handler(binary(), binary()) -> ok.
|
||||
|
||||
unregister_iq_handler(Host, XMLNS) ->
|
||||
?GEN_SERVER:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}).
|
||||
|
||||
%% Why the hell do we have so many similar kicks?
|
||||
c2s_handle_info(#{lang := Lang} = State, replaced) ->
|
||||
State1 = State#{replaced => true},
|
||||
@@ -437,26 +428,17 @@ init([]) ->
|
||||
init_cache(),
|
||||
lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()),
|
||||
clean_cache(),
|
||||
ets:new(sm_iqtable, [named_table, public, {read_concurrency, true}]),
|
||||
gen_iq_handler:start(?MODULE),
|
||||
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
|
||||
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
|
||||
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
|
||||
lists:foreach(fun host_up/1, ?MYHOSTS),
|
||||
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
|
||||
ejabberd_commands:register_commands(get_commands_spec()),
|
||||
{ok, #state{}}.
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
Reply = ok, {reply, Reply, State}.
|
||||
|
||||
handle_cast({register_iq_handler, Host, XMLNS, Module, Function},
|
||||
State) ->
|
||||
ets:insert(sm_iqtable,
|
||||
{{Host, XMLNS}, Module, Function}),
|
||||
{noreply, State};
|
||||
handle_cast({unregister_iq_handler, Host, XMLNS},
|
||||
State) ->
|
||||
ets:delete(sm_iqtable, {Host, XMLNS}),
|
||||
{noreply, State};
|
||||
handle_cast(_Msg, State) -> {noreply, State}.
|
||||
|
||||
handle_info({route, Packet}, State) ->
|
||||
@@ -467,7 +449,7 @@ handle_info(Info, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
lists:foreach(fun host_down/1, ?MYHOSTS),
|
||||
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()),
|
||||
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50),
|
||||
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60),
|
||||
ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 50),
|
||||
@@ -664,7 +646,7 @@ do_route(#message{to = #jid{lresource = <<"">>}, type = T} = Packet) ->
|
||||
end;
|
||||
do_route(#iq{to = #jid{lresource = <<"">>}} = Packet) ->
|
||||
?DEBUG("processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]),
|
||||
process_iq(Packet);
|
||||
gen_iq_handler:handle(?MODULE, Packet);
|
||||
do_route(Packet) ->
|
||||
?DEBUG("processing packet to full JID:~n~s", [xmpp:pp(Packet)]),
|
||||
To = xmpp:get_to(Packet),
|
||||
@@ -849,31 +831,6 @@ get_max_user_sessions(LUser, Host) ->
|
||||
end.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
-spec process_iq(iq()) -> any().
|
||||
process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
|
||||
when T == get; T == set ->
|
||||
XMLNS = xmpp:get_ns(El),
|
||||
Host = To#jid.lserver,
|
||||
case ets:lookup(sm_iqtable, {Host, XMLNS}) of
|
||||
[{_, Module, Function}] ->
|
||||
gen_iq_handler:handle(Host, Module, Function, Packet);
|
||||
[] ->
|
||||
Txt = <<"No module is handling this query">>,
|
||||
Err = xmpp:err_service_unavailable(Txt, Lang),
|
||||
ejabberd_router:route_error(Packet, Err)
|
||||
end;
|
||||
process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
|
||||
when T == get; T == set ->
|
||||
Txt = case SubEls of
|
||||
[] -> <<"No child elements found">>;
|
||||
_ -> <<"Too many child elements">>
|
||||
end,
|
||||
Err = xmpp:err_bad_request(Txt, Lang),
|
||||
ejabberd_router:route_error(Packet, Err);
|
||||
process_iq(#iq{}) ->
|
||||
ok.
|
||||
|
||||
-spec force_update_presence({binary(), binary()}) -> ok.
|
||||
|
||||
force_update_presence({LUser, LServer}) ->
|
||||
@@ -895,7 +852,7 @@ get_sm_backend(Host) ->
|
||||
-spec get_sm_backends() -> [module()].
|
||||
|
||||
get_sm_backends() ->
|
||||
lists:usort([get_sm_backend(Host) || Host <- ?MYHOSTS]).
|
||||
lists:usort([get_sm_backend(Host) || Host <- ejabberd_config:get_myhosts()]).
|
||||
|
||||
-spec get_vh_by_backend(module()) -> [binary()].
|
||||
|
||||
@@ -903,7 +860,7 @@ get_vh_by_backend(Mod) ->
|
||||
lists:filter(
|
||||
fun(Host) ->
|
||||
get_sm_backend(Host) == Mod
|
||||
end, ?MYHOSTS).
|
||||
end, ejabberd_config:get_myhosts()).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%% Cache stuff
|
||||
@@ -966,7 +923,7 @@ use_cache() ->
|
||||
fun(Host) ->
|
||||
Mod = get_sm_backend(Host),
|
||||
use_cache(Mod, Host)
|
||||
end, ?MYHOSTS).
|
||||
end, ejabberd_config:get_myhosts()).
|
||||
|
||||
-spec cache_nodes(module(), binary()) -> [node()].
|
||||
cache_nodes(Mod, LServer) ->
|
||||
@@ -1026,14 +983,23 @@ user_resources(User, Server) ->
|
||||
Resources = get_user_resources(User, Server),
|
||||
lists:sort(Resources).
|
||||
|
||||
-spec kick_user(binary(), binary()) -> non_neg_integer().
|
||||
kick_user(User, Server) ->
|
||||
Resources = get_user_resources(User, Server),
|
||||
lists:foreach(
|
||||
fun(Resource) ->
|
||||
PID = get_session_pid(User, Server, Resource),
|
||||
ejabberd_c2s:route(PID, kick)
|
||||
end, Resources),
|
||||
length(Resources).
|
||||
lists:foldl(
|
||||
fun(Resource, Acc) ->
|
||||
case kick_user(User, Server, Resource) of
|
||||
false -> Acc;
|
||||
true -> Acc + 1
|
||||
end
|
||||
end, 0, Resources).
|
||||
|
||||
-spec kick_user(binary(), binary(), binary()) -> boolean().
|
||||
kick_user(User, Server, Resource) ->
|
||||
case get_session_pid(User, Server, Resource) of
|
||||
none -> false;
|
||||
Pid -> ejabberd_c2s:route(Pid, kick)
|
||||
end.
|
||||
|
||||
make_sid() ->
|
||||
{p1_time_compat:unique_timestamp(), self()}.
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3, start_link/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_sm.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
-export([init/1, handle_cast/2, handle_call/3, handle_info/2,
|
||||
terminate/2, code_change/3, start_link/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_sm.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
get_sessions/1,
|
||||
get_sessions/2]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("ejabberd_sm.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
session_established/2, session_established/3,
|
||||
opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_sql_pt.hrl").
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
get_pids/1, get_random_pid/1, transform_options/1,
|
||||
opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(PGSQL_PORT, 5432).
|
||||
@@ -172,12 +171,7 @@ check_sqlite_db(Host) ->
|
||||
end.
|
||||
|
||||
create_sqlite_tables(DB) ->
|
||||
SqlDir = case code:priv_dir(ejabberd) of
|
||||
{error, _} ->
|
||||
?SQL_DIR;
|
||||
PrivDir ->
|
||||
filename:join(PrivDir, "sql")
|
||||
end,
|
||||
SqlDir = misc:sql_dir(),
|
||||
File = filename:join(SqlDir, "lite.sql"),
|
||||
case file:open(File, [read, binary]) of
|
||||
{ok, Fd} ->
|
||||
|
||||
@@ -46,7 +46,6 @@ start(_, _) ->
|
||||
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2,
|
||||
socket_type/0, listen_opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
@@ -79,7 +78,7 @@ prepare_turn_opts(Opts) ->
|
||||
prepare_turn_opts(Opts, _UseTurn = false) ->
|
||||
set_certfile(Opts);
|
||||
prepare_turn_opts(Opts, _UseTurn = true) ->
|
||||
NumberOfMyHosts = length(?MYHOSTS),
|
||||
NumberOfMyHosts = length(ejabberd_config:get_myhosts()),
|
||||
case proplists:get_value(turn_ip, Opts) of
|
||||
undefined ->
|
||||
?WARNING_MSG("option 'turn_ip' is undefined, "
|
||||
@@ -100,11 +99,11 @@ prepare_turn_opts(Opts, _UseTurn = true) ->
|
||||
"'auth_type' is set to 'user', "
|
||||
"more likely the TURN relay won't "
|
||||
"be working properly. Using ~s as "
|
||||
"a fallback", [?MYNAME]);
|
||||
"a fallback", [ejabberd_config:get_myname()]);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
[{auth_realm, ?MYNAME}];
|
||||
[{auth_realm, ejabberd_config:get_myname()}];
|
||||
_ ->
|
||||
[]
|
||||
end,
|
||||
@@ -118,7 +117,7 @@ set_certfile(Opts) ->
|
||||
true ->
|
||||
Opts;
|
||||
false ->
|
||||
Realm = proplists:get_value(auth_realm, Opts, ?MYNAME),
|
||||
Realm = proplists:get_value(auth_realm, Opts, ejabberd_config:get_myname()),
|
||||
case ejabberd_pkix:get_certfile(Realm) of
|
||||
{ok, CertFile} ->
|
||||
[{certfile, CertFile}|Opts];
|
||||
@@ -174,8 +173,10 @@ listen_opt_type(server_name) ->
|
||||
fun iolist_to_binary/1;
|
||||
listen_opt_type(backlog) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(_) ->
|
||||
[shaper, auth_type, auth_realm, tls, certfile, turn_min_port,
|
||||
turn_max_port, turn_max_allocations, turn_max_permissions,
|
||||
server_name, backlog].
|
||||
server_name, backlog, accept_interval].
|
||||
-endif.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
-author('ekhramtsov@process-one.net').
|
||||
|
||||
%% API
|
||||
-export([start/0, opt_type/1]).
|
||||
-export([start/0, opt_type/1, config_reloaded/0]).
|
||||
|
||||
%% gen_event callbacks
|
||||
-export([init/1, handle_event/2, handle_call/2,
|
||||
@@ -42,7 +42,6 @@
|
||||
%%-include("logger.hrl").
|
||||
|
||||
-define(CHECK_INTERVAL, timer:seconds(30)).
|
||||
-define(DISK_FULL_THRES, 0.99).
|
||||
|
||||
-record(state, {tref :: reference(),
|
||||
mref :: reference()}).
|
||||
@@ -67,30 +66,29 @@ start() ->
|
||||
application:set_env(os_mon, start_cpu_sup, false),
|
||||
application:set_env(os_mon, start_os_sup, false),
|
||||
application:set_env(os_mon, start_memsup, true),
|
||||
application:set_env(os_mon, start_disksup, true),
|
||||
application:set_env(os_mon, disk_almost_full_threshold, ?DISK_FULL_THRES),
|
||||
ejabberd:start_app(os_mon).
|
||||
application:set_env(os_mon, start_disksup, false),
|
||||
ejabberd:start_app(os_mon),
|
||||
set_oom_watermark().
|
||||
|
||||
excluded_apps() ->
|
||||
[os_mon, mnesia, sasl, stdlib, kernel].
|
||||
|
||||
-spec config_reloaded() -> ok.
|
||||
config_reloaded() ->
|
||||
set_oom_watermark().
|
||||
|
||||
%%%===================================================================
|
||||
%%% gen_event callbacks
|
||||
%%%===================================================================
|
||||
init([]) ->
|
||||
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
|
||||
{ok, #state{}}.
|
||||
|
||||
handle_event({set_alarm, {system_memory_high_watermark, _}}, State) ->
|
||||
error_logger:warning_msg(
|
||||
"More than 80% of OS memory is allocated, "
|
||||
"starting OOM watchdog", []),
|
||||
handle_overload(State),
|
||||
{ok, restart_timer(State)};
|
||||
handle_event({clear_alarm, system_memory_high_watermark}, State) ->
|
||||
cancel_timer(State#state.tref),
|
||||
error_logger:info_msg(
|
||||
"Memory consumption is back to normal, "
|
||||
"stopping OOM watchdog", []),
|
||||
{ok, State#state{tref = undefined}};
|
||||
handle_event({set_alarm, {process_memory_high_watermark, Pid}}, State) ->
|
||||
case proc_stat(Pid, get_app_pids()) of
|
||||
@@ -105,12 +103,6 @@ handle_event({set_alarm, {process_memory_high_watermark, Pid}}, State) ->
|
||||
end;
|
||||
handle_event({clear_alarm, process_memory_high_watermark}, State) ->
|
||||
{ok, State};
|
||||
handle_event({set_alarm, {{disk_almost_full, MountPoint}, _}}, State) ->
|
||||
error_logger:warning_msg("Disk is almost full on ~p", [MountPoint]),
|
||||
{ok, State};
|
||||
handle_event({clear_alarm, {disk_almost_full, MountPoint}}, State) ->
|
||||
error_logger:info_msg("Disk usage is back to normal on ~p", [MountPoint]),
|
||||
{ok, State};
|
||||
handle_event(Event, State) ->
|
||||
error_logger:warning_msg("unexpected event: ~p", [Event]),
|
||||
{ok, State}.
|
||||
@@ -126,7 +118,7 @@ handle_info(Info, State) ->
|
||||
{ok, State}.
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
ok.
|
||||
ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 50).
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
@@ -142,7 +134,8 @@ handle_overload(State) ->
|
||||
handle_overload(_State, Procs) ->
|
||||
AppPids = get_app_pids(),
|
||||
{TotalMsgs, ProcsNum, Apps, Stats} = overloaded_procs(AppPids, Procs),
|
||||
if TotalMsgs >= 10000 ->
|
||||
MaxMsgs = ejabberd_config:get_option(oom_queue, 10000),
|
||||
if TotalMsgs >= MaxMsgs ->
|
||||
SortedStats = lists:reverse(lists:keysort(#proc_stat.qlen, Stats)),
|
||||
error_logger:warning_msg(
|
||||
"The system is overloaded with ~b messages "
|
||||
@@ -326,14 +319,21 @@ kill_proc(Pid) ->
|
||||
exit(Pid, kill),
|
||||
Pid.
|
||||
|
||||
-spec set_oom_watermark() -> ok.
|
||||
set_oom_watermark() ->
|
||||
WaterMark = ejabberd_config:get_option(oom_watermark, 80),
|
||||
memsup:set_sysmem_high_watermark(WaterMark/100).
|
||||
|
||||
-spec maybe_restart_app(atom()) -> any().
|
||||
maybe_restart_app(lager) ->
|
||||
ejabberd_logger:restart();
|
||||
maybe_restart_app(_) ->
|
||||
ok.
|
||||
|
||||
-spec opt_type(oom_killer) -> fun((boolean()) -> boolean());
|
||||
(atom()) -> [atom()].
|
||||
opt_type(oom_killer) ->
|
||||
fun(B) when is_boolean(B) -> B end;
|
||||
opt_type(_) -> [oom_killer].
|
||||
opt_type(oom_watermark) ->
|
||||
fun(I) when is_integer(I), I>0, I<100 -> I end;
|
||||
opt_type(oom_queue) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
opt_type(_) -> [oom_killer, oom_watermark, oom_queue].
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
%% API
|
||||
-export([update/0, update/1, update_info/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%====================================================================
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
%% External exports
|
||||
-export([make_xhtml/1, make_xhtml/2, error/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
list_users_in_diapason/4, pretty_print_xml/1,
|
||||
term_to_id/1, opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
@@ -1062,7 +1061,7 @@ parse_access_rule(Text) ->
|
||||
%%%% list_vhosts
|
||||
|
||||
list_vhosts(Lang, JID) ->
|
||||
Hosts = (?MYHOSTS),
|
||||
Hosts = ejabberd_config:get_myhosts(),
|
||||
HostsAllowed = lists:filter(fun (Host) ->
|
||||
acl:any_rules_allowed(Host,
|
||||
[configure, webadmin_view],
|
||||
@@ -1240,7 +1239,7 @@ list_given_users(Host, Users, Prefix, Lang, URLFunc) ->
|
||||
?XE(<<"tr">>,
|
||||
[?XE(<<"td">>,
|
||||
[?AC((URLFunc({user, Prefix,
|
||||
ejabberd_http:url_encode(User),
|
||||
misc:url_encode(User),
|
||||
Server})),
|
||||
(us_to_list(US)))]),
|
||||
?XE(<<"td">>, FQueueLen),
|
||||
@@ -1282,7 +1281,7 @@ get_stats(global, Lang) ->
|
||||
ejabberd_auth:count_users(Host)
|
||||
+ Total
|
||||
end,
|
||||
0, ?MYHOSTS),
|
||||
0, ejabberd_config:get_myhosts()),
|
||||
OutS2SNumber = ejabberd_s2s:outgoing_s2s_number(),
|
||||
InS2SNumber = ejabberd_s2s:incoming_s2s_number(),
|
||||
[?XAE(<<"table">>, [],
|
||||
@@ -1319,7 +1318,7 @@ list_online_users(Host, _Lang) ->
|
||||
SUsers = lists:usort(Users),
|
||||
lists:flatmap(fun ({_S, U} = SU) ->
|
||||
[?AC(<<"../user/",
|
||||
(ejabberd_http:url_encode(U))/binary, "/">>,
|
||||
(misc:url_encode(U))/binary, "/">>,
|
||||
(su_to_list(SU))),
|
||||
?BR]
|
||||
end,
|
||||
@@ -1784,7 +1783,7 @@ get_node(global, Node, [<<"backup">>], Query, Lang) ->
|
||||
?C(<<" ">>),
|
||||
?INPUT(<<"text">>,
|
||||
<<"export_piefxis_host_dirhost">>,
|
||||
(?MYNAME))]),
|
||||
(ejabberd_config:get_myname()))]),
|
||||
?XE(<<"td">>,
|
||||
[?INPUT(<<"text">>,
|
||||
<<"export_piefxis_host_dirpath">>,
|
||||
@@ -1800,7 +1799,7 @@ get_node(global, Node, [<<"backup">>], Query, Lang) ->
|
||||
?C(<<" ">>),
|
||||
?INPUT(<<"text">>,
|
||||
<<"export_sql_filehost">>,
|
||||
(?MYNAME))]),
|
||||
(ejabberd_config:get_myname()))]),
|
||||
?XE(<<"td">>,
|
||||
[?INPUT(<<"text">>,
|
||||
<<"export_sql_filepath">>,
|
||||
|
||||
@@ -42,9 +42,8 @@
|
||||
|
||||
-author('ecestari@process-one.net').
|
||||
|
||||
-export([check/2, socket_handoff/8]).
|
||||
-export([check/2, socket_handoff/5]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-include("xmpp.hrl").
|
||||
@@ -89,8 +88,9 @@ check(_Path, Headers) ->
|
||||
|
||||
socket_handoff(LocalPath, #request{method = 'GET', ip = IP, q = Q, path = Path,
|
||||
headers = Headers, host = Host, port = Port,
|
||||
opts = HOpts},
|
||||
Socket, SockMod, Buf, _Opts, HandlerModule, InfoMsgFun) ->
|
||||
socket = Socket, sockmod = SockMod,
|
||||
data = Buf, opts = HOpts},
|
||||
_Opts, HandlerModule, InfoMsgFun) ->
|
||||
case check(LocalPath, Headers) of
|
||||
true ->
|
||||
WS = #ws{socket = Socket,
|
||||
@@ -109,11 +109,11 @@ socket_handoff(LocalPath, #request{method = 'GET', ip = IP, q = Q, path = Path,
|
||||
_ ->
|
||||
{200, ?HEADER, InfoMsgFun()}
|
||||
end;
|
||||
socket_handoff(_, #request{method = 'OPTIONS'}, _, _, _, _, _, _) ->
|
||||
socket_handoff(_, #request{method = 'OPTIONS'}, _, _, _) ->
|
||||
{200, ?OPTIONS_HEADER, []};
|
||||
socket_handoff(_, #request{method = 'HEAD'}, _, _, _, _, _, _) ->
|
||||
socket_handoff(_, #request{method = 'HEAD'}, _, _, _) ->
|
||||
{200, ?HEADER, []};
|
||||
socket_handoff(_, _, _, _, _, _, _, _) ->
|
||||
socket_handoff(_, _, _, _, _) ->
|
||||
{400, ?HEADER, #xmlel{name = <<"h1">>,
|
||||
children = [{xmlcdata, <<"400 Bad Request">>}]}}.
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
-export([start/2, handler/2, process/2, socket_type/0,
|
||||
transform_listen_option/2, listen_opt_type/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
-include("mod_roster.hrl").
|
||||
@@ -585,5 +584,8 @@ listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
|
||||
listen_opt_type(backlog) ->
|
||||
fun(I) when is_integer(I), I>0 -> I end;
|
||||
listen_opt_type(accept_interval) ->
|
||||
fun(I) when is_integer(I), I>=0 -> I end;
|
||||
listen_opt_type(_) ->
|
||||
[access_commands, maxsessions, timeout, backlog, inet, inet6].
|
||||
[access_commands, maxsessions, timeout, backlog, inet, inet6,
|
||||
accept_interval].
|
||||
|
||||
@@ -51,7 +51,6 @@ modules() ->
|
||||
[ejabberd_auth,
|
||||
mod_announce,
|
||||
mod_caps,
|
||||
mod_irc,
|
||||
mod_last,
|
||||
mod_mam,
|
||||
mod_muc,
|
||||
|
||||
+71
-13
@@ -65,7 +65,6 @@
|
||||
|
||||
-behaviour(p1_fsm).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%% External exports
|
||||
@@ -88,7 +87,7 @@
|
||||
-export_type([filter/0]).
|
||||
|
||||
-include("ELDAPv3.hrl").
|
||||
|
||||
-include_lib("kernel/include/inet.hrl").
|
||||
-include("eldap.hrl").
|
||||
|
||||
-define(LDAP_VERSION, 3).
|
||||
@@ -139,8 +138,8 @@
|
||||
passwd = <<"">> :: binary(),
|
||||
id = 0 :: non_neg_integer(),
|
||||
bind_timer = make_ref() :: reference(),
|
||||
dict = dict:new() :: ?TDICT,
|
||||
req_q = queue:new() :: ?TQUEUE}).
|
||||
dict = dict:new() :: dict:dict(),
|
||||
req_q = queue:new() :: queue:queue()}).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
@@ -1057,15 +1056,11 @@ connect_bind(S) ->
|
||||
?DEBUG("Connecting to LDAP server at ~s:~p with options ~p",
|
||||
[Host, S#eldap.port, Opts]),
|
||||
HostS = binary_to_list(Host),
|
||||
SocketData = case S#eldap.tls of
|
||||
tls ->
|
||||
SockMod = ssl, ssl:connect(HostS, S#eldap.port, Opts);
|
||||
%% starttls -> %% TODO: Implement STARTTLS;
|
||||
_ ->
|
||||
SockMod = gen_tcp,
|
||||
gen_tcp:connect(HostS, S#eldap.port, Opts)
|
||||
end,
|
||||
case SocketData of
|
||||
SockMod = case S#eldap.tls of
|
||||
tls -> ssl;
|
||||
_ -> gen_tcp
|
||||
end,
|
||||
case connect(HostS, S#eldap.port, SockMod, Opts) of
|
||||
{ok, Socket} ->
|
||||
case bind_request(Socket, S#eldap{sockmod = SockMod}) of
|
||||
{ok, NewS} ->
|
||||
@@ -1132,3 +1127,66 @@ format_error(SockMod, Reason) ->
|
||||
_ ->
|
||||
Txt
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Connecting stuff
|
||||
%%--------------------------------------------------------------------
|
||||
-define(CONNECT_TIMEOUT, timer:seconds(15)).
|
||||
-define(DNS_TIMEOUT, timer:seconds(5)).
|
||||
|
||||
connect(Host, Port, Mod, Opts) ->
|
||||
case lookup(Host) of
|
||||
{ok, AddrsFamilies} ->
|
||||
do_connect(AddrsFamilies, Port, Mod, Opts, {error, nxdomain});
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end.
|
||||
|
||||
do_connect([{IP, Family}|AddrsFamilies], Port, Mod, Opts, _Err) ->
|
||||
case Mod:connect(IP, Port, [Family|Opts], ?CONNECT_TIMEOUT) of
|
||||
{ok, Sock} ->
|
||||
{ok, Sock};
|
||||
{error, _} = Err ->
|
||||
do_connect(AddrsFamilies, Port, Mod, Opts, Err)
|
||||
end;
|
||||
do_connect([], _Port, _Mod, _Opts, Err) ->
|
||||
Err.
|
||||
|
||||
lookup(Host) ->
|
||||
case inet:parse_address(Host) of
|
||||
{ok, IP} ->
|
||||
{ok, [{IP, get_addr_type(IP)}]};
|
||||
{error, _} ->
|
||||
do_lookup([{Host, Family} || Family <- [inet6, inet]],
|
||||
[], {error, nxdomain})
|
||||
end.
|
||||
|
||||
do_lookup([{Host, Family}|HostFamilies], AddrFamilies, Err) ->
|
||||
case inet:gethostbyname(Host, Family, ?DNS_TIMEOUT) of
|
||||
{ok, HostEntry} ->
|
||||
Addrs = host_entry_to_addrs(HostEntry),
|
||||
AddrFamilies1 = [{Addr, Family} || Addr <- Addrs],
|
||||
do_lookup(HostFamilies,
|
||||
AddrFamilies ++ AddrFamilies1,
|
||||
Err);
|
||||
{error, _} = Err1 ->
|
||||
do_lookup(HostFamilies, AddrFamilies, Err1)
|
||||
end;
|
||||
do_lookup([], [], Err) ->
|
||||
Err;
|
||||
do_lookup([], AddrFamilies, _Err) ->
|
||||
{ok, AddrFamilies}.
|
||||
|
||||
host_entry_to_addrs(#hostent{h_addr_list = AddrList}) ->
|
||||
lists:filter(
|
||||
fun(Addr) ->
|
||||
try get_addr_type(Addr) of
|
||||
_ -> true
|
||||
catch _:badarg ->
|
||||
false
|
||||
end
|
||||
end, AddrList).
|
||||
|
||||
get_addr_type({_, _, _, _}) -> inet;
|
||||
get_addr_type({_, _, _, _, _, _, _, _}) -> inet6;
|
||||
get_addr_type(_) -> erlang:error(badarg).
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
-export([start_link/7, bind/3, search/2,
|
||||
modify_passwd/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
%%====================================================================
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
decode_octet_string/3, uids_domain_subst/2, opt_type/1,
|
||||
options/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
-include("eldap.hrl").
|
||||
|
||||
|
||||
+14
-14
@@ -33,7 +33,7 @@
|
||||
available_command/0, available/0, available/1,
|
||||
installed_command/0, installed/0, installed/1,
|
||||
install/1, uninstall/1, upgrade/0, upgrade/1,
|
||||
add_sources/2, del_sources/1, modules_dir/0,
|
||||
add_sources/1, add_sources/2, del_sources/1, modules_dir/0,
|
||||
config_dir/0, opt_type/1, get_commands_spec/0]).
|
||||
|
||||
-export([compile_erlang_file/2, compile_elixir_file/2]).
|
||||
@@ -56,7 +56,8 @@ init([]) ->
|
||||
process_flag(trap_exit, true),
|
||||
[code:add_patha(module_ebin_dir(Module))
|
||||
|| {Module, _} <- installed()],
|
||||
p1_http:start(),
|
||||
application:start(inets),
|
||||
inets:start(httpc, [{profile, ext_mod}]),
|
||||
ejabberd_commands:register_commands(get_commands_spec()),
|
||||
{ok, #state{}}.
|
||||
|
||||
@@ -313,23 +314,22 @@ check(Package) when is_binary(Package) ->
|
||||
%% -- archives and variables functions
|
||||
|
||||
geturl(Url) ->
|
||||
geturl(Url, []).
|
||||
geturl(Url, UsrOpts) ->
|
||||
geturl(Url, [], UsrOpts).
|
||||
geturl(Url, Hdrs, UsrOpts) ->
|
||||
Host = case getenv("PROXY_SERVER", "", ":") of
|
||||
[H, Port] -> [{proxy_host, H}, {proxy_port, list_to_integer(Port)}];
|
||||
[H] -> [{proxy_host, H}, {proxy_port, 8080}];
|
||||
_ -> []
|
||||
case getenv("PROXY_SERVER", "", ":") of
|
||||
[H, Port] ->
|
||||
httpc:set_options([{proxy, {{H, list_to_integer(Port)}, []}}], ext_mod);
|
||||
[H] ->
|
||||
httpc:set_options([{proxy, {{H, 8080}, []}}], ext_mod);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
User = case getenv("PROXY_USER", "", [4]) of
|
||||
[U, Pass] -> [{proxy_user, U}, {proxy_password, Pass}];
|
||||
[U, Pass] -> [{proxy_auth, {U, Pass}}];
|
||||
_ -> []
|
||||
end,
|
||||
case p1_http:request(get, Url, Hdrs, [], Host++User++UsrOpts++[{version, "HTTP/1.0"}]) of
|
||||
{ok, 200, Headers, Response} ->
|
||||
case httpc:request(get, {Url, []}, User, [{body_format, binary}], ext_mod) of
|
||||
{ok, {{_, 200, _}, Headers, Response}} ->
|
||||
{ok, Headers, Response};
|
||||
{ok, Code, _Headers, Response} ->
|
||||
{ok, {{_, Code, _}, _Headers, Response}} ->
|
||||
{error, {Code, Response}};
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
|
||||
+155
-105
@@ -1,8 +1,5 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : extauth.erl
|
||||
%%% Author : Leif Johansson <leifj@it.su.se>
|
||||
%%% Purpose : External authentication using a simple port-driver
|
||||
%%% Created : 30 Jul 2004 by Leif Johansson <leifj@it.su.se>
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% Created : 7 May 2018 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
|
||||
@@ -21,54 +18,45 @@
|
||||
%%% with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
%%%
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(extauth).
|
||||
|
||||
-behaviour(ejabberd_config).
|
||||
-ifndef(GEN_SERVER).
|
||||
-define(GEN_SERVER, gen_server).
|
||||
-endif.
|
||||
-behaviour(?GEN_SERVER).
|
||||
|
||||
-author('leifj@it.su.se').
|
||||
-define(CALL_TIMEOUT, timer:seconds(30)).
|
||||
|
||||
-export([start/2, stop/1, init/2, check_password/3,
|
||||
set_password/3, try_register/3, remove_user/2,
|
||||
remove_user/3, user_exists/2, opt_type/1]).
|
||||
%% API
|
||||
-export([start/1, stop/1, reload/1, start_link/2]).
|
||||
-export([check_password/3, set_password/3, try_register/3, remove_user/2,
|
||||
remove_user/3, user_exists/2]).
|
||||
-export([prog_name/1, pool_name/1, worker_name/2, pool_size/1]).
|
||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
terminate/2, code_change/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("logger.hrl").
|
||||
|
||||
-define(INIT_TIMEOUT, 60000).
|
||||
-record(state, {port :: port(),
|
||||
prog :: string(),
|
||||
start_time :: integer(),
|
||||
os_pid :: integer() | undefined}).
|
||||
|
||||
-define(CALL_TIMEOUT, 10000).
|
||||
|
||||
start(Host, ExtPrg) ->
|
||||
lists:foreach(fun (This) ->
|
||||
start_instance(get_process_name(Host, This), ExtPrg)
|
||||
end,
|
||||
lists:seq(0, get_instances(Host) - 1)).
|
||||
|
||||
start_instance(ProcessName, ExtPrg) ->
|
||||
spawn(?MODULE, init, [ProcessName, ExtPrg]).
|
||||
|
||||
restart_instance(ProcessName, ExtPrg) ->
|
||||
unregister(ProcessName),
|
||||
start_instance(ProcessName, ExtPrg).
|
||||
|
||||
init(ProcessName, ExtPrg) ->
|
||||
register(ProcessName, self()),
|
||||
process_flag(trap_exit, true),
|
||||
Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
|
||||
loop(Port, ?INIT_TIMEOUT, ProcessName, ExtPrg).
|
||||
%%%===================================================================
|
||||
%%% API
|
||||
%%%===================================================================
|
||||
start(Host) ->
|
||||
extauth_sup:start(Host).
|
||||
|
||||
stop(Host) ->
|
||||
lists:foreach(fun (This) ->
|
||||
get_process_name(Host, This) ! stop
|
||||
end,
|
||||
lists:seq(0, get_instances(Host) - 1)).
|
||||
extauth_sup:stop(Host).
|
||||
|
||||
get_process_name(Host, Integer) ->
|
||||
gen_mod:get_module_proc(iolist_to_binary([Host,
|
||||
integer_to_list(Integer)]),
|
||||
eauth).
|
||||
reload(Host) ->
|
||||
extauth_sup:reload(Host).
|
||||
|
||||
start_link(Name, Prog) ->
|
||||
?GEN_SERVER:start_link({local, Name}, ?MODULE, [Prog], []).
|
||||
|
||||
check_password(User, Server, Password) ->
|
||||
call_port(Server, [<<"auth">>, User, Server, Password]).
|
||||
@@ -80,82 +68,144 @@ set_password(User, Server, Password) ->
|
||||
call_port(Server, [<<"setpass">>, User, Server, Password]).
|
||||
|
||||
try_register(User, Server, Password) ->
|
||||
case call_port(Server,
|
||||
[<<"tryregister">>, User, Server, Password])
|
||||
of
|
||||
true -> ok;
|
||||
false -> {error, not_allowed}
|
||||
end.
|
||||
call_port(Server, [<<"tryregister">>, User, Server, Password]).
|
||||
|
||||
remove_user(User, Server) ->
|
||||
call_port(Server, [<<"removeuser">>, User, Server]).
|
||||
|
||||
remove_user(User, Server, Password) ->
|
||||
call_port(Server,
|
||||
[<<"removeuser3">>, User, Server, Password]).
|
||||
call_port(Server, [<<"removeuser3">>, User, Server, Password]).
|
||||
|
||||
call_port(Server, Msg) ->
|
||||
LServer = jid:nameprep(Server),
|
||||
ProcessName = get_process_name(LServer,
|
||||
random_instance(get_instances(LServer))),
|
||||
ProcessName ! {call, self(), Msg},
|
||||
receive {eauth, Result} -> Result end.
|
||||
-spec prog_name(binary()) -> string() | undefined.
|
||||
prog_name(Host) ->
|
||||
ejabberd_config:get_option({extauth_program, Host}).
|
||||
|
||||
random_instance(MaxNum) ->
|
||||
randoms:uniform(MaxNum) - 1.
|
||||
-spec pool_name(binary()) -> atom().
|
||||
pool_name(Host) ->
|
||||
list_to_atom("extauth_pool_" ++ binary_to_list(Host)).
|
||||
|
||||
get_instances(Server) ->
|
||||
ejabberd_config:get_option({extauth_instances, Server}, 1).
|
||||
-spec worker_name(atom(), integer()) -> atom().
|
||||
worker_name(Pool, N) ->
|
||||
list_to_atom(atom_to_list(Pool) ++ "_" ++ integer_to_list(N)).
|
||||
|
||||
loop(Port, Timeout, ProcessName, ExtPrg) ->
|
||||
receive
|
||||
{call, Caller, Msg} ->
|
||||
port_command(Port, encode(Msg)),
|
||||
receive
|
||||
{Port, {data, Data}} ->
|
||||
?DEBUG("extauth call '~p' received data response:~n~p",
|
||||
[Msg, Data]),
|
||||
Caller ! {eauth, decode(Data)},
|
||||
loop(Port, ?CALL_TIMEOUT, ProcessName, ExtPrg);
|
||||
{Port, Other} ->
|
||||
?ERROR_MSG("extauth call '~p' received strange response:~n~p",
|
||||
[Msg, Other]),
|
||||
Caller ! {eauth, false},
|
||||
loop(Port, ?CALL_TIMEOUT, ProcessName, ExtPrg)
|
||||
-spec pool_size(binary()) -> pos_integer().
|
||||
pool_size(Host) ->
|
||||
case ejabberd_config:get_option({extauth_pool_size, Host}) of
|
||||
undefined ->
|
||||
try erlang:system_info(logical_processors)
|
||||
catch _:_ -> 1
|
||||
end;
|
||||
Size ->
|
||||
Size
|
||||
end.
|
||||
|
||||
%%%===================================================================
|
||||
%%% gen_server callbacks
|
||||
%%%===================================================================
|
||||
init([Prog]) ->
|
||||
process_flag(trap_exit, true),
|
||||
{Port, OSPid} = start_port(Prog),
|
||||
Time = curr_time(),
|
||||
{ok, #state{port = Port, start_time = Time,
|
||||
prog = Prog, os_pid = OSPid}}.
|
||||
|
||||
handle_call({cmd, Cmd, EndTime}, _From, State) ->
|
||||
Timeout = EndTime - curr_time(),
|
||||
if Timeout > 0 ->
|
||||
Port = State#state.port,
|
||||
port_command(Port, Cmd),
|
||||
receive
|
||||
{Port, {data, [0, N] = Data}} when N == 0; N == 1 ->
|
||||
?DEBUG("Received response from external authentication "
|
||||
"program: ~p", [Data]),
|
||||
{reply, decode_bool(N), State};
|
||||
{Port, Data} ->
|
||||
?ERROR_MSG("Received unexpected response from external "
|
||||
"authentication program '~s': ~p "
|
||||
"(port = ~p, pid = ~w)",
|
||||
[State#state.prog, Data, Port, State#state.os_pid]),
|
||||
{reply, {error, unexpected_response}, State};
|
||||
{'EXIT', Port, Reason} ->
|
||||
handle_info({'EXIT', Port, Reason}, State)
|
||||
after Timeout ->
|
||||
?ERROR_MSG("extauth call '~p' didn't receive response",
|
||||
[Msg]),
|
||||
Caller ! {eauth, false},
|
||||
Pid = restart_instance(ProcessName, ExtPrg),
|
||||
flush_buffer_and_forward_messages(Pid),
|
||||
exit(port_terminated)
|
||||
end;
|
||||
stop ->
|
||||
Port ! {self(), close},
|
||||
receive {Port, closed} -> exit(normal) end;
|
||||
{'EXIT', Port, Reason} ->
|
||||
?CRITICAL_MSG("extauth script has exitted abruptly "
|
||||
"with reason '~p'",
|
||||
[Reason]),
|
||||
Pid = restart_instance(ProcessName, ExtPrg),
|
||||
flush_buffer_and_forward_messages(Pid),
|
||||
exit(port_terminated)
|
||||
{stop, normal, State}
|
||||
end;
|
||||
true ->
|
||||
{noreply, State}
|
||||
end.
|
||||
|
||||
flush_buffer_and_forward_messages(Pid) ->
|
||||
receive
|
||||
Message ->
|
||||
Pid ! Message, flush_buffer_and_forward_messages(Pid)
|
||||
after 0 -> true
|
||||
handle_cast(_Msg, State) ->
|
||||
{noreply, State}.
|
||||
|
||||
handle_info({'EXIT', Port, _Reason}, #state{port = Port,
|
||||
start_time = Time} = State) ->
|
||||
case curr_time() - Time of
|
||||
Diff when Diff < 1000 ->
|
||||
?ERROR_MSG("Failed to start external authentication program '~s'",
|
||||
[State#state.prog]),
|
||||
{stop, normal, State};
|
||||
_ ->
|
||||
?ERROR_MSG("External authentication program '~s' has terminated "
|
||||
"unexpectedly (pid=~w), restarting via supervisor...",
|
||||
[State#state.prog, State#state.os_pid]),
|
||||
{stop, normal, State}
|
||||
end;
|
||||
handle_info(Info, State) ->
|
||||
?WARNING_MSG("Unexpected info: ~p", [Info]),
|
||||
{noreply, State}.
|
||||
|
||||
terminate(_Reason, State) ->
|
||||
catch port_close(State#state.port),
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
-spec curr_time() -> non_neg_integer().
|
||||
curr_time() ->
|
||||
p1_time_compat:monotonic_time(milli_seconds).
|
||||
|
||||
-spec start_port(string()) -> {port(), integer() | undefined}.
|
||||
start_port(Path) ->
|
||||
Port = open_port({spawn, Path}, [{packet, 2}]),
|
||||
link(Port),
|
||||
case erlang:port_info(Port, os_pid) of
|
||||
{os_pid, OSPid} ->
|
||||
{Port, OSPid};
|
||||
undefined ->
|
||||
{Port, undefined}
|
||||
end.
|
||||
|
||||
encode(L) -> str:join(L, <<":">>).
|
||||
call_port(Server, Args) ->
|
||||
call_port(Server, Args, ?CALL_TIMEOUT).
|
||||
|
||||
decode([0, 0]) -> false;
|
||||
decode([0, 1]) -> true.
|
||||
call_port(Server, Args, Timeout) ->
|
||||
StartTime = p1_time_compat:monotonic_time(milli_seconds),
|
||||
Pool = pool_name(Server),
|
||||
PoolSize = pool_size(Server),
|
||||
I = randoms:round_robin(PoolSize),
|
||||
Cmd = str:join(Args, <<":">>),
|
||||
do_call(Cmd, I, I + PoolSize, Pool, PoolSize,
|
||||
StartTime + Timeout, StartTime).
|
||||
|
||||
-spec opt_type(extauth_instances) -> fun((pos_integer()) -> pos_integer());
|
||||
(atom()) -> [atom()].
|
||||
opt_type(extauth_instances) ->
|
||||
fun (V) when is_integer(V), V > 0 -> V end;
|
||||
opt_type(_) -> [extauth_instances].
|
||||
do_call(_, Max, Max, _, _, _, _) ->
|
||||
{error, disconnected};
|
||||
do_call(Cmd, I, Max, Pool, PoolSize, EndTime, CurrTime) ->
|
||||
Timeout = EndTime - CurrTime,
|
||||
if Timeout > 0 ->
|
||||
Proc = worker_name(Pool, (I rem PoolSize) + 1),
|
||||
try ?GEN_SERVER:call(Proc, {cmd, Cmd, EndTime}, Timeout)
|
||||
catch exit:{timeout, {?GEN_SERVER, call, _}} ->
|
||||
{error, timeout};
|
||||
exit:{_, {?GEN_SERVER, call, _}} ->
|
||||
do_call(Cmd, I+1, Max, Pool, PoolSize, EndTime, curr_time())
|
||||
end;
|
||||
true ->
|
||||
{error, timeout}
|
||||
end.
|
||||
|
||||
decode_bool(0) -> false;
|
||||
decode_bool(1) -> true.
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% Created : 7 May 2018 by Evgeny Khramtsov <ekhramtsov@process-one.net>
|
||||
%%%
|
||||
%%%
|
||||
%%% ejabberd, Copyright (C) 2002-2018 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.
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(extauth_sup).
|
||||
-behaviour(supervisor).
|
||||
|
||||
%% API
|
||||
-export([start/1, stop/1, reload/1, start_link/3]).
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
|
||||
-include("logger.hrl").
|
||||
|
||||
%%%===================================================================
|
||||
%%% API functions
|
||||
%%%===================================================================
|
||||
start(Host) ->
|
||||
case extauth:prog_name(Host) of
|
||||
undefined ->
|
||||
?ERROR_MSG("Option 'extauth_program' is not set for '~s'",
|
||||
[Host]),
|
||||
ignore;
|
||||
Prog ->
|
||||
Pool = extauth:pool_name(Host),
|
||||
ChildSpec = {Pool, {?MODULE, start_link, [Host, Prog, Pool]},
|
||||
permanent, infinity, supervisor, [?MODULE]},
|
||||
supervisor:start_child(ejabberd_backend_sup, ChildSpec)
|
||||
end.
|
||||
|
||||
stop(Host) ->
|
||||
Pool = extauth:pool_name(Host),
|
||||
supervisor:terminate_child(ejabberd_backend_sup, Pool),
|
||||
supervisor:delete_child(ejabberd_backend_sup, Pool).
|
||||
|
||||
reload(Host) ->
|
||||
Pool = extauth:pool_name(Host),
|
||||
Prog = extauth:prog_name(Host),
|
||||
PoolSize = extauth:pool_size(Host),
|
||||
try process_info(whereis(Pool), dictionary) of
|
||||
{dictionary, Dict} ->
|
||||
case proplists:get_value(extauth_program, Dict) of
|
||||
Prog ->
|
||||
OldPoolSize = try supervisor:which_children(Pool) of
|
||||
Children -> length(Children)
|
||||
catch _:_ -> PoolSize
|
||||
end,
|
||||
if OldPoolSize > PoolSize ->
|
||||
lists:foreach(
|
||||
fun(I) ->
|
||||
Worker = extauth:worker_name(Pool, I),
|
||||
supervisor:terminate_child(Pool, Worker),
|
||||
supervisor:delete_child(Pool, Worker)
|
||||
end, lists:seq(PoolSize+1, OldPoolSize));
|
||||
OldPoolSize < PoolSize ->
|
||||
lists:foreach(
|
||||
fun(I) ->
|
||||
Spec = worker_spec(Pool, Prog, I),
|
||||
supervisor:start_child(Pool, Spec)
|
||||
end, lists:seq(OldPoolSize+1, PoolSize));
|
||||
OldPoolSize == PoolSize ->
|
||||
ok
|
||||
end;
|
||||
_ ->
|
||||
stop(Host),
|
||||
start(Host)
|
||||
end
|
||||
catch _:badarg ->
|
||||
ok
|
||||
end.
|
||||
|
||||
start_link(Host, Prog, Pool) ->
|
||||
supervisor:start_link({local, Pool}, ?MODULE, [Host, Prog, Pool]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Supervisor callbacks
|
||||
%%%===================================================================
|
||||
init([Host, Prog, Pool]) ->
|
||||
PoolSize = extauth:pool_size(Host),
|
||||
Children = lists:map(
|
||||
fun(I) ->
|
||||
worker_spec(Pool, Prog, I)
|
||||
end, lists:seq(1, PoolSize)),
|
||||
put(extauth_program, Prog),
|
||||
{ok, {{one_for_one, PoolSize, 1}, Children}}.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Internal functions
|
||||
%%%===================================================================
|
||||
worker_spec(Pool, Prog, I) ->
|
||||
Worker = extauth:worker_name(Pool, I),
|
||||
{Worker, {extauth, start_link, [Worker, Prog]},
|
||||
permanent, 5000, worker, [extauth]}.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user