25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-24 17:29:28 +01:00

Change configuration file format to YAML

This commit is contained in:
Evgeniy Khramtsov 2013-08-12 22:25:05 +10:00
parent f68dfacbbf
commit 91a74e3e27
59 changed files with 5061 additions and 4085 deletions

View File

@ -109,9 +109,9 @@ install: all
#
# Configuration files
$(INSTALL) -d -m 750 $(G_USER) $(ETCDIR)
[ -f $(ETCDIR)/ejabberd.cfg ] \
&& $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg-new \
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.cfg.example $(ETCDIR)/ejabberd.cfg
[ -f $(ETCDIR)/ejabberd.yml ] \
&& $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml-new \
|| $(INSTALL) -b -m 640 $(G_USER) ejabberd.yml.example $(ETCDIR)/ejabberd.yml
$(SED) -e "s*{{rootdir}}*@prefix@*" \
-e "s*{{installuser}}*@INSTALLUSER@*" \
-e "s*{{libdir}}*@libdir@*" \
@ -120,9 +120,9 @@ install: all
-e "s*{{docdir}}*@docdir@*" \
-e "s*{{erl}}*@ERL@*" ejabberdctl.template \
> ejabberdctl.example
[ -f $(ETCDIR)/ejabberdctl.cfg ] \
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg-new \
|| $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.cfg.example $(ETCDIR)/ejabberdctl.cfg
[ -f $(ETCDIR)/ejabberdctl.yml ] \
&& $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.yml.example $(ETCDIR)/ejabberdctl.yml-new \
|| $(INSTALL) -b -m 640 $(G_USER) ejabberdctl.yml.example $(ETCDIR)/ejabberdctl.yml
$(INSTALL) -b -m 644 $(G_USER) inetrc $(ETCDIR)/inetrc
#
# Administration script

1
README
View File

@ -9,6 +9,7 @@ To compile ejabberd you need:
- GNU Make
- GCC
- Libexpat 1.95 or higher
- Libyaml 1.4 or higher
- Erlang/OTP R15B or higher.
- OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
- Zlib 1.2.3 or higher, for Stream Compression support

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,609 +0,0 @@
%%%
%%% ejabberd configuration file
%%%
%%%'
%%% The parameters used in this configuration file are explained in more detail
%%% in the ejabberd Installation and Operation Guide.
%%% Please consult the Guide in case of doubts, it is included with
%%% your copy of ejabberd, and is also available online at
%%% http://www.process-one.net/en/ejabberd/docs/
%%% This configuration file contains Erlang terms.
%%% In case you want to understand the syntax, here are the concepts:
%%%
%%% - The character to comment a line is %
%%%
%%% - Each term ends in a dot, for example:
%%% override_global.
%%%
%%% - A tuple has a fixed definition, its elements are
%%% enclosed in {}, and separated with commas:
%%% {loglevel, 4}.
%%%
%%% - A list can have as many elements as you want,
%%% and is enclosed in [], for example:
%%% [http_poll, web_admin, tls]
%%%
%%% - A keyword of ejabberd is a word in lowercase.
%%% Strings are enclosed in "" and can contain spaces, dots, ...
%%% {language, "en"}.
%%% {ldap_rootdn, "dc=example,dc=com"}.
%%%
%%% - This term includes a tuple, a keyword, a list, and two strings:
%%% {hosts, ["jabber.example.net", "im.example.com"]}.
%%%
%%%. =======================
%%%' OVERRIDE STORED OPTIONS
%%
%% Override the old values stored in the database.
%%
%%
%% Override global options (shared by all ejabberd nodes in a cluster).
%%
%%override_global.
%%
%% Override local options (specific for this particular ejabberd node).
%%
%%override_local.
%%
%% Remove the Access Control Lists before new ones are added.
%%
%%override_acls.
%%%. =========
%%%' DEBUGGING
%%
%% loglevel: Verbosity of log files generated by ejabberd.
%% 0: No ejabberd log at all (not recommended)
%% 1: Critical
%% 2: Error
%% 3: Warning
%% 4: Info
%% 5: Debug
%%
{loglevel, 4}.
%%
%% 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"]}.
%%%. ================
%%%' SERVED HOSTNAMES
%%
%% hosts: Domains served by ejabberd.
%% You can define one or several, for example:
%% {hosts, ["example.net", "example.com", "example.org"]}.
%%
{hosts, ["localhost"]}.
%%
%% route_subdomains: Delegate subdomains to other XMPP servers.
%% For example, if this ejabberd serves example.org and you want
%% to allow communication with an XMPP server called im.example.org.
%%
%%{route_subdomains, s2s}.
%%%. ===============
%%%' LISTENING PORTS
%%
%% listen: The ports ejabberd will listen on, which service each is handled
%% by and what options to start it with.
%%
{listen,
[
{5222, ejabberd_c2s, [
%%
%% If TLS is compiled in and you installed a SSL
%% certificate, specify the full path to the
%% file and uncomment this line:
%%
%%{certfile, "/path/to/ssl.pem"}, starttls,
{access, c2s},
{shaper, c2s_shaper},
{max_stanza_size, 65536}
]},
%%
%% To enable the old SSL connection method on port 5223:
%%
%%{5223, ejabberd_c2s, [
%% {access, c2s},
%% {shaper, c2s_shaper},
%% {certfile, "/path/to/ssl.pem"}, tls,
%% {max_stanza_size, 65536}
%% ]},
{5269, ejabberd_s2s_in, [
{shaper, s2s_shaper},
{max_stanza_size, 131072}
]},
%%
%% ejabberd_service: Interact with external components (transports, ...)
%%
%%{8888, ejabberd_service, [
%% {access, all},
%% {shaper_rule, fast},
%% {hosts, ["icq.example.org", "sms.example.org"],
%% [{password, "secret"}]
%% }
%% ]},
%%
%% ejabberd_stun: Handles STUN Binding requests
%%
%%{{3478, udp}, ejabberd_stun, []},
{5280, ejabberd_http, [
%%{request_handlers,
%% [
%% {["pub", "archive"], mod_http_fileserver}
%% ]},
captcha,
http_bind,
http_poll,
%%register,
web_admin
]}
]}.
%%
%% s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
%% Allowed values are: false optional required required_trusted
%% You must specify a certificate file.
%%
%%{s2s_use_starttls, optional}.
%%
%% s2s_certfile: Specify a certificate file.
%%
%%{s2s_certfile, "/path/to/ssl.pem"}.
%%
%% domain_certfile: Specify a different certificate for each served hostname.
%%
%%{domain_certfile, "example.org", "/path/to/example_org.pem"}.
%%{domain_certfile, "example.com", "/path/to/example_com.pem"}.
%%
%% S2S whitelist or blacklist
%%
%% Default s2s policy for undefined hosts.
%%
%%{s2s_default_policy, allow}.
%%
%% Allow or deny communication with specific servers.
%%
%%{{s2s_host, "goodhost.org"}, allow}.
%%{{s2s_host, "badhost.org"}, deny}.
%%
%% Outgoing S2S options
%%
%% Preferred address families (which to try first) and connect timeout
%% in milliseconds.
%%
%%{outgoing_s2s_options, [ipv4, ipv6], 10000}.
%%%. ==============
%%%' AUTHENTICATION
%%
%% auth_method: Method used to authenticate the users.
%% The default method is the internal.
%% If you want to use a different method,
%% comment this line and enable the correct ones.
%%
{auth_method, internal}.
%%
%% Store the plain passwords or hashed for SCRAM:
%%{auth_password_format, plain}.
%%{auth_password_format, scram}.
%%
%% Define the FQDN if ejabberd doesn't detect it:
%%{fqdn, "server3.example.com"}.
%%
%% Authentication using external script
%% Make sure the script is executable by ejabberd.
%%
%%{auth_method, external}.
%%{extauth_program, "/path/to/authentication/script"}.
%%
%% Authentication using ODBC
%% Remember to setup a database in the next section.
%%
%%{auth_method, odbc}.
%%
%% Authentication using PAM
%%
%%{auth_method, pam}.
%%{pam_service, "pamservicename"}.
%%
%% Authentication using LDAP
%%
%%{auth_method, ldap}.
%%
%% List of LDAP servers:
%%{ldap_servers, ["localhost"]}.
%%
%% Encryption of connection to LDAP servers:
%%{ldap_encrypt, none}.
%%{ldap_encrypt, tls}.
%%
%% Port to connect to on LDAP servers:
%%{ldap_port, 389}.
%%{ldap_port, 636}.
%%
%% LDAP manager:
%%{ldap_rootdn, "dc=example,dc=com"}.
%%
%% Password of LDAP manager:
%%{ldap_password, "******"}.
%%
%% Search base of LDAP directory:
%%{ldap_base, "dc=example,dc=com"}.
%%
%% LDAP attribute that holds user ID:
%%{ldap_uids, [{"mail", "%u@mail.example.org"}]}.
%%
%% LDAP filter:
%%{ldap_filter, "(objectClass=shadowAccount)"}.
%%
%% Anonymous login support:
%% auth_method: anonymous
%% anonymous_protocol: sasl_anon | login_anon | both
%% allow_multiple_connections: true | false
%%
%%{host_config, "public.example.org", [{auth_method, anonymous},
%% {allow_multiple_connections, false},
%% {anonymous_protocol, sasl_anon}]}.
%%
%% To use both anonymous and internal authentication:
%%
%%{host_config, "public.example.org", [{auth_method, [internal, anonymous]}]}.
%%%. ==============
%%%' DATABASE SETUP
%% ejabberd by default uses the internal Mnesia database,
%% so you do not necessarily need this section.
%% This section provides configuration examples in case
%% you want to use other database backends.
%% Please consult the ejabberd Guide for details on database creation.
%%
%% MySQL server:
%%
%%{odbc_server, {mysql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {mysql, "server", 1234, "database", "username", "password"}}.
%%
%% PostgreSQL server:
%%
%%{odbc_server, {pgsql, "server", "database", "username", "password"}}.
%%
%% If you want to specify the port:
%%{odbc_server, {pgsql, "server", 1234, "database", "username", "password"}}.
%%
%% If you use PostgreSQL, have a large database, and need a
%% faster but inexact replacement for "select count(*) from users"
%%
%%{pgsql_users_number_estimate, true}.
%%
%% ODBC compatible or MSSQL server:
%%
%%{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}.
%%
%% Number of connections to open to the database for each virtual host
%%
%%{odbc_pool_size, 10}.
%%
%% Interval to make a dummy SQL request to keep the connections to the
%% database alive. Specify in seconds: for example 28800 means 8 hours
%%
%%{odbc_keepalive_interval, undefined}.
%%%. ===============
%%%' TRAFFIC SHAPERS
%%
%% The "normal" shaper limits traffic speed to 1000 B/s
%%
{shaper, normal, {maxrate, 1000}}.
%%
%% The "fast" shaper limits traffic speed to 50000 B/s
%%
{shaper, fast, {maxrate, 50000}}.
%%
%% This option specifies the maximum number of elements in the queue
%% of the FSM. Refer to the documentation for details.
%%
{max_fsm_queue, 1000}.
%%%. ====================
%%%' ACCESS CONTROL LISTS
%%
%% The 'admin' ACL grants administrative privileges to XMPP accounts.
%% You can put here as many accounts as you want.
%%
%%{acl, admin, {user, "aleksey", "localhost"}}.
%%{acl, admin, {user, "ermine", "example.org"}}.
%%
%% Blocked users
%%
%%{acl, blocked, {user, "baduser", "example.org"}}.
%%{acl, blocked, {user, "test"}}.
%%
%% Local users: don't modify this line.
%%
{acl, local, {user_regexp, ""}}.
%%
%% More examples of ACLs
%%
%%{acl, jabberorg, {server, "jabber.org"}}.
%%{acl, aleksey, {user, "aleksey", "jabber.ru"}}.
%%{acl, test, {user_regexp, "^test"}}.
%%{acl, test, {user_glob, "test*"}}.
%%
%% Define specific ACLs in a virtual host.
%%
%%{host_config, "localhost",
%% [
%% {acl, admin, {user, "bob-local", "localhost"}}
%% ]
%%}.
%%%. ============
%%%' ACCESS RULES
%% Maximum number of simultaneous sessions allowed for a single user:
{access, max_user_sessions, [{10, all}]}.
%% Maximum number of offline messages that users can have:
{access, max_user_offline_messages, [{5000, admin}, {100, all}]}.
%% This rule allows access only for local users:
{access, local, [{allow, local}]}.
%% Only non-blocked users can use c2s connections:
{access, c2s, [{deny, blocked},
{allow, all}]}.
%% For C2S connections, all users except admins use the "normal" shaper
{access, c2s_shaper, [{none, admin},
{normal, all}]}.
%% All S2S connections use the "fast" shaper
{access, s2s_shaper, [{fast, all}]}.
%% Only admins can send announcement messages:
{access, announce, [{allow, admin}]}.
%% Only admins can use the configuration interface:
{access, configure, [{allow, admin}]}.
%% Admins of this server are also admins of the MUC service:
{access, muc_admin, [{allow, admin}]}.
%% Only accounts of the local ejabberd server can create rooms:
{access, muc_create, [{allow, local}]}.
%% All users are allowed to use the MUC service:
{access, muc, [{allow, all}]}.
%% Only accounts on the local ejabberd server can create Pubsub nodes:
{access, pubsub_createnode, [{allow, local}]}.
%% In-band registration allows registration of any possible username.
%% To disable in-band registration, replace 'allow' with 'deny'.
{access, register, [{allow, all}]}.
%% By default the frequency of account registrations from the same IP
%% is limited to 1 account every 10 minutes. To disable, specify: infinity
%%{registration_timeout, 600}.
%%
%% Define specific Access Rules in a virtual host.
%%
%%{host_config, "localhost",
%% [
%% {access, c2s, [{allow, admin}, {deny, all}]},
%% {access, register, [{deny, all}]}
%% ]
%%}.
%%%. ================
%%%' DEFAULT LANGUAGE
%%
%% language: Default language used for server messages.
%%
{language, "en"}.
%%
%% Set a different default language in a virtual host.
%%
%%{host_config, "localhost",
%% [{language, "ru"}]
%%}.
%%%. =======
%%%' CAPTCHA
%%
%% Full path to a script that generates the image.
%%
%%{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.
%%
%% Host for the URL and port where ejabberd listens for CAPTCHA requests.
%%
%%{captcha_host, "example.org:5280"}.
%%
%% Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
%%
%%{captcha_limit, 5}.
%%%. =======
%%%' MODULES
%%
%% Modules enabled in all ejabberd virtual hosts.
%%
{modules,
[
{mod_adhoc, []},
{mod_announce, [{access, announce}]}, % recommends mod_adhoc
{mod_blocking,[]}, % requires mod_privacy
{mod_caps, []},
{mod_configure,[]}, % requires mod_adhoc
{mod_disco, []},
%%{mod_echo, [{host, "echo.localhost"}]},
{mod_irc, []},
{mod_http_bind, []},
%%{mod_http_fileserver, [
%% {docroot, "/var/www"},
%% {accesslog, "/var/log/ejabberd/access.log"}
%% ]},
{mod_last, []},
{mod_muc, [
%%{host, "conference.@HOST@"},
{access, muc},
{access_create, muc_create},
{access_persistent, muc_create},
{access_admin, muc_admin}
]},
%%{mod_muc_log,[]},
{mod_offline, [{access_max_user_messages, max_user_offline_messages}]},
{mod_ping, []},
%%{mod_pres_counter,[{count, 5}, {interval, 60}]},
{mod_privacy, []},
{mod_private, []},
%%{mod_proxy65,[]},
{mod_pubsub, [
{access_createnode, pubsub_createnode},
{ignore_pep_from_offline, true}, % reduces resource comsumption, but XEP incompliant
%%{ignore_pep_from_offline, false}, % XEP compliant, but increases resource comsumption
{last_item_cache, false},
{plugins, ["flat", "hometree", "pep"]} % pep requires mod_caps
]},
{mod_register, [
%%
%% Protect In-Band account registrations with CAPTCHA.
%%
%%{captcha_protected, true},
%%
%% Set the minimum informational entropy for passwords.
%%
%%{password_strength, 32},
%%
%% After successful registration, the user receives
%% a message with this subject and body.
%%
{welcome_message, {"Welcome!",
"Hi.\nWelcome to this XMPP server."}},
%%
%% When a user registers, send a notification to
%% these XMPP accounts.
%%
%%{registration_watchers, ["admin1@example.org"]},
%%
%% Only clients in the server machine can register accounts
%%
{ip_access, [{allow, "127.0.0.0/8"},
{deny, "0.0.0.0/0"}]},
%%
%% Local c2s or remote s2s users cannot register accounts
%%
%%{access_from, deny},
{access, register}
]},
%%{mod_register_web, [
%%
%% When a user registers, send a notification to
%% these XMPP accounts.
%%
%%{registration_watchers, ["admin1@example.org"]}
%% ]},
{mod_roster, []},
%%{mod_service_log,[]},
{mod_shared_roster,[]},
{mod_stats, []},
{mod_time, []},
{mod_vcard, []},
{mod_version, []}
]}.
%%
%% Enable modules with custom options in a specific virtual host
%%
%%{host_config, "localhost",
%% [{{add, modules},
%% [
%% {mod_echo, [{host, "mirror.localhost"}]}
%% ]
%% }
%% ]}.
%%%.
%%%'
%%% $Id$
%%% Local Variables:
%%% mode: erlang
%%% End:
%%% vim: set filetype=erlang tabstop=8 foldmarker=%%%',%%%. foldmethod=marker:

615
ejabberd.yml.example Normal file
View File

@ -0,0 +1,615 @@
###
### ejabberd configuration file
###
###
### The parameters used in this configuration file are explained in more detail
### in the ejabberd Installation and Operation Guide.
### Please consult the Guide in case of doubts, it is included with
### your copy of ejabberd, and is also available online at
### http://www.process-one.net/en/ejabberd/docs/
### The configuration file is written in YAML.
### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
### However, ejabberd treats different literals as different types:
###
### - unquoted or single-quoted strings. They are called "atoms".
### Example: dog, 'Jupiter', '3.14159', YELLOW
###
### - numeric literals. Example: 3, -45.0, .0
###
### - quoted or folded strings.
### Examples of quoted string: "Lizzard", "orange".
### Example of folded string:
### > Art thou not Romeo,
### and a Montague?
### =========
### DEBUGGING
##
## loglevel: Verbosity of log files generated by ejabberd.
## 0: No ejabberd log at all (not recommended)
## 1: Critical
## 2: Error
## 3: Warning
## 4: Info
## 5: Debug
##
loglevel: 4
##
## 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"
### ================
### SERVED HOSTNAMES
##
## hosts: Domains served by ejabberd.
## You can define one or several, for example:
## hosts:
## - "example.net"
## - "example.com"
## - "example.org"
##
hosts:
- "localhost"
##
## route_subdomains: Delegate subdomains to other XMPP servers.
## For example, if this ejabberd serves example.org and you want
## to allow communication with an XMPP server called im.example.org.
##
## route_subdomains: s2s
### ===============
### LISTENING PORTS
##
## listen: The ports ejabberd will listen on, which service each is handled
## by and what options to start it with.
##
listen:
-
port: 5222
module: ejabberd_c2s
##
## If TLS is compiled in and you installed a SSL
## certificate, specify the full path to the
## file and uncomment this line:
##
## certfile: "/path/to/ssl.pem"
## starttls: true
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s
-
port: 5269
module: ejabberd_s2s_in
##
## ejabberd_service: Interact with external components (transports, ...)
##
## -
## port: 8888
## module: ejabberd_service
## access: all
## shaper_rule: fast
## ip: "127.0.0.1"
## hosts:
## "icq.example.org":
## password: "secret"
## "sms.example.org":
## password: "secret"
##
## ejabberd_stun: Handles STUN Binding requests
##
## -
## port: 3478
## transport: udp
## module: ejabberd_stun
##
## To handle XML-RPC requests that provide admin credentials:
##
## -
## port: 4560
## module: ejabberd_xmlrpc
-
port: 5280
module: ejabberd_http
## request_handlers:
## "/pub/archive": mod_http_fileserver
web_admin: true
http_poll: true
http_bind: true
## register: true
captcha: true
##
## s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
## Allowed values are: false optional required required_trusted
## You must specify a certificate file.
##
## s2s_use_starttls: optional
##
## s2s_certfile: Specify a certificate file.
##
## s2s_certfile: "/path/to/ssl.pem"
##
## domain_certfile: Specify a different certificate for each served hostname.
##
## host_config:
## "example.org":
## domain_certfile: "/path/to/example_org.pem"
## "example.com":
## domain_certfile: "/path/to/example_com.pem"
##
## S2S whitelist or blacklist
##
## Default s2s policy for undefined hosts.
##
## s2s_policy: s2s_access
##
## Outgoing S2S options
##
## Preferred address families (which to try first) and connect timeout
## in milliseconds.
##
## outgoing_s2s_families:
## - ipv4
## - ipv6
## outgoing_s2s_timeout: 10000
### ==============
### AUTHENTICATION
##
## auth_method: Method used to authenticate the users.
## The default method is the internal.
## If you want to use a different method,
## comment this line and enable the correct ones.
##
auth_method: internal
##
## Store the plain passwords or hashed for SCRAM:
## auth_password_format: plain
## auth_password_format: scram
##
## Define the FQDN if ejabberd doesn't detect it:
## fqdn: "server3.example.com"
##
## Authentication using external script
## Make sure the script is executable by ejabberd.
##
## auth_method: external
## extauth_program: "/path/to/authentication/script"
##
## Authentication using ODBC
## Remember to setup a database in the next section.
##
## auth_method: odbc
##
## Authentication using PAM
##
## auth_method: pam
## pam_service: "pamservicename"
##
## Authentication using LDAP
##
## auth_method: ldap
##
## List of LDAP servers:
## ldap_servers:
## - "localhost"
##
## Encryption of connection to LDAP servers:
## ldap_encrypt: none
## ldap_encrypt: tls
##
## Port to connect to on LDAP servers:
## ldap_port: 389
## ldap_port: 636
##
## LDAP manager:
## ldap_rootdn: "dc=example,dc=com"
##
## Password of LDAP manager:
## ldap_password: "******"
##
## Search base of LDAP directory:
## ldap_base: "dc=example,dc=com"
##
## LDAP attribute that holds user ID:
## ldap_uids:
## - "mail": "%u@mail.example.org"
##
## LDAP filter:
## ldap_filter: "(objectClass=shadowAccount)"
##
## Anonymous login support:
## auth_method: anonymous
## anonymous_protocol: sasl_anon | login_anon | both
## allow_multiple_connections: true | false
##
## host_config:
## "public.example.org":
## auth_method: anonymous
## allow_multiple_connections: false
## anonymous_protocol: sasl_anon
##
## To use both anonymous and internal authentication:
##
## host_config:
## "public.example.org":
## auth_method:
## - internal
## - anonymous
### ==============
### DATABASE SETUP
## ejabberd by default uses the internal Mnesia database,
## so you do not necessarily need this section.
## This section provides configuration examples in case
## you want to use other database backends.
## Please consult the ejabberd Guide for details on database creation.
##
## MySQL server:
##
## odbc_type: mysql
## odbc_server: "server"
## odbc_database: "database"
## odbc_username: "username"
## odbc_password: "password"
##
## If you want to specify the port:
## odbc_port: 1234
##
## PostgreSQL server:
##
## odbc_type: pgsql
## odbc_server: "server"
## odbc_database: "database"
## odbc_username: "username"
## odbc_password: "password"
##
## If you want to specify the port:
## odbc_port: 1234
##
## If you use PostgreSQL, have a large database, and need a
## faster but inexact replacement for "select count(*) from users"
##
## pgsql_users_number_estimate: true
##
## ODBC compatible or MSSQL server:
##
## odbc_type: odbc
## odbc_server: "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"
##
## Number of connections to open to the database for each virtual host
##
## odbc_pool_size: 10
##
## Interval to make a dummy SQL request to keep the connections to the
## database alive. Specify in seconds: for example 28800 means 8 hours
##
## odbc_keepalive_interval: undefined
### ===============
### TRAFFIC SHAPERS
shaper:
##
## The "normal" shaper limits traffic speed to 1000 B/s
##
normal: 1000
##
## The "fast" shaper limits traffic speed to 50000 B/s
##
fast: 50000
##
## This option specifies the maximum number of elements in the queue
## of the FSM. Refer to the documentation for details.
##
max_fsm_queue: 1000
###. ====================
###' ACCESS CONTROL LISTS
acl:
##
## The 'admin' ACL grants administrative privileges to XMPP accounts.
## You can put here as many accounts as you want.
##
## admin:
## user:
## - "aleksey": "localhost"
## - "ermine": "example.org"
##
## Blocked users
##
## blocked:
## user:
## - "baduser": "example.org"
## - "test": global
## Local users: don't modify this.
##
local:
user_regexp:
- "": global
##
## More examples of ACLs
##
## jabberorg:
## server:
## - "jabber.org"
## aleksey:
## user:
## - "aleksey": "jabber.ru"
## test:
## user_regexp:
## - "^test": global
## user_glob:
## - "test*": global
##
## Loopback network
##
loopback:
ip:
- "127.0.0.0/8"
##
## Bad XMPP servers
##
## bad_servers:
## server:
## - "xmpp.zombie.org"
## - "xmpp.spam.com"
##
## Define specific ACLs in a virtual host.
##
## host_config:
## "localhost":
## acl:
## admin:
## user:
## - "bob-local": "localhost"
### ============
### ACCESS RULES
access:
## Maximum number of simultaneous sessions allowed for a single user:
max_user_sessions:
all: 10
## Maximum number of offline messages that users can have:
max_user_offline_messages:
admin: 5000
all: 100
## This rule allows access only for local users:
local:
local: allow
## Only non-blocked users can use c2s connections:
c2s:
blocked: deny
all: allow
## For C2S connections, all users except admins use the "normal" shaper
c2s_shaper:
admin: none
all: normal
## All S2S connections use the "fast" shaper
s2s_shaper:
all: fast
## Only admins can send announcement messages:
announce:
admin: allow
## Only admins can use the configuration interface:
configure:
admin: allow
## Admins of this server are also admins of the MUC service:
muc_admin:
admin: allow
## Only accounts of the local ejabberd server can create rooms:
muc_create:
local: allow
## All users are allowed to use the MUC service:
muc:
all: allow
## Only accounts on the local ejabberd server can create Pubsub nodes:
pubsub_createnode:
local: allow
## In-band registration allows registration of any possible username.
## To disable in-band registration, replace 'allow' with 'deny'.
register:
all: allow
## Only allow to register from localhost
trusted_network:
loopback: allow
## Do not establish S2S connections with bad servers
## s2s_access:
## bad_servers: deny
## all: allow
## By default the frequency of account registrations from the same IP
## is limited to 1 account every 10 minutes. To disable, specify: infinity
## registration_timeout: 600
##
## Define specific Access Rules in a virtual host.
##
## host_config:
## "localhost":
## access:
## c2s:
## admin: allow
## all: deny
## register:
## all: deny
### ================
### DEFAULT LANGUAGE
##
## language: Default language used for server messages.
##
language: "en"
##
## Set a different default language in a virtual host.
##
## host_config:
## "localhost":
## language: "ru"
### =======
### CAPTCHA
##
## Full path to a script that generates the image.
##
## captcha_cmd: "/lib/ejabberd/priv/bin/captcha.sh"
##
## Host for the URL and port where ejabberd listens for CAPTCHA requests.
##
## captcha_host: "example.org:5280"
##
## Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
##
## captcha_limit: 5
### =======
### MODULES
##
## Modules enabled in all ejabberd virtual hosts.
##
modules:
mod_adhoc: {}
mod_announce: # recommends mod_adhoc
access: announce
mod_blocking: {} # requires mod_privacy
mod_caps: {}
mod_configure: {} # requires mod_adhoc
mod_disco: {}
## mod_echo: {}
mod_irc: {}
mod_http_bind: {}
## mod_http_fileserver:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
mod_last: {}
mod_muc:
## host: "conference.@HOST@"
access: muc
access_create: muc_create
access_persistent: muc_create
access_admin: muc_admin
## mod_muc_log: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
## mod_pres_counter:
## count: 5
## interval: 60
mod_privacy: {}
mod_private: {}
## mod_proxy65: {}
mod_pubsub:
access_createnode: pubsub_createnode
## reduces resource comsumption, but XEP incompliant
ignore_pep_from_offline: true
## XEP compliant, but increases resource comsumption
## ignore_pep_from_offline: false
last_item_cache: false
plugins:
- "flat"
- "hometree"
- "pep" # pep requires mod_caps
mod_register:
##
## Protect In-Band account registrations with CAPTCHA.
##
## captcha_protected: true
##
## Set the minimum informational entropy for passwords.
##
## password_strength: 32
##
## After successful registration, the user receives
## a message with this subject and body.
##
welcome_message:
subject: "Welcome!"
body: |-
Hi.
Welcome to this XMPP server.
##
## When a user registers, send a notification to
## these XMPP accounts.
##
## registration_watchers:
## - "admin1@example.org"
##
## Only clients in the server machine can register accounts
##
ip_access: trusted_network
##
## Local c2s or remote s2s users cannot register accounts
##
## access_from: deny
access: register
mod_roster: {}
mod_shared_roster: {}
mod_stats: {}
mod_time: {}
mod_vcard: {}
mod_version: {}
##
## Enable modules with custom options in a specific virtual host
##
## host_config:
## "localhost":
## add:
## modules:
## mod_echo:
## host: "mirror.localhost"
### Local Variables:
### mode: yaml
### End:
### vim: set filetype=yaml tabstop=8

View File

@ -65,7 +65,7 @@ if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then
. "$EJABBERDCTL_CONFIG_PATH"
fi
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.yml
fi
if [ "$LOGS_DIR" = "" ] ; then
LOGS_DIR={{localstatedir}}/log/ejabberd

View File

@ -56,6 +56,7 @@ Deps = [{p1_cache_tab, ".*", {git, "git://github.com/processone/cache_tab"}},
{p1_tls, ".*", {git, "git://github.com/processone/tls"}},
{p1_stringprep, ".*", {git, "git://github.com/processone/stringprep"}},
{p1_xml, ".*", {git, "git://github.com/processone/xml"}},
{p1_yaml, ".*", {git, "git://github.com/processone/p1_yaml"}},
{xmlrpc, ".*", {git, "git://github.com/rds13/xmlrpc"}}],
ConfigureCmd = fun(Pkg, Flags) ->

View File

@ -28,7 +28,7 @@ ConfiguredOTPApps = lists:flatmap(
OTPApps = RequiredOTPApps ++ ConfiguredOTPApps,
DepRequiredApps = [p1_cache_tab, p1_tls, p1_stringprep, p1_xml, xmlrpc],
DepRequiredApps = [p1_cache_tab, p1_tls, p1_stringprep, p1_xml, p1_yaml, xmlrpc],
DepConfiguredApps = lists:flatmap(
fun({mysql, true}) -> [p1_mysql];
@ -39,7 +39,7 @@ DepConfiguredApps = lists:flatmap(
({json, true}) -> [jiffy];
({iconv, true}) -> [p1_iconv];
({http, true}) -> [ibrowse, lhttpc];
({lager, true}) -> [lager];
({lager, true}) -> [lager, goldrush];
({lager, false}) -> [p1_logger];
(_) -> []
end, Vars),
@ -89,7 +89,7 @@ Overlay = [
{template, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{template, "../ejabberdctl.template", "bin/ejabberdctl"},
{copy, "../ejabberdctl.cfg.example", "etc/ejabberd/ejabberdctl.cfg"},
{copy, "../ejabberd.cfg.example", "etc/ejabberd/ejabberd.cfg"},
{copy, "../ejabberd.yml.example", "etc/ejabberd/ejabberd.yml"},
{copy, "../inetrc", "etc/ejabberd/inetrc"},
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}
],

View File

@ -29,35 +29,38 @@
-author('alexey@process-one.net').
-export([start/0, to_record/3, add/3, add_list/3,
add_local/3, add_list_local/3,
match_rule/3, match_acl/3]).
add_local/3, add_list_local/3, load_from_config/0,
match_rule/3, match_acl/3, transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jlib.hrl").
-record(acl, {aclname, aclspec}).
-record(access, {name :: access_name(),
rules = [] :: [access_rule()]}).
-type regexp() :: binary().
-type glob() :: binary().
-type access_name() :: atom().
-type access_rule() :: {atom(), any()}.
-type host() :: binary().
-type aclname() :: {atom(), binary() | global}.
-type aclspec() :: all | none |
{user, binary()} |
{user, binary(), binary()} |
{user, {binary(), host()} | binary()} |
{server, binary()} |
{resource, binary()} |
{user_regexp, regexp()} |
{shared_group, binary()} |
{shared_group, binary(), binary()} |
{user_regexp, regexp(), binary()} |
{user_regexp, {regexp(), host()} | regexp()} |
{shared_group, {binary(), host()} | binary()} |
{user_regexp, {regexp(), host()} | regexp()} |
{server_regexp, regexp()} |
{resource_regexp, regexp()} |
{node_regexp, regexp(), regexp()} |
{user_glob, glob()} |
{user_glob, glob(), binary()} |
{node_regexp, {regexp(), regexp()}} |
{user_glob, {glob(), host()} | glob()} |
{server_glob, glob()} |
{resource_glob, glob()} |
{node_glob, glob(), glob()}.
{ip, {inet:ip_address(), integer()}} |
{node_glob, {glob(), glob()}}.
-type acl() :: #acl{aclname :: aclname(),
aclspec :: aclspec()}.
@ -65,12 +68,23 @@
-export_type([acl/0]).
start() ->
case catch mnesia:table_info(acl, storage_type) of
disc_copies ->
mnesia:delete_table(acl);
_ ->
ok
end,
mnesia:create_table(acl,
[{disc_copies, [node()]}, {type, bag},
[{ram_copies, [node()]}, {type, bag},
{local_content, true},
{attributes, record_info(fields, acl)}]),
mnesia:create_table(access,
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, access)}]),
mnesia:add_table_copy(acl, node(), ram_copies),
update_table(),
mnesia:add_table_copy(access, node(), ram_copies),
load_from_config(),
ok.
-spec to_record(binary(), atom(), aclspec()) -> acl().
@ -82,7 +96,7 @@ to_record(Host, ACLName, ACLSpec) ->
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
add(Host, ACLName, ACLSpec) ->
{ResL, BadNodes} = rpc:multicall(ejabberd_cluster:get_nodes(),
{ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
?MODULE, add_local,
[Host, ACLName, ACLSpec]),
case lists:keyfind(aborted, 1, ResL) of
@ -109,7 +123,7 @@ add_local(Host, ACLName, ACLSpec) ->
-spec add_list(binary(), [acl()], boolean()) -> ok | {error, any()}.
add_list(Host, ACLs, Clear) ->
{ResL, BadNodes} = rpc:multicall(ejabberd_cluster:get_nodes(),
{ResL, BadNodes} = rpc:multicall(mnesia:system_info(running_db_nodes),
?MODULE, add_list_local,
[Host, ACLs, Clear]),
case lists:keyfind(aborted, 1, ResL) of
@ -147,130 +161,196 @@ add_list_local(Host, ACLs, Clear) ->
end,
mnesia:transaction(F).
normalize(A) -> jlib:nodeprep(iolist_to_binary(A)).
-spec add_access(binary() | global,
access_name(), [access_rule()]) -> ok | {error, any()}.
normalize_spec({A, B}) -> {A, normalize(B)};
normalize_spec({A, B, C}) ->
{A, normalize(B), normalize(C)};
normalize_spec(all) -> all;
normalize_spec(none) -> none.
add_access(Host, Access, Rules) ->
case mnesia:transaction(
fun() ->
mnesia:write(
#access{name = {Access, Host},
rules = Rules})
end) of
{atomic, ok} ->
ok;
Err ->
{error, Err}
end.
-spec match_rule(global | binary(), atom(), jid() | ljid()) -> any().
-spec load_from_config() -> ok.
match_rule(global, Rule, JID) ->
case Rule of
all -> allow;
none -> deny;
_ ->
case ejabberd_config:get_global_option(
{access, Rule, global}, fun(V) -> V end)
of
undefined -> deny;
GACLs -> match_acls(GACLs, JID, global)
end
end;
match_rule(Host, Rule, JID) ->
case Rule of
all -> allow;
none -> deny;
_ ->
case ejabberd_config:get_global_option(
{access, Rule, global}, fun(V) -> V end)
of
undefined ->
case ejabberd_config:get_global_option(
{access, Rule, Host}, fun(V) -> V end)
of
undefined -> deny;
ACLs -> match_acls(ACLs, JID, Host)
end;
GACLs ->
case ejabberd_config:get_global_option(
{access, Rule, Host}, fun(V) -> V end)
of
undefined -> match_acls(GACLs, JID, Host);
ACLs ->
case lists:reverse(GACLs) of
[{allow, all} | Rest] ->
match_acls(lists:reverse(Rest) ++
ACLs ++ [{allow, all}],
JID, Host);
_ -> match_acls(GACLs ++ ACLs, JID, Host)
end
end
end
load_from_config() ->
Hosts = [global|?MYHOSTS],
lists:foreach(
fun(Host) ->
ACLs = ejabberd_config:get_option(
{acl, Host}, fun(V) -> V end, []),
AccessRules = ejabberd_config:get_option(
{access, Host}, fun(V) -> V end, []),
lists:foreach(
fun({ACLName, SpecList}) ->
lists:foreach(
fun({ACLType, ACLSpecs}) when is_list(ACLSpecs) ->
lists:foreach(
fun(ACLSpec) ->
add(Host, ACLName,
{ACLType, ACLSpec})
end, lists:flatten(ACLSpecs));
({ACLType, ACLSpecs}) ->
add(Host, ACLName, {ACLType, ACLSpecs})
end, lists:flatten(SpecList))
end, ACLs),
lists:foreach(
fun({Access, Rules}) ->
add_access(Host, Access, Rules)
end, AccessRules)
end, Hosts).
b(S) ->
iolist_to_binary(S).
nodeprep(S) ->
jlib:nodeprep(b(S)).
nameprep(S) ->
jlib:nameprep(b(S)).
resourceprep(S) ->
jlib:resourceprep(b(S)).
normalize_spec(Spec) ->
case Spec of
all -> all;
none -> none;
{user, {U, S}} -> {user, {nodeprep(U), nameprep(S)}};
{user, U} -> {user, nodeprep(U)};
{shared_group, {G, H}} -> {shared_group, {b(G), nameprep(H)}};
{shared_group, G} -> {shared_group, b(G)};
{user_regexp, {UR, S}} -> {user_regexp, {b(UR), nameprep(S)}};
{user_regexp, UR} -> {user_regexp, b(UR)};
{node_regexp, {UR, SR}} -> {node_regexp, {b(UR), b(SR)}};
{user_glob, {UR, S}} -> {user_glob, {b(UR), nameprep(S)}};
{user_glob, UR} -> {user_glob, b(UR)};
{node_glob, {UR, SR}} -> {node_glob, {b(UR), b(SR)}};
{server, S} -> {server, nameprep(S)};
{resource, R} -> {resource, resourceprep(R)};
{server_regexp, SR} -> {server_regexp, b(SR)};
{server_glob, S} -> {server_glob, b(S)};
{resource_glob, R} -> {resource_glob, b(R)};
{ip, S} ->
case parse_ip_netmask(b(S)) of
{ok, Net, Mask} ->
{ip, {Net, Mask}};
error ->
?INFO_MSG("Invalid network address: ~p", [S]),
none
end
end.
-spec match_rule(global | binary(), access_name(),
jid() | ljid() | inet:ip_address()) -> any().
match_rule(_Host, all, _JID) ->
allow;
match_rule(_Host, none, _JID) ->
deny;
match_rule(Host, Access, JID) ->
GAccess = ets:lookup(access, {Access, global}),
LAccess = if Host /= global ->
ets:lookup(access, {Access, Host});
true ->
[]
end,
case GAccess ++ LAccess of
[] ->
?WARNING_MSG("Attempt to match against unspecified "
"access rule '~s' (scope: ~s)",
[Access, Host]),
deny;
AccessList ->
Rules = lists:flatmap(
fun(#access{rules = Rs}) ->
Rs
end, AccessList),
match_acls(Rules, JID, Host)
end.
match_acls([], _, _Host) -> deny;
match_acls([{Access, ACL} | ACLs], JID, Host) ->
match_acls([{ACL, Access} | ACLs], JID, Host) ->
case match_acl(ACL, JID, Host) of
true -> Access;
_ -> match_acls(ACLs, JID, Host)
end.
-spec match_acl(atom(), jid() | ljid(), binary()) -> boolean().
-spec match_acl(atom(),
jid() | ljid() | inet:ip_address(),
binary()) -> boolean().
match_acl(all, _JID, _Host) ->
true;
match_acl(none, _JID, _Host) ->
false;
match_acl(ACL, IP, Host) when tuple_size(IP) == 4;
tuple_size(IP) == 8 ->
lists:any(
fun(#acl{aclspec = {ip, {Net, Mask}}}) ->
is_ip_match(IP, Net, Mask);
(_) ->
false
end,
ets:lookup(acl, {ACL, Host}) ++
ets:lookup(acl, {ACL, global}));
match_acl(ACL, JID, Host) ->
case ACL of
all -> true;
none -> false;
_ ->
{User, Server, Resource} = jlib:jid_tolower(JID),
lists:any(fun (#acl{aclspec = Spec}) ->
case Spec of
all -> true;
{user, U} ->
U == User andalso
(Host == Server orelse
Host == global andalso
lists:member(Server, ?MYHOSTS));
{user, U, S} -> U == User andalso S == Server;
{server, S} -> S == Server;
{resource, R} -> R == Resource;
{user_regexp, UR} ->
(Host == Server orelse
Host == global andalso
lists:member(Server, ?MYHOSTS))
andalso is_regexp_match(User, UR);
{shared_group, G} ->
Mod = loaded_shared_roster_module(Host),
Mod:is_user_in_group({User, Server}, G, Host);
{shared_group, G, H} ->
Mod = loaded_shared_roster_module(H),
Mod:is_user_in_group({User, Server}, G, H);
{user_regexp, UR, S} ->
S == Server andalso is_regexp_match(User, UR);
{server_regexp, SR} ->
is_regexp_match(Server, SR);
{resource_regexp, RR} ->
is_regexp_match(Resource, RR);
{node_regexp, UR, SR} ->
is_regexp_match(Server, SR) andalso
is_regexp_match(User, UR);
{user_glob, UR} ->
(Host == Server orelse
Host == global andalso
lists:member(Server, ?MYHOSTS))
andalso is_glob_match(User, UR);
{user_glob, UR, S} ->
S == Server andalso is_glob_match(User, UR);
{server_glob, SR} -> is_glob_match(Server, SR);
{resource_glob, RR} ->
is_glob_match(Resource, RR);
{node_glob, UR, SR} ->
is_glob_match(Server, SR) andalso
is_glob_match(User, UR);
WrongSpec ->
?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
"config file and reload it with the override_a"
"cls option enabled",
[WrongSpec]),
false
end
end,
ets:lookup(acl, {ACL, global}) ++
ets:lookup(acl, {ACL, Host}))
end.
{User, Server, Resource} = jlib:jid_tolower(JID),
lists:any(
fun(#acl{aclspec = Spec}) ->
case Spec of
all -> true;
{user, {U, S}} -> U == User andalso S == Server;
{user, U} ->
U == User andalso
lists:member(Server, ?MYHOSTS);
{server, S} -> S == Server;
{resource, R} -> R == Resource;
{shared_group, {G, H}} ->
Mod = loaded_shared_roster_module(H),
Mod:is_user_in_group({User, Server}, G, H);
{shared_group, G} ->
Mod = loaded_shared_roster_module(Host),
Mod:is_user_in_group({User, Server}, G, Host);
{user_regexp, {UR, S}} ->
S == Server andalso is_regexp_match(User, UR);
{user_regexp, UR} ->
lists:member(Server, ?MYHOSTS)
andalso is_regexp_match(User, UR);
{server_regexp, SR} ->
is_regexp_match(Server, SR);
{resource_regexp, RR} ->
is_regexp_match(Resource, RR);
{node_regexp, {UR, SR}} ->
is_regexp_match(Server, SR) andalso
is_regexp_match(User, UR);
{user_glob, {UR, S}} ->
S == Server andalso is_glob_match(User, UR);
{user_glob, UR} ->
lists:member(Server, ?MYHOSTS)
andalso is_glob_match(User, UR);
{server_glob, SR} -> is_glob_match(Server, SR);
{resource_glob, RR} ->
is_glob_match(Resource, RR);
{node_glob, {UR, SR}} ->
is_glob_match(Server, SR) andalso
is_glob_match(User, UR);
WrongSpec ->
?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
"config file and reload it with the override_a"
"cls option enabled",
[WrongSpec]),
false
end
end,
ets:lookup(acl, {ACL, Host}) ++
ets:lookup(acl, {ACL, global})).
is_regexp_match(String, RegExp) ->
case ejabberd_regexp:run(String, RegExp) of
@ -286,34 +366,115 @@ is_glob_match(String, Glob) ->
is_regexp_match(String,
ejabberd_regexp:sh_to_awk(Glob)).
is_ip_match({_, _, _, _} = 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) ->
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(_, _, _) ->
false.
ip_to_integer({IP1, IP2, IP3, IP4}) ->
IP1 bsl 8 bor IP2 bsl 8 bor IP3 bsl 8 bor IP4;
ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7,
IP8}) ->
IP1 bsl 16 bor IP2 bsl 16 bor IP3 bsl 16 bor IP4 bsl 16
bor IP5
bsl 16
bor IP6
bsl 16
bor IP7
bsl 16
bor IP8.
loaded_shared_roster_module(Host) ->
case gen_mod:is_loaded(Host, mod_shared_roster_ldap) of
true -> mod_shared_roster_ldap;
false -> mod_shared_roster
end.
update_table() ->
Fields = record_info(fields, acl),
case mnesia:table_info(acl, attributes) of
Fields ->
ejabberd_config:convert_table_to_binary(
acl, Fields, bag,
fun(#acl{aclspec = Spec}) when is_tuple(Spec) ->
element(2, Spec);
(_) ->
'$next'
end,
fun(#acl{aclname = {ACLName, Host},
aclspec = Spec} = R) ->
NewHost = if Host == global ->
Host;
true ->
iolist_to_binary(Host)
end,
R#acl{aclname = {ACLName, NewHost},
aclspec = normalize_spec(Spec)}
end);
_ ->
?INFO_MSG("Recreating acl table", []),
mnesia:transform_table(acl, ignore, Fields)
parse_ip_netmask(S) ->
case str:tokens(S, <<"/">>) of
[IPStr] ->
case inet_parse:address(binary_to_list(IPStr)) of
{ok, {_, _, _, _} = IP} -> {ok, IP, 32};
{ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
_ -> error
end;
[IPStr, MaskStr] ->
case catch jlib:binary_to_integer(MaskStr) of
Mask when is_integer(Mask), Mask >= 0 ->
case inet_parse:address(binary_to_list(IPStr)) of
{ok, {_, _, _, _} = IP} when Mask =< 32 ->
{ok, IP, Mask};
{ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
{ok, IP, Mask};
_ -> error
end;
_ -> error
end;
_ -> error
end.
transform_options(Opts) ->
Opts1 = lists:foldl(fun transform_options/2, [], Opts),
{ACLOpts, Opts2} = lists:mapfoldl(
fun({acl, Os}, Acc) ->
{Os, Acc};
(O, Acc) ->
{[], [O|Acc]}
end, [], Opts1),
{AccessOpts, Opts3} = lists:mapfoldl(
fun({access, Os}, Acc) ->
{Os, Acc};
(O, Acc) ->
{[], [O|Acc]}
end, [], Opts2),
ACLOpts1 = ejabberd_config:collect_options(lists:flatten(ACLOpts)),
AccessOpts1 = case ejabberd_config:collect_options(
lists:flatten(AccessOpts)) of
[] -> [];
L1 -> [{access, L1}]
end,
ACLOpts2 = case lists:map(
fun({ACLName, Os}) ->
{ACLName, ejabberd_config:collect_options(Os)}
end, ACLOpts1) of
[] -> [];
L2 -> [{acl, L2}]
end,
ACLOpts2 ++ AccessOpts1 ++ Opts3.
transform_options({acl, Name, Type}, Opts) ->
T = case Type of
all -> all;
none -> none;
{user, U} -> {user, [U]};
{user, U, S} -> {user, [[{U, S}]]};
{shared_group, G} -> {shared_group, [G]};
{shared_group, G, H} -> {shared_group, [[{G, H}]]};
{user_regexp, UR} -> {user_regexp, [UR]};
{user_regexp, UR, S} -> {user_regexp, [[{UR, S}]]};
{node_regexp, UR, SR} -> {node_regexp, [[{UR, SR}]]};
{user_glob, UR} -> {user_glob, [UR]};
{user_glob, UR, S} -> {user_glob, [[{UR, S}]]};
{node_glob, UR, SR} -> {node_glob, [[{UR, SR}]]};
{server, S} -> {server, [S]};
{resource, R} -> {resource, [R]};
{server_regexp, SR} -> {server_regexp, [SR]};
{server_glob, S} -> {server_glob, [S]};
{ip, S} -> {ip, [S]};
{resource_glob, R} -> {resource_glob, [R]}
end,
[{acl, [{Name, [T]}]}|Opts];
transform_options({access, Name, Rules}, Opts) ->
NewRules = [{ACL, Action} || {Action, ACL} <- Rules],
[{access, [{Name, NewRules}]}|Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].

View File

@ -204,11 +204,11 @@ get_local_fqdn() ->
Str when is_binary(Str) -> Str;
_ ->
<<"unknown-fqdn, please configure fqdn "
"option in ejabberd.cfg!">>
"option in ejabberd.yml!">>
end.
get_local_fqdn2() ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
fqdn, fun iolist_to_binary/1) of
ConfiguredFqdn when is_binary(ConfiguredFqdn) ->
ConfiguredFqdn;

View File

@ -164,6 +164,12 @@ commands() ->
module = ejd2odbc, function = export,
args = [{host, string}, {file, string}], result = {res, rescode}},
#ejabberd_commands{name = convert_to_yaml, tags = [config],
desc = "Convert the input file from Erlang to YAML format",
module = ejabberd_config, function = convert_to_yaml,
args = [{in, string}, {out, string}],
result = {res, rescode}},
#ejabberd_commands{name = delete_expired_messages, tags = [purge],
desc = "Delete expired offline messages from database",
module = ?MODULE, function = delete_expired_messages,

View File

@ -47,12 +47,14 @@ start(normal, _Args) ->
db_init(),
start(),
translate:start(),
acl:start(),
ejabberd_ctl:init(),
ejabberd_commands:init(),
ejabberd_admin:start(),
gen_mod:start(),
ejabberd_config:start(),
set_loglevel_from_config(),
acl:start(),
shaper:start(),
connect_nodes(),
Sup = ejabberd_sup:start_link(),
ejabberd_rdbms:start(),
@ -119,7 +121,7 @@ db_init() ->
start_modules() ->
lists:foreach(
fun(Host) ->
Modules = ejabberd_config:get_local_option(
Modules = ejabberd_config:get_option(
{modules, Host},
fun(Mods) ->
lists:map(
@ -137,7 +139,7 @@ start_modules() ->
stop_modules() ->
lists:foreach(
fun(Host) ->
Modules = ejabberd_config:get_local_option(
Modules = ejabberd_config:get_option(
{modules, Host},
fun(Mods) ->
lists:map(
@ -152,7 +154,7 @@ stop_modules() ->
end, ?MYHOSTS).
connect_nodes() ->
Nodes = ejabberd_config:get_local_option(
Nodes = ejabberd_config:get_option(
cluster_nodes,
fun(Ns) ->
true = lists:all(fun is_atom/1, Ns),
@ -212,9 +214,17 @@ delete_pid_file() ->
file:delete(PidFilename)
end.
set_loglevel_from_config() ->
Level = ejabberd_config:get_option(
loglevel,
fun(P) when P>=0, P=<5 -> P end,
4),
ejabberd_logger:set(Level).
start_apps() ->
ejabberd:start_app(sasl),
ejabberd:start_app(ssl),
ejabberd:start_app(p1_yaml),
ejabberd:start_app(p1_tls),
ejabberd:start_app(p1_xml),
ejabberd:start_app(p1_stringprep),

View File

@ -423,7 +423,7 @@ auth_modules() ->
%% Return the list of authenticated modules for a given host
auth_modules(Server) ->
LServer = jlib:nameprep(Server),
Methods = ejabberd_config:get_local_option(
Methods = ejabberd_config:get_option(
{auth_method, LServer},
fun(V) when is_list(V) ->
true = lists:all(fun is_atom/1, V),

View File

@ -104,7 +104,7 @@ is_login_anonymous_enabled(Host) ->
%% Return the anonymous protocol to use: sasl_anon|login_anon|both
%% defaults to login_anon
anonymous_protocol(Host) ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{anonymous_protocol, Host},
fun(sasl_anon) -> sasl_anon;
(login_anon) -> login_anon;
@ -115,7 +115,7 @@ anonymous_protocol(Host) ->
%% Return true if multiple connections have been allowed in the config file
%% defaults to false
allow_multiple_connections(Host) ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{allow_multiple_connections, Host},
fun(V) when is_boolean(V) -> V end,
false).

View File

@ -48,7 +48,7 @@
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
Cmd = ejabberd_config:get_local_option(
Cmd = ejabberd_config:get_option(
{extauth_program, Host},
fun(V) ->
binary_to_list(iolist_to_binary(V))
@ -171,7 +171,7 @@ remove_user(User, Server, Password) ->
%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
get_cache_option(Host) ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
{extauth_cache, Host},
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> false;

View File

@ -406,7 +406,7 @@ is_scrammed() ->
is_option_scram() ->
scram ==
ejabberd_config:get_local_option({auth_password_format, ?MYNAME},
ejabberd_config:get_option({auth_password_format, ?MYNAME},
fun(V) -> V end).
maybe_alert_password_scrammed_without_option() ->

View File

@ -369,8 +369,10 @@ parse_options(Host) ->
{iolist_to_binary(U),
iolist_to_binary(P)};
({U}) ->
{iolist_to_binary(U)};
(U) ->
{iolist_to_binary(U)}
end, Us)
end, lists:flatten(Us))
end, [{<<"uid">>, <<"%u">>}]),
UIDs = eldap_utils:uids_domain_subst(Host, UIDsTemp),
SubFilter = eldap_utils:generate_subfilter(UIDs),

View File

@ -107,13 +107,13 @@ store_type() -> external.
%% Internal functions
%%====================================================================
get_pam_service(Host) ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{pam_service, Host},
fun iolist_to_binary/1,
<<"ejabberd">>).
get_pam_userinfotype(Host) ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{pam_userinfotype, Host},
fun(username) -> username;
(jid) -> jid

View File

@ -47,7 +47,8 @@
del_aux_field/2,
get_subscription/2,
broadcast/4,
get_subscribed/1]).
get_subscribed/1,
transform_listen_option/2]).
%% gen_fsm callbacks
-export([init/1,
@ -233,11 +234,10 @@ init([{SockMod, Socket}, Opts]) ->
{value, {_, XS}} -> XS;
_ -> false
end,
Zlib = lists:member(zlib, Opts),
StartTLS = lists:member(starttls, Opts),
StartTLSRequired = lists:member(starttls_required,
Opts),
TLSEnabled = lists:member(tls, Opts),
Zlib = proplists:get_bool(zlib, Opts),
StartTLS = proplists:get_bool(starttls, Opts),
StartTLSRequired = proplists:get_bool(starttls_required, Opts),
TLSEnabled = proplists:get_bool(tls, Opts),
TLS = StartTLS orelse
StartTLSRequired orelse TLSEnabled,
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
@ -682,7 +682,7 @@ wait_for_feature_request({xmlstreamelement, El},
when TLS == true, TLSEnabled == false,
SockMod == gen_tcp ->
TLSOpts = case
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{domain_certfile, StateData#state.server},
fun iolist_to_binary/1)
of
@ -876,7 +876,7 @@ resource_conflict_action(U, S, R) ->
R)
of
true ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{resource_conflict, S},
fun(setresource) -> setresource;
(closeold) -> closeold;
@ -2279,7 +2279,7 @@ fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) -> [{max_queue, N}];
_ ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];
@ -2377,3 +2377,6 @@ pack_string(String, Pack) ->
{value, PackedString} -> {PackedString, Pack};
none -> {String, gb_trees:insert(String, String, Pack)}
end.
transform_listen_option(Opt, Opts) ->
[Opt|Opts].

View File

@ -34,7 +34,7 @@
%% Get first c2s configuration limitations to apply it to other c2s
%% connectors.
get_c2s_limits() ->
case ejabberd_config:get_local_option(listen, fun(V) -> V end) of
case ejabberd_config:get_option(listen, fun(V) -> V end) of
undefined -> [];
C2SFirstListen ->
case lists:keysearch(ejabberd_c2s, 2, C2SFirstListen) of

View File

@ -504,7 +504,7 @@ do_create_image(Key) ->
end.
get_prog_name() ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
captcha_cmd,
fun(FileName) ->
F = iolist_to_binary(FileName),
@ -521,7 +521,7 @@ get_prog_name() ->
end.
get_url(Str) ->
CaptchaHost = ejabberd_config:get_local_option(
CaptchaHost = ejabberd_config:get_option(
captcha_host,
fun iolist_to_binary/1,
<<"">>),
@ -549,7 +549,7 @@ get_transfer_protocol(PortString) ->
get_captcha_transfer_protocol(PortListeners).
get_port_listeners(PortNumber) ->
AllListeners = ejabberd_config:get_local_option(listen, fun(V) -> V end),
AllListeners = ejabberd_config:get_option(listen, fun(V) -> V end),
lists:filter(fun ({{Port, _Ip, _Netp}, _Module1,
_Opts1})
when Port == PortNumber ->
@ -579,7 +579,7 @@ get_captcha_transfer_protocol([_ | Listeners]) ->
is_limited(undefined) -> false;
is_limited(Limiter) ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
captcha_limit,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> false;

View File

@ -27,16 +27,16 @@
-module(ejabberd_config).
-author('alexey@process-one.net').
-export([start/0, load_file/1,
-export([start/0, load_file/1, read_file/1,
add_global_option/2, add_local_option/2,
get_global_option/2, get_local_option/2,
get_global_option/3, get_local_option/3,
get_option/2, get_option/3, add_option/2]).
-export([get_vh_by_auth_method/1]).
-export([is_file_readable/1]).
-export([get_version/0, get_myhosts/0, get_mylang/0]).
-export([prepare_opt_val/4]).
-export([convert_table_to_binary/5]).
get_option/2, get_option/3, add_option/2,
get_vh_by_auth_method/1, is_file_readable/1,
get_version/0, get_myhosts/0, get_mylang/0,
prepare_opt_val/4, convert_table_to_binary/5,
transform_options/1, collect_options/1,
convert_to_yaml/1, convert_to_yaml/2]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -53,21 +53,29 @@
start() ->
case catch mnesia:table_info(local_config, storage_type) of
disc_copies ->
mnesia:delete_table(local_config);
_ ->
ok
end,
mnesia:create_table(local_config,
[{disc_copies, [node()]},
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, local_config)}]),
mnesia:add_table_copy(local_config, node(), ram_copies),
Config = get_ejabberd_config_path(),
load_file(Config),
State = read_file(Config),
%% This start time is used by mod_last:
add_option(node_start, now()),
ok.
{MegaSecs, Secs, _} = now(),
UnixTime = MegaSecs*1000000 + Secs,
State1 = set_option({node_start, global}, UnixTime, State),
set_opts(State1).
%% @doc Get the filename of the ejabberd configuration file.
%% The filename can be specified with: erl -config "/path/to/ejabberd.cfg".
%% The filename can be specified with: erl -config "/path/to/ejabberd.yml".
%% It can also be specified with the environtment variable EJABBERD_CONFIG_PATH.
%% If not specified, the default value 'ejabberd.cfg' is assumed.
%% If not specified, the default value 'ejabberd.yml' is assumed.
%% @spec () -> string()
get_ejabberd_config_path() ->
case application:get_env(config) of
@ -81,16 +89,59 @@ get_ejabberd_config_path() ->
end
end.
%% @doc Load the ejabberd configuration file.
%% @doc Read the ejabberd configuration file.
%% It also includes additional configuration files and replaces macros.
%% This function will crash if finds some error in the configuration file.
%% @spec (File::string()) -> ok
load_file(File) ->
Terms = get_plain_terms_file(File),
%% @spec (File::string()) -> #state{}.
read_file(File) ->
read_file(File, [{replace_macros, true},
{include_files, true}]).
read_file(File, Opts) ->
Terms1 = get_plain_terms_file(File, Opts),
Terms_macros = case proplists:get_bool(replace_macros, Opts) of
true -> replace_macros(Terms1);
false -> Terms1
end,
Terms = transform_terms(Terms_macros),
State = lists:foldl(fun search_hosts/2, #state{}, Terms),
Terms_macros = replace_macros(Terms),
Res = lists:foldl(fun process_term/2, State, Terms_macros),
set_opts(Res).
{Head, Tail} = lists:partition(
fun({host_config, _}) -> false;
({append_host_config, _}) -> false;
(_) -> true
end, Terms),
State1 = lists:foldl(fun process_term/2, State, Head ++ Tail),
State1#state{opts = compact(State1#state.opts)}.
-spec load_file(string()) -> ok.
load_file(File) ->
State = read_file(File),
set_opts(State).
-spec convert_to_yaml(file:filename()) -> ok | {error, any()}.
convert_to_yaml(File) ->
convert_to_yaml(File, stdout).
-spec convert_to_yaml(file:filename(),
stdout | file:filename()) -> ok | {error, any()}.
convert_to_yaml(File, Output) ->
State = read_file(File, [{include_files, false}]),
Opts = [{K, V} || #local_config{key = K, value = V} <- State#state.opts],
{GOpts, HOpts} = split_by_hosts(Opts),
NewOpts = GOpts ++ lists:map(
fun({Host, Opts1}) ->
{host_config, [{Host, Opts1}]}
end, HOpts),
Data = p1_yaml:encode(lists:reverse(NewOpts)),
case Output of
stdout ->
io:format("~s~n", [Data]);
FileName ->
file:write_file(FileName, Data)
end.
%% @doc Read an ejabberd configuration file and return the terms.
%% Input is an absolute or relative path to an ejabberd config file.
@ -99,22 +150,47 @@ load_file(File) ->
%% and the terms in those files were included.
%% @spec(string()) -> [term()]
%% @spec(iolist()) -> [term()]
get_plain_terms_file(File) when is_binary(File) ->
get_plain_terms_file(binary_to_list(File));
get_plain_terms_file(File1) ->
get_plain_terms_file(File) ->
get_plain_terms_file(File, [{include_files, true}]).
get_plain_terms_file(File, Opts) when is_binary(File) ->
get_plain_terms_file(binary_to_list(File), Opts);
get_plain_terms_file(File1, Opts) ->
File = get_absolute_path(File1),
case file:consult(File) of
case consult(File) of
{ok, Terms} ->
BinTerms = strings_to_binary(Terms),
include_config_files(BinTerms);
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
ExitText = describe_config_problem(File, Reason, LineNumber),
?ERROR_MSG(ExitText, []),
exit_or_halt(ExitText);
case proplists:get_bool(include_files, Opts) of
true ->
include_config_files(BinTerms);
false ->
BinTerms
end;
{error, Reason} ->
ExitText = describe_config_problem(File, Reason),
?ERROR_MSG(ExitText, []),
exit_or_halt(ExitText)
?ERROR_MSG(Reason, []),
exit_or_halt(Reason)
end.
consult(File) ->
case filename:extension(File) of
".yml" ->
case p1_yaml:decode_from_file(File, [plain_as_atom]) of
{ok, []} ->
{ok, []};
{ok, [Document|_]} ->
{ok, Document};
{error, Err} ->
{error, p1_yaml:format_error(Err)}
end;
_ ->
case file:consult(File) of
{ok, Terms} ->
{ok, Terms};
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} ->
{error, describe_config_problem(File, Reason, LineNumber)};
{error, Reason} ->
{error, describe_config_problem(File, Reason)}
end
end.
%% @doc Convert configuration filename to absolute path.
@ -158,7 +234,7 @@ search_hosts(Term, State) ->
add_hosts_to_option(Hosts, State) ->
PrepHosts = normalize_hosts(Hosts),
add_option(hosts, PrepHosts, State#state{hosts = PrepHosts}).
set_option({hosts, global}, PrepHosts, State#state{hosts = PrepHosts}).
normalize_hosts(Hosts) ->
normalize_hosts(Hosts,[]).
@ -232,21 +308,37 @@ exit_or_halt(ExitText) ->
%% @doc Include additional configuration files in the list of terms.
%% @spec ([term()]) -> [term()]
include_config_files(Terms) ->
include_config_files(Terms, []).
{FileOpts, Terms1} =
lists:mapfoldl(
fun({include_config_file, _} = T, Ts) ->
{[transform_include_option(T)], Ts};
({include_config_file, _, _} = T, Ts) ->
{[transform_include_option(T)], Ts};
(T, Ts) ->
{[], [T|Ts]}
end, [], Terms),
Terms2 = lists:flatmap(
fun({File, Opts}) ->
include_config_file(File, Opts)
end, lists:flatten(FileOpts)),
Terms1 ++ Terms2.
include_config_files([], Res) ->
Res;
include_config_files([{include_config_file, Filename} | Terms], Res) ->
include_config_files([{include_config_file, Filename, []} | Terms], Res);
include_config_files([{include_config_file, Filename, Options} | Terms], Res) ->
transform_include_option({include_config_file, File}) when is_list(File) ->
case is_string(File) of
true -> {File, []};
false -> File
end;
transform_include_option({include_config_file, Filename}) ->
{Filename, []};
transform_include_option({include_config_file, Filename, Options}) ->
{Filename, Options}.
include_config_file(Filename, Options) ->
Included_terms = get_plain_terms_file(Filename),
Disallow = proplists:get_value(disallow, Options, []),
Included_terms2 = delete_disallowed(Disallow, Included_terms),
Allow_only = proplists:get_value(allow_only, Options, all),
Included_terms3 = keep_only_allowed(Allow_only, Included_terms2),
include_config_files(Terms, Res ++ Included_terms3);
include_config_files([Term | Terms], Res) ->
include_config_files(Terms, Res ++ [Term]).
keep_only_allowed(Allow_only, Included_terms2).
%% @doc Filter from the list of terms the disallowed.
%% Returns a sublist of Terms without the ones which first element is
@ -308,12 +400,19 @@ split_terms_macros(Terms) ->
fun(Term, {TOs, Ms}) ->
case Term of
{define_macro, Key, Value} ->
case is_atom(Key) and is_all_uppercase(Key) of
case is_correct_macro({Key, Value}) of
true ->
{TOs, Ms++[{Key, Value}]};
false ->
exit({macro_not_properly_defined, Term})
end;
{define_macro, KeyVals} ->
case lists:all(fun is_correct_macro/1, KeyVals) of
true ->
{TOs, Ms ++ KeyVals};
false ->
exit({macros_not_properly_defined, Term})
end;
Term ->
{TOs ++ [Term], Ms}
end
@ -321,6 +420,11 @@ split_terms_macros(Terms) ->
{[], []},
Terms).
is_correct_macro({Key, _Val}) ->
is_atom(Key) and is_all_uppercase(Key);
is_correct_macro(_) ->
false.
%% @doc Recursively replace in Terms macro usages with the defined value.
%% @spec (Terms, Macros) -> Terms
%% Terms = [term()]
@ -328,7 +432,9 @@ split_terms_macros(Terms) ->
replace([], _) ->
[];
replace([Term|Terms], Macros) ->
[replace_term(Term, Macros) | replace(Terms, Macros)].
[replace_term(Term, Macros) | replace(Terms, Macros)];
replace(Term, Macros) ->
replace_term(Term, Macros).
replace_term(Key, Macros) when is_atom(Key) ->
case is_all_uppercase(Key) of
@ -362,121 +468,65 @@ is_all_uppercase(Atom) ->
process_term(Term, State) ->
case Term of
override_global ->
State#state{override_global = true};
override_local ->
State#state{override_local = true};
override_acls ->
State#state{override_acls = true};
{host_config, Host, Terms} ->
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
State, Terms);
{listen, Listeners} ->
Listeners2 =
lists:map(
fun({PortIP, Module, Opts}) ->
{Port, IPT, _, _, Proto, OptsClean} =
ejabberd_listener:parse_listener_portip(PortIP, Opts),
{{Port, IPT, Proto}, Module, OptsClean}
end,
Listeners),
add_option(listen, Listeners2, State);
{s2s_certfile, CertFile} ->
CertFileS = binary_to_list(CertFile),
case ejabberd_config:is_file_readable(CertFileS) of
true -> add_option(s2s_certfile, CertFile, State);
false ->
ErrorText = "There is a problem in the configuration: "
"the specified file is not readable: ",
throw({error, ErrorText ++ CertFileS})
end;
{domain_certfile, Domain, CertFile} ->
CertFileS = binary_to_list(CertFile),
case ejabberd_config:is_file_readable(CertFileS) of
true -> add_option({domain_certfile, Domain}, CertFile, State);
false ->
ErrorText = "There is a problem in the configuration: "
"the specified file is not readable: ",
throw({error, ErrorText ++ CertFileS})
end;
{loglevel, Loglevel} ->
ejabberd_logger:set(Loglevel),
State;
{host_config, HostTerms} ->
lists:foldl(
fun({Host, Terms}, AccState) ->
lists:foldl(fun(T, S) ->
process_host_term(T, Host, S, set)
end, AccState, Terms)
end, State, HostTerms);
{append_host_config, HostTerms} ->
lists:foldl(
fun({Host, Terms}, AccState) ->
lists:foldl(fun(T, S) ->
process_host_term(T, Host, S, append)
end, AccState, Terms)
end, State, HostTerms);
_ ->
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end,
State, [global|State#state.hosts])
process_host_term(Term, global, State, set)
end.
process_host_term(Term, Host, State) ->
process_host_term(Term, Host, State, Action) ->
case Term of
{acl, ACLName, ACLData} ->
State#state{opts =
[acl:to_record(Host, ACLName, ACLData) | State#state.opts]};
{access, RuleName, Rules} ->
add_option({access, RuleName, Host}, Rules, State);
{shaper, Name, Data} ->
add_option({shaper, Name, Host}, Data, State);
{modules, Modules} ->
add_option({modules, Host}, replace_modules(Modules), State);
{modules, Modules} when Action == set ->
set_option({modules, Host}, replace_modules(Modules), State);
{modules, Modules} when Action == append ->
append_option({modules, Host}, replace_modules(Modules), State);
{host, _} ->
State;
{hosts, _} ->
State;
{Opt, Val} ->
add_option({Opt, Host}, Val, State)
{Opt, Val} when Action == set ->
set_option({Opt, Host}, Val, State);
{Opt, Val} when Action == append ->
append_option({Opt, Host}, Val, State);
Opt ->
?WARNING_MSG("Ignore invalid (outdated?) option ~p", [Opt]),
State
end.
add_option(Opt, Val, State) when is_atom(Opt) ->
add_option({Opt, global}, Val, State);
add_option(Opt, Val, State) ->
case Opt of
{{add, OptName}, Host} ->
State#state{opts = compact({OptName, Host}, Val,
State#state.opts, [])};
_ ->
State#state{opts = [#local_config{key = Opt, value = Val} |
State#state.opts]}
end.
compact({OptName, Host} = Opt, Val, [], Os) ->
?WARNING_MSG("The option '~p' is defined for the host ~p using host_config "
"before the global '~p' option. This host_config option may get overwritten.", [OptName, Host, OptName]),
[#local_config{key = Opt, value = Val}] ++ Os;
%% Traverse the list of the options already parsed
compact(Opt, Val, [O | Os1], Os2) ->
case catch O#local_config.key of
%% If the key of a local_config matches the Opt that wants to be added
Opt ->
%% Then prepend the new value to the list of old values
Os2 ++ [#local_config{key = Opt,
value = Val++O#local_config.value}
] ++ Os1;
_ ->
compact(Opt, Val, Os1, Os2++[O])
end.
set_option(Opt, Val, State) ->
State#state{opts = [#local_config{key = Opt, value = Val} |
State#state.opts]}.
append_option({Opt, Host}, Val, State) ->
GlobalVals = lists:flatmap(
fun(#local_config{key = {O, global}, value = V})
when O == Opt ->
if is_list(V) -> V;
true -> [V]
end;
(_) ->
[]
end, State#state.opts),
NewVal = if is_list(Val) -> Val ++ GlobalVals;
true -> [Val|GlobalVals]
end,
set_option({Opt, Host}, NewVal, State).
set_opts(State) ->
Opts = lists:reverse(State#state.opts),
Opts = State#state.opts,
F = fun() ->
if
State#state.override_local ->
Ksl = mnesia:all_keys(local_config),
lists:foreach(fun(K) ->
mnesia:delete({local_config, K})
end, Ksl);
true ->
ok
end,
if
State#state.override_acls ->
Ksa = mnesia:all_keys(acl),
lists:foreach(fun(K) ->
mnesia:delete({acl, K})
end, Ksa);
true ->
ok
end,
lists:foreach(fun(R) ->
mnesia:write(R)
end, Opts)
@ -565,11 +615,22 @@ get_option(Opt, F) ->
get_option(Opt, F, Default) when is_atom(Opt) ->
get_option({Opt, global}, F, Default);
get_option(Opt, F, Default) ->
case Opt of
{O, global} when is_atom(O) -> ok;
{O, H} when is_atom(O), is_binary(H) -> ok;
_ -> ?WARNING_MSG("Option ~p has invalid (outdated?) format. "
"This is likely a bug", [Opt])
end,
case ets:lookup(local_config, Opt) of
[#local_config{value = Val}] ->
prepare_opt_val(Opt, Val, F, Default);
_ ->
Default
_ ->
case Opt of
{Key, Host} when Host /= global ->
get_option({Key, global}, F, Default);
_ ->
Default
end
end.
-spec get_vh_by_auth_method(atom()) -> [binary()].
@ -632,14 +693,14 @@ replace_modules(Modules) ->
emit_deprecation_warning(Module, NewModule, DBType),
NewOpts = [{db_type, DBType} |
lists:keydelete(db_type, 1, Opts)],
{NewModule, NewOpts};
{NewModule, transform_module_options(Module, NewOpts)};
NewModule ->
if Module /= NewModule ->
emit_deprecation_warning(Module, NewModule);
true ->
ok
end,
{NewModule, Opts}
{NewModule, transform_module_options(Module, Opts)}
end
end, Modules).
@ -695,6 +756,142 @@ format_term(S) when is_list(S), S /= [] ->
format_term(T) ->
io_lib:format("~p", [binary_to_strings(T)]).
transform_terms(Terms) ->
%% We could check all ejabberd beams, but this
%% slows down start-up procedure :(
Mods = [mod_register,
mod_last,
ejabberd_s2s,
ejabberd_listener,
ejabberd_odbc_sup,
shaper,
ejabberd_s2s_out,
acl,
ejabberd_config],
collect_options(transform_terms(Mods, Terms)).
transform_terms([Mod|Mods], Terms) ->
case catch Mod:transform_options(Terms) of
{'EXIT', _} = Err ->
?ERROR_MSG("Failed to transform terms by ~p: ~p", [Mod, Err]),
transform_terms(Mods, Terms);
NewTerms ->
transform_terms(Mods, NewTerms)
end;
transform_terms([], NewTerms) ->
NewTerms.
transform_module_options(Module, Opts) ->
Opts1 = gen_iq_handler:transform_module_options(Opts),
try
Module:transform_module_options(Opts1)
catch error:undef ->
Opts1
end.
compact(Cfg) ->
Opts = [{K, V} || #local_config{key = K, value = V} <- Cfg],
{GOpts, HOpts} = split_by_hosts(Opts),
[#local_config{key = {O, global}, value = V} || {O, V} <- GOpts] ++
lists:flatmap(
fun({Host, OptVal}) ->
case lists:member(OptVal, GOpts) of
true ->
[];
false ->
[#local_config{key = {Opt, Host}, value = Val}
|| {Opt, Val} <- OptVal]
end
end, lists:flatten(HOpts)).
split_by_hosts(Opts) ->
Opts1 = orddict:to_list(
lists:foldl(
fun({{Opt, Host}, Val}, D) ->
orddict:append(Host, {Opt, Val}, D)
end, orddict:new(), Opts)),
case lists:keytake(global, 1, Opts1) of
{value, {global, GlobalOpts}, HostOpts} ->
{GlobalOpts, HostOpts};
_ ->
{[], Opts1}
end.
collect_options(Opts) ->
{D, InvalidOpts} =
lists:foldl(
fun({K, V}, {D, Os}) when is_list(V) ->
{orddict:append_list(K, V, D), Os};
({K, V}, {D, Os}) ->
{orddict:store(K, V, D), Os};
(Opt, {D, Os}) ->
{D, [Opt|Os]}
end, {orddict:new(), []}, Opts),
InvalidOpts ++ orddict:to_list(D).
transform_options(Opts) ->
Opts1 = lists:foldl(fun transform_options/2, [], Opts),
{HOpts, Opts2} = lists:mapfoldl(
fun({host_config, O}, Os) ->
{[O], Os};
(O, Os) ->
{[], [O|Os]}
end, [], Opts1),
{AHOpts, Opts3} = lists:mapfoldl(
fun({append_host_config, O}, Os) ->
{[O], Os};
(O, Os) ->
{[], [O|Os]}
end, [], Opts2),
HOpts1 = case collect_options(lists:flatten(HOpts)) of
[] ->
[];
HOs ->
[{host_config,
[{H, transform_terms(O)} || {H, O} <- HOs]}]
end,
AHOpts1 = case collect_options(lists:flatten(AHOpts)) of
[] ->
[];
AHOs ->
[{append_host_config,
[{H, transform_terms(O)} || {H, O} <- AHOs]}]
end,
HOpts1 ++ AHOpts1 ++ Opts3.
transform_options({domain_certfile, Domain, CertFile}, Opts) ->
?WARNING_MSG("Option 'domain_certfile' now should be defined "
"per virtual host or globally. The old format is "
"still supported but it is better to fix your config", []),
[{host_config, [{Domain, [{domain_certfile, CertFile}]}]}|Opts];
transform_options(Opt, Opts) when Opt == override_global;
Opt == override_local;
Opt == override_acls ->
?WARNING_MSG("Ignoring '~s' option which has no effect anymore", [Opt]),
Opts;
transform_options({host_config, Host, HOpts}, Opts) ->
{AddOpts, HOpts1} =
lists:mapfoldl(
fun({{add, Opt}, Val}, Os) ->
?WARNING_MSG("Option 'add' is deprecated. "
"The option is still supported "
"but it is better to fix your config: "
"use 'append_host_config' instead.", []),
{[{Opt, Val}], Os};
(O, Os) ->
{[], [O|Os]}
end, [], HOpts),
[{append_host_config, [{Host, lists:flatten(AddOpts)}]},
{host_config, [{Host, HOpts1}]}|Opts];
transform_options({define_macro, Macro, Val}, Opts) ->
[{define_macro, [{Macro, Val}]}|Opts];
transform_options({include_config_file, _} = Opt, Opts) ->
[{include_config_file, [transform_include_option(Opt)]} | Opts];
transform_options({include_config_file, _, _} = Opt, Opts) ->
[{include_config_file, [transform_include_option(Opt)]} | Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].
-spec convert_table_to_binary(atom(), [atom()], atom(),
fun(), fun()) -> ok.

View File

@ -237,7 +237,7 @@ process2(Args, Auth, AccessCommands) ->
end.
get_accesscommands() ->
ejabberd_config:get_local_option(ejabberdctl_access_commands,
ejabberd_config:get_option(ejabberdctl_access_commands,
fun(V) when is_list(V) -> V end, []).
%%-----------------------------

View File

@ -280,7 +280,7 @@ code_change(_OldVsn, State, _Extra) -> {ok, State}.
%%% Internal functions
%%--------------------------------------------------------------------
check_starttls(SockMod, Socket, Receiver, Opts) ->
TLSEnabled = lists:member(tls, Opts),
TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts = lists:filter(fun({certfile, _}) -> true;
(_) -> false
end, Opts),
@ -292,4 +292,3 @@ check_starttls(SockMod, Socket, Receiver, Opts) ->
true ->
{SockMod, Socket}
end.

View File

@ -30,7 +30,8 @@
%% 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, url_encode/1,
transform_listen_option/2]).
%% Callbacks
-export([init/2]).
@ -91,7 +92,7 @@ start_link(SockData, Opts) ->
[SockData, Opts])}.
init({SockMod, Socket}, Opts) ->
TLSEnabled = lists:member(tls, Opts),
TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
(_) -> false
end,
@ -133,12 +134,13 @@ init({SockMod, Socket}, Opts) ->
true -> [{[<<"http-poll">>], ejabberd_http_poll}];
false -> []
end,
DefinedHandlers = case lists:keysearch(request_handlers,
1, Opts)
of
{value, {request_handlers, H}} -> H;
false -> []
end,
DefinedHandlers = gen_mod:get_opt(
request_handlers, Opts,
fun(Hs) ->
[{str:tokens(
iolist_to_binary(Path), <<"/">>),
Mod} || {Path, Mod} <- Hs]
end, []),
RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
Admin ++ Bind ++ Poll,
?DEBUG("S: ~p~n", [RequestHandlers]),
@ -484,7 +486,7 @@ analyze_ip_xff(IP, [], _Host) -> IP;
analyze_ip_xff({IPLast, Port}, XFF, Host) ->
[ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++
[jlib:ip_to_list(IPLast)],
TrustedProxies = ejabberd_config:get_local_option(
TrustedProxies = ejabberd_config:get_option(
{trusted_proxies, Host},
fun(TPs) ->
[iolist_to_binary(TP) || TP <- TPs]
@ -834,3 +836,25 @@ normalize_path([_Parent, <<"..">>|Path], Norm) ->
normalize_path(Path, Norm);
normalize_path([Part | Path], Norm) ->
normalize_path(Path, [Part|Norm]).
transform_listen_option(captcha, Opts) ->
[{captcha, true}|Opts];
transform_listen_option(register, Opts) ->
[{register, true}|Opts];
transform_listen_option(web_admin, Opts) ->
[{web_admin, true}|Opts];
transform_listen_option(http_bind, Opts) ->
[{http_bind, true}|Opts];
transform_listen_option(http_poll, Opts) ->
[{http_poll, true}|Opts];
transform_listen_option({request_handlers, Hs}, Opts) ->
Hs1 = lists:map(
fun({PList, Mod}) when is_list(PList) ->
Path = iolist_to_binary([[$/, P] || P <- PList]),
{Path, Mod};
(Opt) ->
Opt
end, Hs),
[{request_handlers, Hs1} | Opts];
transform_listen_option(Opt, Opts) ->
[Opt|Opts].

View File

@ -205,7 +205,7 @@ get_human_html_xmlel() ->
init([ID, Key, IP]) ->
?INFO_MSG("started: ~p", [{ID, Key, IP}]),
Opts = ejabberd_c2s_config:get_c2s_limits(),
HTTPPollTimeout = ejabberd_config:get_local_option(
HTTPPollTimeout = ejabberd_config:get_option(
{http_poll_timeout, ?MYNAME},
fun(I) when is_integer(I), I>0 -> I end,
?HTTP_POLL_TIMEOUT) * 1000,

View File

@ -36,7 +36,8 @@
parse_listener_portip/2,
add_listener/3,
delete_listener/2,
validate_cfg/1
transform_options/1,
validate_cfg/1
]).
-include("ejabberd.hrl").
@ -55,7 +56,7 @@ init(_) ->
{ok, {{one_for_one, 10, 1}, []}}.
bind_tcp_ports() ->
case ejabberd_config:get_local_option(listen, fun validate_cfg/1) of
case ejabberd_config:get_option(listen, fun validate_cfg/1) of
undefined ->
ignore;
Ls ->
@ -88,7 +89,7 @@ bind_tcp_port(PortIP, Module, RawOpts) ->
end.
start_listeners() ->
case ejabberd_config:get_local_option(listen, fun validate_cfg/1) of
case ejabberd_config:get_option(listen, fun validate_cfg/1) of
undefined ->
ignore;
Ls ->
@ -267,7 +268,7 @@ strip_ip_option(Opts) ->
Opts),
case IPL of
%% Only the first ip option is considered
[{ip, T1} | _] when is_tuple(T1) ->
[{ip, T1} | _] ->
{T1, OptsNoIP};
[] ->
{no_ip_option, OptsNoIP}
@ -364,7 +365,7 @@ start_listener_sup(Port, Module, Opts) ->
supervisor:start_child(ejabberd_listeners, ChildSpec).
stop_listeners() ->
Ports = ejabberd_config:get_local_option(listen, fun validate_cfg/1),
Ports = ejabberd_config:get_option(listen, fun validate_cfg/1),
lists:foreach(
fun({PortIpNetp, Module, _Opts}) ->
delete_listener(PortIpNetp, Module)
@ -397,7 +398,7 @@ add_listener(PortIP, Module, Opts) ->
PortIP1 = {Port, IPT, Proto},
case start_listener(PortIP1, Module, Opts) of
{ok, _Pid} ->
Ports = case ejabberd_config:get_local_option(
Ports = case ejabberd_config:get_option(
listen, fun validate_cfg/1) of
undefined ->
[];
@ -406,7 +407,8 @@ add_listener(PortIP, Module, Opts) ->
end,
Ports1 = lists:keydelete(PortIP1, 1, Ports),
Ports2 = [{PortIP1, Module, Opts} | Ports1],
ejabberd_config:add_local_option(listen, Ports2),
Ports3 = lists:map(fun transform_option/1, Ports2),
ejabberd_config:add_option(listen, Ports3),
ok;
{error, {already_started, _Pid}} ->
{error, {already_started, PortIP}};
@ -428,7 +430,7 @@ delete_listener(PortIP, Module) ->
delete_listener(PortIP, Module, Opts) ->
{Port, IPT, _, _, Proto, _} = parse_listener_portip(PortIP, Opts),
PortIP1 = {Port, IPT, Proto},
Ports = case ejabberd_config:get_local_option(
Ports = case ejabberd_config:get_option(
listen, fun validate_cfg/1) of
undefined ->
[];
@ -436,7 +438,8 @@ delete_listener(PortIP, Module, Opts) ->
Ls
end,
Ports1 = lists:keydelete(PortIP1, 1, Ports),
ejabberd_config:add_local_option(listen, Ports1),
Ports2 = lists:map(fun transform_option/1, Ports1),
ejabberd_config:add_option(listen, Ports2),
stop_listener(PortIP1, Module).
@ -541,6 +544,55 @@ format_error(Reason) ->
-define(IS_PORT(P), (is_integer(P) and (P > 0) and (P =< 65535))).
-define(IS_TRANSPORT(T), ((T == tcp) or (T == udp))).
transform_option({{Port, IP, Transport}, Mod, Opts}) ->
IPStr = if is_tuple(IP) ->
list_to_binary(inet_parse:ntoa(IP));
true ->
IP
end,
Opts1 = lists:map(
fun({ip, IPT}) when is_tuple(IPT) ->
{ip, list_to_binary(inet_parse:ntoa(IP))};
(tls) -> {tls, true};
(ssl) -> {tls, true};
(zlib) -> {zlib, true};
(starttls) -> {starttls, true};
(starttls_required) -> {starttls_required, true};
(Opt) -> Opt
end, Opts),
Opts2 = lists:foldl(
fun(Opt, Acc) ->
try
Mod:transform_listen_option(Opt, Acc)
catch error:undef ->
Acc
end
end, [], Opts1),
TransportOpt = if Transport == tcp -> [];
true -> [{transport, Transport}]
end,
IPOpt = if IPStr == <<"0.0.0.0">> -> [];
true -> [{ip, IPStr}]
end,
IPOpt ++ TransportOpt ++ [{port, Port}, {module, Mod} | Opts2];
transform_option({{Port, Transport}, Mod, Opts})
when ?IS_TRANSPORT(Transport) ->
transform_option({{Port, {0,0,0,0}, Transport}, Mod, Opts});
transform_option({{Port, IP}, Mod, Opts}) ->
transform_option({{Port, IP, tcp}, Mod, Opts});
transform_option({Port, Mod, Opts}) ->
transform_option({{Port, {0,0,0,0}, tcp}, Mod, Opts});
transform_option(Opt) ->
Opt.
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({listen, LOpts}, Opts) ->
[{listen, lists:map(fun transform_option/1, LOpts)} | Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].
-type transport() :: udp | tcp.
-type port_ip_transport() :: inet:port_number() |
{inet:port_number(), transport()} |
@ -551,18 +603,21 @@ format_error(Reason) ->
validate_cfg(L) ->
lists:map(
fun({PortIPTransport, Mod1, Opts}) when is_atom(Mod1), is_list(Opts) ->
Mod = prepare_mod(Mod1),
case PortIPTransport of
Port when ?IS_PORT(Port) ->
{Port, Mod, Opts};
{Port, Trans} when ?IS_PORT(Port) and ?IS_TRANSPORT(Trans) ->
{{Port, Trans}, Mod, Opts};
{Port, IP} when ?IS_PORT(Port) ->
{{Port, prepare_ip(IP)}, Mod, Opts};
{Port, IP, Trans} when ?IS_PORT(Port) and ?IS_TRANSPORT(Trans) ->
{{Port, prepare_ip(IP), Trans}, Mod, Opts}
end
fun(LOpts) ->
lists:foldl(
fun({port, Port}, {{_, IP, T}, Mod, Opts}) ->
true = ?IS_PORT(Port),
{{Port, IP, T}, Mod, Opts};
({ip, IP}, {{Port, _, T}, Mod, Opts}) ->
{{Port, prepare_ip(IP), T}, Mod, Opts};
({transport, T}, {{Port, IP, _}, Mod, Opts}) ->
true = ?IS_TRANSPORT(T),
{{Port, IP, T}, Mod, Opts};
({module, Mod}, {Port, _, Opts}) ->
{Port, prepare_mod(Mod), Opts};
(Opt, {Port, Mod, Opts}) ->
{Port, Mod, [Opt|Opts]}
end, {{5222, {0,0,0,0}, tcp}, ejabberd_c2s, []}, LOpts)
end, L).
prepare_ip({A, B, C, D} = IP)
@ -583,5 +638,5 @@ prepare_mod(ejabberd_stun) ->
prepare_mod(stun) ->
ejabberd:start_app(p1_stun),
stun;
prepare_mod(Mod) ->
prepare_mod(Mod) when is_atom(Mod) ->
Mod.

View File

@ -84,7 +84,12 @@ get_closest_node(Name) ->
%%--------------------------------------------------------------------
init([]) ->
{FE, BE} =
case ejabberd_config:get_local_option(node_type, fun(N) -> N end) of
case ejabberd_config:get_option(
node_type,
fun(frontend) -> frontend;
(backend) -> backend;
(generic) -> generic
end, generic) of
frontend ->
{true, false};
backend ->

View File

@ -71,12 +71,12 @@
-define(TOP_LEVEL_TXN, 0).
-define(MAX_TRANSACTION_RESTARTS, 10).
-define(PGSQL_PORT, 5432).
-define(MYSQL_PORT, 3306).
-define(MAX_TRANSACTION_RESTARTS, 10).
-define(TRANSACTION_TIMEOUT, 60000).
-define(KEEPALIVE_TIMEOUT, 60000).
@ -201,8 +201,8 @@ decode_term(Bin) ->
%%% Callback functions from gen_fsm
%%%----------------------------------------------------------------------
init([Host, StartInterval]) ->
case ejabberd_config:get_local_option(
{odbc_keepalive_interval, Host},
case ejabberd_config:get_option(
{keepalive_interval, Host},
fun(I) when is_integer(I), I>0 -> I end) of
undefined ->
ok;
@ -573,39 +573,39 @@ log(Level, Format, Args) ->
end.
db_opts(Host) ->
case ejabberd_config:get_local_option(
{odbc_server, Host},
fun({Type, Server, DB, User, Pass}) ->
{Type,
iolist_to_binary(Server),
case Type of
mysql -> ?MYSQL_PORT;
pgsql -> ?PGSQL_PORT
end,
iolist_to_binary(DB),
iolist_to_binary(User),
iolist_to_binary(Pass)};
({Type, Server, Port, DB, User, Pass})
when ((Type == mysql) or (Type == pgsql))
and (is_integer(Port) and ((Port > 0)
and (Port < 65536))) ->
{Type,
iolist_to_binary(Server),
Port,
iolist_to_binary(DB),
iolist_to_binary(User),
iolist_to_binary(Pass)};
(S) ->
iolist_to_binary(S)
end, <<"localhost">>) of
{Type, Server, Port, DB, User, Pass} ->
[Type, Server, Port, DB, User, Pass];
SQLServer ->
[odbc, SQLServer]
Type = ejabberd_config:get_option({odbc_type, Host},
fun(mysql) -> mysql;
(pgsql) -> pgsql;
(odbc) -> odbc
end, odbc),
Server = ejabberd_config:get_option({odbc_server, Host},
fun iolist_to_binary/1,
<<"localhost">>),
case Type of
odbc ->
[odbc, Server];
_ ->
Port = ejabberd_config:get_option(
{port, Host},
fun(P) when is_integer(P), P > 0, P < 65536 -> P end,
case Type of
mysql -> ?MYSQL_PORT;
pgsql -> ?PGSQL_PORT
end),
DB = ejabberd_config:get_option({odbc_database, Host},
fun iolist_to_binary/1,
<<"ejabberd">>),
User = ejabberd_config:get_option({odbc_username, Host},
fun iolist_to_binary/1,
<<"ejabberd">>),
Pass = ejabberd_config:get_option({odbc_password, Host},
fun iolist_to_binary/1,
<<"">>),
[Type, Server, Port, DB, User, Pass]
end.
max_fsm_queue() ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
max_fsm_queue,
fun(N) when is_integer(N), N > 0 -> N end).

View File

@ -30,11 +30,15 @@
%% API
-export([start_link/1, init/1, add_pid/2, remove_pid/2,
get_pids/1, get_random_pid/1]).
get_pids/1, get_random_pid/1, transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-define(PGSQL_PORT, 5432).
-define(MYSQL_PORT, 3306).
-define(DEFAULT_POOL_SIZE, 10).
-define(DEFAULT_ODBC_START_INTERVAL, 30).
@ -56,11 +60,11 @@ start_link(Host) ->
?MODULE, [Host]).
init([Host]) ->
PoolSize = ejabberd_config:get_local_option(
PoolSize = ejabberd_config:get_option(
{odbc_pool_size, Host},
fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_POOL_SIZE),
StartInterval = ejabberd_config:get_local_option(
StartInterval = ejabberd_config:get_option(
{odbc_start_interval, Host},
fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_ODBC_START_INTERVAL),
@ -93,3 +97,20 @@ remove_pid(Host, Pid) ->
mnesia:delete_object(#sql_pool{host = Host, pid = Pid})
end,
mnesia:ets(F).
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({odbc_server, {Type, Server, Port, DB, User, Pass}}, Opts) ->
[{odbc_type, Type},
{odbc_server, Server},
{odbc_port, Port},
{odbc_database, DB},
{odbc_username, User},
{odbc_password, Pass}|Opts];
transform_options({odbc_server, {mysql, Server, DB, User, Pass}}, Opts) ->
transform_options({odbc_server, {mysql, Server, ?MYSQL_PORT, DB, User, Pass}}, Opts);
transform_options({odbc_server, {pgsql, Server, DB, User, Pass}}, Opts) ->
transform_options({odbc_server, {pgsql, Server, ?PGSQL_PORT, DB, User, Pass}}, Opts);
transform_options(Opt, Opts) ->
[Opt|Opts].

View File

@ -69,18 +69,16 @@ start_odbc(Host, App) ->
start_odbc(Host, App)
end.
%% Returns {true, App} if we have configured odbc_server for the given host
%% Returns {true, App} if we have configured odbc for the given host
needs_odbc(Host) ->
LHost = jlib:nameprep(Host),
case ejabberd_config:get_local_option(
{odbc_server, LHost}, fun(Res) -> Res end) of
{mysql, _, _, _, _} -> {true, p1_mysql};
{pgsql, _, _, _, _} -> {true, p1_pgsql};
{mysql, _, _, _, _, _} -> {true, p1_mysql};
{pgsql, _, _, _, _, _} -> {true, p1_pgsql};
S ->
case catch iolist_to_binary(S) of
{'EXIT', _} -> false;
_ -> true
end
case ejabberd_config:get_option({odbc_type, LHost},
fun(mysql) -> mysql;
(pgsql) -> pgsql;
(odbc) -> odbc
end, undefined) of
mysql -> {true, p1_mysql};
pgsql -> {true, p1_pgsql};
odbc -> {true, odbc};
undefined -> false
end.

View File

@ -387,14 +387,10 @@ do_route(OrigFrom, OrigTo, OrigPacket) ->
end.
get_component_number(LDomain) ->
case
ejabberd_config:get_local_option({domain_balancing_component_number,
LDomain}, fun(D) -> D end)
of
N when is_integer(N), N > 1 -> N;
_ -> undefined
end.
ejabberd_config:get_option(
{domain_balancing_component_number, LDomain},
fun(N) when is_integer(N), N > 1 -> N end,
undefined).
update_tables() ->
case catch mnesia:table_info(route, attributes) of

View File

@ -45,7 +45,7 @@
handle_info/2, terminate/2, code_change/3]).
%% ejabberd API
-export([get_info_s2s_connections/1]).
-export([get_info_s2s_connections/1, transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -461,12 +461,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber,
%% --------------------------------------------------------------------
is_service(From, To) ->
LFromDomain = From#jid.lserver,
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
{route_subdomains, LFromDomain},
fun(s2s) -> s2s end) of
fun(s2s) -> s2s; (local) -> local end, local) of
s2s -> % bypass RFC 3920 10.3
false;
undefined ->
local ->
Hosts = (?MYHOSTS),
P = fun (ParentDomain) ->
lists:member(ParentDomain, Hosts)
@ -548,34 +548,50 @@ allow_host2(MyServer, S2SHost) ->
end.
allow_host1(MyHost, S2SHost) ->
case ejabberd_config:get_local_option(
{{s2s_host, S2SHost}, MyHost},
fun(deny) -> deny; (allow) -> allow end)
of
deny -> false;
allow -> true;
undefined ->
case ejabberd_config:get_local_option(
{s2s_default_policy, MyHost},
fun(deny) -> deny; (allow) -> allow end)
of
deny -> false;
_ ->
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
allow, [MyHost, S2SHost])
of
deny -> false;
allow -> true;
_ -> true
end
end
Rule = ejabberd_config:get_option(
s2s_access,
fun(A) when is_atom(A) -> A end,
all),
JID = jlib:make_jid(<<"">>, S2SHost, <<"">>),
case acl:match_rule(MyHost, Rule, JID) of
deny -> false;
allow ->
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
allow, [MyHost, S2SHost]) of
deny -> false;
allow -> true;
_ -> true
end
end.
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({{s2s_host, Host}, Action}, Opts) ->
?WARNING_MSG("Option 's2s_host' is deprecated. "
"The option is still supported but it is better to "
"fix your config: use access rules instead.", []),
ACLName = jlib:binary_to_atom(
iolist_to_binary(["s2s_access_", Host])),
[{acl, ACLName, {server, Host}},
{access, s2s, [{Action, ACLName}]},
{s2s_access, s2s} |
Opts];
transform_options({s2s_default_policy, Action}, Opts) ->
?WARNING_MSG("Option 's2s_default_policy' is deprecated. "
"The option is still supported but it is better to "
"fix your config: "
"use 's2s_access' with an access rule.", []),
[{access, s2s, [{Action, all}]},
{s2s_access, s2s} |
Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].
%% Get information about S2S connections of the specified type.
%% @spec (Type) -> [Info]
%% where Type = in | out
%% Info = [{InfoName::atom(), InfoValue::any()}]
get_info_s2s_connections(Type) ->
ChildType = case Type of
in -> ejabberd_s2s_in_sup;

View File

@ -149,7 +149,7 @@ init([{SockMod, Socket}, Opts]) ->
_ -> none
end,
{StartTLS, TLSRequired, TLSCertverify} =
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
s2s_use_starttls,
fun(false) -> false;
(true) -> true;
@ -171,7 +171,7 @@ init([{SockMod, Socket}, Opts]) ->
required_trusted ->
{true, true, true}
end,
TLSOpts1 = case ejabberd_config:get_local_option(
TLSOpts1 = case ejabberd_config:get_option(
s2s_certfile,
fun iolist_to_binary/1) of
undefined -> [];
@ -324,7 +324,7 @@ wait_for_feature_request({xmlstreamelement, El},
?DEBUG("starttls", []),
Socket = StateData#state.socket,
TLSOpts1 = case
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{domain_certfile, StateData#state.server},
fun iolist_to_binary/1) of
undefined -> StateData#state.tls_options;
@ -332,7 +332,7 @@ wait_for_feature_request({xmlstreamelement, El},
[{certfile, CertFile} | lists:keydelete(certfile, 1,
StateData#state.tls_options)]
end,
TLSOpts = case ejabberd_config:get_local_option(
TLSOpts = case ejabberd_config:get_option(
{s2s_tls_compression, StateData#state.server},
fun(true) -> true;
(false) -> false
@ -843,7 +843,7 @@ fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) -> [{max_queue, N}];
_ ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];

View File

@ -35,7 +35,8 @@
start_link/3,
start_connection/1,
terminate_if_waiting_delay/2,
stop_connection/1]).
stop_connection/1,
transform_options/1]).
%% p1_fsm callbacks (same as gen_fsm)
-export([init/1,
@ -161,7 +162,7 @@ init([From, Server, Type]) ->
process_flag(trap_exit, true),
?DEBUG("started: ~p", [{From, Server, Type}]),
{TLS, TLSRequired} = case
ejabberd_config:get_local_option(
ejabberd_config:get_option(
s2s_use_starttls,
fun(true) -> true;
(false) -> false;
@ -184,13 +185,13 @@ init([From, Server, Type]) ->
end,
UseV10 = TLS,
TLSOpts1 = case
ejabberd_config:get_local_option(
ejabberd_config:get_option(
s2s_certfile, fun iolist_to_binary/1)
of
undefined -> [connect];
CertFile -> [{certfile, CertFile}, connect]
end,
TLSOpts = case ejabberd_config:get_local_option(
TLSOpts = case ejabberd_config:get_option(
{s2s_tls_compression, From},
fun(true) -> true;
(false) -> false
@ -702,7 +703,7 @@ wait_for_starttls_proceed({xmlstreamelement, El},
[{StateData#state.myname, StateData#state.server}]),
Socket = StateData#state.socket,
TLSOpts = case
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{domain_certfile, StateData#state.myname},
fun iolist_to_binary/1)
of
@ -1142,16 +1143,15 @@ get_addr_port(Server) ->
end.
srv_lookup(Server) ->
Options = case
ejabberd_config:get_local_option(
s2s_dns_options, fun(L) when is_list(L) -> L end)
of
undefined -> [];
L -> L
end,
TimeoutMs = timer:seconds(proplists:get_value(timeout,
Options, 10)),
Retries = proplists:get_value(retries, Options, 2),
TimeoutMs = timer:seconds(
ejabberd_config:get_option(
s2s_dns_timeout,
fun(I) when is_integer(I), I>=0 -> I end,
10)),
Retries = ejabberd_config:get_option(
s2s_dns_retries,
fun(I) when is_integer(I), I>=0 -> I end,
2),
srv_lookup(binary_to_list(Server), TimeoutMs, Retries).
%% XXX - this behaviour is suboptimal in the case that the domain
@ -1211,15 +1211,15 @@ get_addrs(Host, Family) ->
end.
outgoing_s2s_port() ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
outgoing_s2s_port,
fun(I) when is_integer(I), I > 0, I =< 65536 -> I end,
5269).
outgoing_s2s_families() ->
ejabberd_config:get_local_option(
outgoing_s2s_options,
fun({Families, _}) ->
ejabberd_config:get_option(
outgoing_s2s_families,
fun(Families) ->
true = lists:all(
fun(ipv4) -> true;
(ipv6) -> true
@ -1228,14 +1228,43 @@ outgoing_s2s_families() ->
end, [ipv4, ipv6]).
outgoing_s2s_timeout() ->
ejabberd_config:get_local_option(
outgoing_s2s_options,
fun({_, TimeOut}) when is_integer(TimeOut), TimeOut > 0 ->
ejabberd_config:get_option(
outgoing_s2s_timeout,
fun(TimeOut) when is_integer(TimeOut), TimeOut > 0 ->
TimeOut;
({_, infinity}) ->
(infinity) ->
infinity
end, 10000).
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({outgoing_s2s_options, Families, Timeout}, Opts) ->
?WARNING_MSG("Option 'outgoing_s2s_options' is deprecated. "
"The option is still supported "
"but it is better to fix your config: "
"use 'outgoing_s2s_timeout' and "
"'outgoing_s2s_families' instead.", []),
[{outgoing_s2s_families, Families},
{outgoing_s2s_timeout, Timeout}
| Opts];
transform_options({s2s_dns_options, S2SDNSOpts}, AllOpts) ->
?WARNING_MSG("Option 's2s_dns_options' is deprecated. "
"The option is still supported "
"but it is better to fix your config: "
"use 's2s_dns_timeout' and "
"'s2s_dns_retries' instead", []),
lists:foldr(
fun({timeout, T}, AccOpts) ->
[{s2s_dns_timeout, T}|AccOpts];
({retries, R}, AccOpts) ->
[{s2s_dns_retries, R}|AccOpts];
(_, AccOpts) ->
AccOpts
end, AllOpts, S2SDNSOpts);
transform_options(Opt, Opts) ->
[Opt|Opts].
%% Human readable S2S logging: Log only new outgoing connections as INFO
%% Do not log dialback
log_s2s_out(false, _, _, _) -> ok;
@ -1278,7 +1307,7 @@ wait_before_reconnect(StateData) ->
queue = queue:new()}}.
get_max_retry_delay() ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
s2s_max_retry_delay,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> ?MAX_RETRY_DELAY;
@ -1295,7 +1324,7 @@ terminate_if_waiting_delay(From, To) ->
Pids).
fsm_limit_opts() ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];

View File

@ -34,7 +34,7 @@
%% External exports
-export([start/2, start_link/2, send_text/2,
send_element/2, socket_type/0]).
send_element/2, socket_type/0, transform_listen_option/2]).
%% gen_fsm callbacks
-export([init/1, wait_for_stream/2,
@ -124,29 +124,18 @@ init([{SockMod, Socket}, Opts]) ->
{value, {_, A}} -> A;
_ -> all
end,
{Hosts, Password} = case lists:keysearch(hosts, 1, Opts)
of
{value, {_, Hs, HOpts}} ->
case lists:keysearch(password, 1, HOpts) of
{value, {_, P}} -> {Hs, P};
_ ->
% TODO: generate error
false
end;
_ ->
case lists:keysearch(host, 1, Opts) of
{value, {_, H, HOpts}} ->
case lists:keysearch(password, 1, HOpts) of
{value, {_, P}} -> {[H], P};
_ ->
% TODO: generate error
false
end;
_ ->
% TODO: generate error
false
end
end,
%% This should be improved probably
{Hosts, HostOpts} = case lists:keyfind(hosts, 1, Opts) of
{_, HOpts} ->
{[H || {H, _} <- HOpts],
lists:flatten(
[O || {_, O} <- HOpts])};
_ ->
{[], []}
end,
Password = gen_mod:get_opt(password, HostOpts,
fun iolist_to_binary/1,
p1_sha:sha(crypto:rand_bytes(20))),
Shaper = case lists:keysearch(shaper_rule, 1, Opts) of
{value, {_, S}} -> S;
_ -> none
@ -384,12 +373,30 @@ send_element(StateData, El) ->
new_id() -> randoms:get_string().
transform_listen_option({hosts, Hosts, O}, Opts) ->
case lists:keyfind(hosts, 1, Opts) of
{_, PrevHostOpts} ->
NewHostOpts =
lists:foldl(
fun(H, Acc) ->
dict:append_list(H, O, Acc)
end, dict:from_list(PrevHostOpts), Hosts),
[{hosts, dict:to_list(NewHostOpts)}|
lists:keydelete(hosts, 1, Opts)];
_ ->
[{hosts, [{H, O} || H <- Hosts]}|Opts]
end;
transform_listen_option({host, Host, Os}, Opts) ->
transform_listen_option({hosts, [Host], Os}, Opts);
transform_listen_option(Opt, Opts) ->
[Opt|Opts].
fsm_limit_opts(Opts) ->
case lists:keysearch(max_fsm_queue, 1, Opts) of
{value, {_, N}} when is_integer(N) ->
[{max_queue, N}];
_ ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
max_fsm_queue,
fun(I) when is_integer(I), I > 0 -> I end) of
undefined -> [];

View File

@ -53,7 +53,7 @@
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
LH = ejabberd_config:get_local_option(
LH = ejabberd_config:get_option(
watchdog_large_heap,
fun(I) when is_integer(I), I > 0 -> I end,
1000000),
@ -200,7 +200,7 @@ send_message(From, To, Body) ->
[{xmlcdata, Body}]}]}).
get_admin_jids() ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
watchdog_admins,
fun(JIDs) ->
[jlib:jid_tolower(

View File

@ -827,14 +827,14 @@ process_admin(Host,
{value, {_, String}} ->
case parse_access_rule(String) of
{ok, Rs} ->
ejabberd_config:add_global_option({access, Name, Host},
ejabberd_config:add_option({access, Name, Host},
Rs),
ok;
_ -> error
end;
_ -> nothing
end,
Rules = case ejabberd_config:get_global_option(
Rules = case ejabberd_config:get_option(
{access, Name, Host}, fun(V) -> V end)
of
undefined -> [];
@ -1198,7 +1198,7 @@ access_parse_addnew(_AccessRules, Host, Query) ->
case lists:keysearch(<<"namenew">>, 1, Query) of
{value, {_, String}} when String /= <<"">> ->
Name = jlib:binary_to_atom(String),
ejabberd_config:add_global_option({access, Name, Host},
ejabberd_config:add_option({access, Name, Host},
[]),
ok
end.

View File

@ -182,7 +182,7 @@ get_opt({Key, Host}, Opts, F) ->
get_opt({Key, Host}, Opts, F, Default) ->
case gen_mod:get_opt(Key, Opts, F, undefined) of
undefined ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{Key, Host}, F, Default);
Val ->
Val

View File

@ -106,7 +106,7 @@ random_instance(MaxNum) ->
random:uniform(MaxNum) - 1.
get_instances(Server) ->
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{extauth_instances, Server},
fun(V) when is_integer(V), V > 0 ->
V

View File

@ -33,7 +33,7 @@
%% API
-export([start_link/3, add_iq_handler/6,
remove_iq_handler/3, stop_iq_handler/3, handle/7,
process_iq/6, check_type/1]).
process_iq/6, check_type/1, transform_module_options/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2,
@ -46,7 +46,7 @@
-record(state, {host, module, function}).
-type component() :: ejabberd_sm | ejabberd_local.
-type type() :: no_queue | one_queue | {queues, pos_integer()} | parallel.
-type type() :: no_queue | one_queue | pos_integer() | parallel.
-type opts() :: no_queue | {one_queue, pid()} | {queues, [pid()]} | parallel.
%%====================================================================
@ -71,7 +71,7 @@ add_iq_handler(Component, Host, NS, Module, Function,
[Host, Module, Function]),
Component:register_iq_handler(Host, NS, Module,
Function, {one_queue, Pid});
{queues, N} ->
N when is_integer(N) ->
Pids = lists:map(fun (_) ->
{ok, Pid} =
supervisor:start_child(ejabberd_iq_sup,
@ -130,9 +130,19 @@ process_iq(_Host, Module, Function, From, To, IQ) ->
check_type(no_queue) -> no_queue;
check_type(one_queue) -> one_queue;
check_type({queues, N}) when is_integer(N), N>0 -> {queues, N};
check_type(N) when is_integer(N), N>0 -> N;
check_type(parallel) -> parallel.
-spec transform_module_options([{atom(), any()}]) -> [{atom(), any()}].
transform_module_options(Opts) ->
lists:map(
fun({iqdisc, {queues, N}}) ->
{iqdisc, N};
(Opt) ->
Opt
end, Opts).
%%====================================================================
%% gen_server callbacks
%%====================================================================

View File

@ -64,13 +64,11 @@ start() ->
-spec start_module(binary(), atom(), opts()) -> any().
start_module(Host, Module, Opts) ->
set_module_opts_mnesia(Host, Module, Opts),
ets:insert(ejabberd_modules,
#ejabberd_module{module_host = {Module, Host},
opts = Opts}),
try Module:start(Host, Opts) catch
Class:Reason ->
del_module_mnesia(Host, Module),
ets:delete(ejabberd_modules, {Module, Host}),
ErrorText =
io_lib:format("Problem starting the module ~p for host "
@ -101,7 +99,7 @@ is_app_running(AppName) ->
stop_module(Host, Module) ->
case stop_module_keep_config(Host, Module) of
error -> error;
ok -> del_module_mnesia(Host, Module)
ok -> ok
end.
%% @doc Stop the module in a host, but keep its configuration.
@ -232,25 +230,6 @@ loaded_modules_with_opts(Host) ->
opts = '$2'},
[], [{{'$1', '$2'}}]}]).
set_module_opts_mnesia(Host, Module, Opts) ->
Modules = ejabberd_config:get_local_option(
{modules, Host},
fun(Ls) when is_list(Ls) -> Ls end,
[]),
Modules1 = lists:keydelete(Module, 1, Modules),
Modules2 = [{Module, Opts} | Modules1],
ejabberd_config:add_local_option({modules, Host},
Modules2).
del_module_mnesia(Host, Module) ->
Modules = ejabberd_config:get_local_option(
{modules, Host},
fun(Ls) when is_list(Ls) -> Ls end,
[]),
Modules1 = lists:keydelete(Module, 1, Modules),
ejabberd_config:add_local_option({modules, Host},
Modules1).
-spec get_hosts(opts(), binary()) -> [binary()].
get_hosts(Opts, Prefix) ->

View File

@ -3,7 +3,7 @@
%%% Author : Eric Cestari <ecestari@process-one.net>
%%% Purpose : Message Carbons XEP-0280 0.8
%%% Created : 5 May 2008 by Mickael Remond <mremond@process-one.net>
%%% Usage : Add the following line in modules section of ejabberd.cfg:
%%% Usage : Add the following line in modules section of ejabberd.yml:
%%% {mod_carboncopy, []}
%%%
%%%

View File

@ -129,7 +129,7 @@ process_get(#xmlel{name = <<"info">>}) ->
children = []}};
process_get(#xmlel{name = <<"welcome-message">>,
attrs = Attrs}) ->
{Subj, Body} = ejabberd_config:get_local_option(
{Subj, Body} = ejabberd_config:get_option(
welcome_message,
fun({Subj, Body}) ->
{iolist_to_binary(Subj),
@ -145,7 +145,7 @@ process_get(#xmlel{name = <<"welcome-message">>,
children = [{xmlcdata, Body}]}]}};
process_get(#xmlel{name = <<"registration-watchers">>,
attrs = Attrs}) ->
SubEls = ejabberd_config:get_local_option(
SubEls = ejabberd_config:get_option(
registration_watchers,
fun(JIDs) when is_list(JIDs) ->
lists:map(

View File

@ -36,7 +36,8 @@
process_sm_iq_items/3, process_sm_iq_info/3,
get_sm_identity/5, get_sm_features/5, get_sm_items/5,
get_info/5, register_feature/2, unregister_feature/2,
register_extra_domain/2, unregister_extra_domain/2]).
register_extra_domain/2, unregister_extra_domain/2,
transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -440,6 +441,22 @@ get_user_resources(User, Server) ->
end,
lists:sort(Rs)).
transform_module_options(Opts) ->
lists:map(
fun({server_info, Infos}) ->
NewInfos = lists:map(
fun({Modules, Name, URLs}) ->
[[{modules, Modules},
{name, Name},
{urls, URLs}]];
(Opt) ->
Opt
end, Infos),
{server_info, NewInfos};
(Opt) ->
Opt
end, Opts).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Support for: XEP-0157 Contact Addresses for XMPP Services
@ -465,9 +482,17 @@ get_info(_A, Host, Mod, Node, _Lang) when Node == <<>> ->
get_info(Acc, _, _, _Node, _) -> Acc.
get_fields_xml(Host, Module) ->
Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info,
fun(L) when is_list(L) -> L end,
[]),
Fields = gen_mod:get_module_opt(
Host, ?MODULE, server_info,
fun(L) ->
lists:map(
fun(Opts) ->
Mods = proplists:get_value(modules, Opts, all),
Name = proplists:get_value(names, Opts, <<>>),
URLs = proplists:get_value(urls, Opts, []),
{Mods, Name, URLs}
end, lists:flatmap(L))
end, []),
Fields_good = lists:filter(fun ({Modules, _, _}) ->
case Modules of
all -> true;

View File

@ -32,7 +32,8 @@
-export([start/2, stop/1, process_local_iq/3, export/1,
process_sm_iq/3, on_presence_update/4, import/1, import/3,
store_last_info/4, get_last_info/2, remove_user/2]).
store_last_info/4, get_last_info/2, remove_user/2,
transform_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -101,18 +102,13 @@ process_local_iq(_From, _To,
%% @doc Get the uptime of the ejabberd node, expressed in seconds.
%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime.
get_node_uptime() ->
case ejabberd_config:get_local_option(
case ejabberd_config:get_option(
node_start,
fun({MegaSecs, Secs, MicroSecs} = Now)
when is_integer(MegaSecs), MegaSecs >= 0,
is_integer(Secs), Secs >= 0,
is_integer(MicroSecs), MicroSecs >= 0 ->
Now
end) of
fun(S) when is_integer(S), S >= 0 -> S end) of
undefined ->
trunc(element(1, erlang:statistics(wall_clock)) / 1000);
StartNow ->
now_to_seconds(now()) - now_to_seconds(StartNow)
Now ->
now_to_seconds(now()) - Now
end.
now_to_seconds({MegaSecs, Secs, _MicroSecs}) ->
@ -319,3 +315,13 @@ import(_LServer, mnesia, #last_activity{} = LA) ->
mnesia:dirty_write(LA);
import(_, _, _) ->
pass.
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({node_start, {_, _, _} = Now}, Opts) ->
?WARNING_MSG("Old 'node_start' format detected. This is still supported "
"but it is better to fix your config.", []),
[{node_start, now_to_seconds(Now)}|Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].

View File

@ -33,7 +33,7 @@
-behaviour(gen_mod).
%% API
-export([start_link/2, start/2, stop/1,
-export([start_link/2, start/2, stop/1, transform_module_options/1,
check_access_log/2, add_to_log/5]).
%% gen_server callbacks
@ -111,6 +111,14 @@ check_access_log(Host, From) ->
Res -> Res
end.
transform_module_options(Opts) ->
lists:map(
fun({top_link, {S1, S2}}) ->
{top_link, [{S1, S2}]};
(Opt) ->
Opt
end, Opts).
%%====================================================================
%% gen_server callbacks
%%====================================================================
@ -152,14 +160,14 @@ init([Host, Opts]) ->
(universal) -> universal
end, local),
Top_link = gen_mod:get_opt(top_link, Opts,
fun({S1, S2}) ->
fun([{S1, S2}]) ->
{iolist_to_binary(S1),
iolist_to_binary(S2)}
end, {<<"/">>, <<"Home">>}),
NoFollow = gen_mod:get_opt(spam_prevention, Opts,
fun(B) when is_boolean(B) -> B end,
true),
Lang = ejabberd_config:get_local_option(
Lang = ejabberd_config:get_option(
{language, Host},
fun iolist_to_binary/1,
?MYLANG),

View File

@ -33,7 +33,7 @@
-behaviour(supervisor).
%% gen_mod callbacks.
-export([start/2, stop/1]).
-export([start/2, stop/1, transform_module_options/1]).
%% supervisor callbacks.
-export([init/1]).
@ -64,6 +64,9 @@ start_link(Host, Opts) ->
supervisor:start_link({local, Proc}, ?MODULE,
[Host, Opts]).
transform_module_options(Opts) ->
mod_proxy65_service:transform_module_options(Opts).
init([Host, Opts]) ->
Service = {mod_proxy65_service,
{mod_proxy65_service, start_link, [Host, Opts]},

View File

@ -35,7 +35,7 @@
handle_cast/2, terminate/2, code_change/3]).
%% API.
-export([start_link/2, add_listener/2,
-export([start_link/2, add_listener/2, transform_module_options/1,
delete_listener/1]).
-include("ejabberd.hrl").
@ -261,16 +261,15 @@ parse_options(ServerHost, Opts) ->
Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1,
<<"SOCKS5 Bytestreams">>),
IP = gen_mod:get_opt(ip, Opts,
fun(Addr) ->
jlib:ip_to_list(Addr),
fun(S) ->
{ok, Addr} = inet_parse:address(
binary_to_list(
iolist_to_binary(S))),
Addr
end, get_my_ip()),
HostName = gen_mod:get_opt(hostname, Opts,
fun(Addr) when is_tuple(Addr) ->
jlib:ip_to_list(Addr);
(S) ->
iolist_to_binary(S)
end, jlib:ip_to_list(IP)),
fun iolist_to_binary/1,
jlib:ip_to_list(IP)),
StreamAddr = [{<<"jid">>, MyHost},
{<<"host">>, HostName},
{<<"port">>, jlib:integer_to_binary(Port)}],
@ -278,6 +277,16 @@ parse_options(ServerHost, Opts) ->
name = Name, port = Port, ip = IP,
stream_addr = StreamAddr, acl = ACL}.
transform_module_options(Opts) ->
lists:map(
fun({ip, IP}) when is_tuple(IP) ->
{ip, jlib:ip_to_list(IP)};
({hostname, IP}) when is_tuple(IP) ->
{hostname, jlib:ip_to_list(IP)};
(Opt) ->
Opt
end, Opts).
get_my_ip() ->
{ok, MyHostName} = inet:gethostname(),
case inet:getaddr(MyHostName, inet) of

View File

@ -279,10 +279,14 @@ select_auth_method(anonymous, AuthMethods) ->
%% Obviously, we must use shaper with maximum rate.
find_maxrate(Shaper, JID1, JID2, Host) ->
MaxRate1 = shaper:new(acl:match_rule(Host, Shaper,
JID1)),
MaxRate2 = shaper:new(acl:match_rule(Host, Shaper,
JID2)),
MaxRate1 = case acl:match_rule(Host, Shaper, JID1) of
deny -> none;
R1 -> shaper:new(R1)
end,
MaxRate2 = case acl:match_rule(Host, Shaper, JID2) of
deny -> none;
R2 -> shaper:new(R2)
end,
if MaxRate1 == none; MaxRate2 == none -> none;
true -> lists:max([MaxRate1, MaxRate2])
end.

View File

@ -32,7 +32,8 @@
-export([start/2, stop/1, stream_feature_register/2,
unauthenticated_iq_register/4, try_register/5,
process_iq/3, send_registration_notifications/3]).
process_iq/3, send_registration_notifications/3,
transform_options/1, transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -418,7 +419,11 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
send_welcome_message(JID) ->
Host = JID#jid.lserver,
case gen_mod:get_module_opt(Host, ?MODULE, welcome_message,
fun({S, B}) ->
fun(Opts) ->
S = proplists:get_value(
subject, Opts, <<>>),
B = proplists:get_value(
body, Opts, <<>>),
{iolist_to_binary(S),
iolist_to_binary(B)}
end, {<<"">>, <<"">>})
@ -483,7 +488,7 @@ check_from(JID, Server) ->
check_timeout(undefined) -> true;
check_timeout(Source) ->
Timeout = ejabberd_config:get_local_option(
Timeout = ejabberd_config:get_option(
registration_timeout,
fun(TO) when is_integer(TO), TO > 0 ->
TO;
@ -537,7 +542,7 @@ clean_treap(Treap, CleanPriority) ->
remove_timeout(undefined) -> true;
remove_timeout(Source) ->
Timeout = ejabberd_config:get_local_option(
Timeout = ejabberd_config:get_option(
registration_timeout,
fun(TO) when is_integer(TO), TO > 0 ->
TO;
@ -604,6 +609,54 @@ is_strong_password(Server, Password) ->
ejabberd_auth:entropy(Password) >= Entropy
end.
transform_options(Opts) ->
Opts1 = transform_ip_access(Opts),
transform_module_options(Opts1).
transform_ip_access(Opts) ->
try
{value, {modules, ModOpts}, Opts1} = lists:keytake(modules, 1, Opts),
{value, {?MODULE, RegOpts}, ModOpts1} = lists:keytake(?MODULE, 1, ModOpts),
{value, {ip_access, L}, RegOpts1} = lists:keytake(ip_access, 1, RegOpts),
true = is_list(L),
?WARNING_MSG("Old 'ip_access' format detected. "
"The old format is still supported "
"but it is better to fix your config: "
"use access rules instead.", []),
ACLs = lists:flatmap(
fun({Action, S}) ->
ACLName = jlib:binary_to_atom(
iolist_to_binary(
["ip_", S])),
[{Action, ACLName},
{acl, ACLName, {ip, S}}]
end, L),
Access = {access, mod_register_networks,
[{Action, ACLName} || {Action, ACLName} <- ACLs]},
[ACL || {acl, _, _} = ACL <- ACLs] ++
[Access,
{modules,
[{mod_register,
[{ip_access, mod_register_networks}|RegOpts1]}
| ModOpts1]}|Opts1]
catch error:{badmatch, false} ->
Opts
end.
transform_module_options(Opts) ->
lists:flatmap(
fun({welcome_message, {Subj, Body}}) ->
?WARNING_MSG("Old 'welcome_message' format detected. "
"The old format is still supported "
"but it is better to fix your config: "
"change it to {welcome_message, "
"[{subject, Subject}, {body, Body}]}",
[]),
[{welcome_message, [{subject, Subj}, {body, Body}]}];
(Opt) ->
[Opt]
end, Opts).
%%%
%%% ip_access management
%%%
@ -614,75 +667,15 @@ may_remove_resource(From) -> From.
get_ip_access(Host) ->
gen_mod:get_module_opt(Host, ?MODULE, ip_access,
fun(IPAccess) ->
lists:flatmap(
fun({Access, S}) ->
{ok, IP, Mask} =
parse_ip_netmask(
iolist_to_binary(S)),
[{Access, IP, Mask}]
end, IPAccess)
end, []).
fun(A) when is_atom(A) -> A end,
all).
parse_ip_netmask(S) ->
case str:tokens(S, <<"/">>) of
[IPStr] ->
case inet_parse:address(binary_to_list(IPStr)) of
{ok, {_, _, _, _} = IP} -> {ok, IP, 32};
{ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
_ -> error
end;
[IPStr, MaskStr] ->
case catch jlib:binary_to_integer(MaskStr) of
Mask when is_integer(Mask), Mask >= 0 ->
case inet_parse:address(binary_to_list(IPStr)) of
{ok, {_, _, _, _} = IP} when Mask =< 32 ->
{ok, IP, Mask};
{ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
{ok, IP, Mask};
_ -> error
end;
_ -> error
end;
_ -> error
end.
check_ip_access(_Source, []) -> allow;
check_ip_access({User, Server, Resource}, IPAccess) ->
case ejabberd_sm:get_user_ip(User, Server, Resource) of
{IPAddress, _PortNumber} ->
check_ip_access(IPAddress, IPAccess);
_ -> true
{IPAddress, _PortNumber} ->
check_ip_access(IPAddress, IPAccess);
_ ->
deny
end;
check_ip_access({_, _, _, _} = IP,
[{Access, {_, _, _, _} = Net, Mask} | IPAccess]) ->
IPInt = ip_to_integer(IP),
NetInt = ip_to_integer(Net),
M = bnot (1 bsl (32 - Mask) - 1),
if IPInt band M =:= NetInt band M -> Access;
true -> check_ip_access(IP, IPAccess)
end;
check_ip_access({_, _, _, _, _, _, _, _} = IP,
[{Access, {_, _, _, _, _, _, _, _} = Net, Mask}
| IPAccess]) ->
IPInt = ip_to_integer(IP),
NetInt = ip_to_integer(Net),
M = bnot (1 bsl (128 - Mask) - 1),
if IPInt band M =:= NetInt band M -> Access;
true -> check_ip_access(IP, IPAccess)
end;
check_ip_access(IP, [_ | IPAccess]) ->
check_ip_access(IP, IPAccess).
ip_to_integer({IP1, IP2, IP3, IP4}) ->
IP1 bsl 8 bor IP2 bsl 8 bor IP3 bsl 8 bor IP4;
ip_to_integer({IP1, IP2, IP3, IP4, IP5, IP6, IP7,
IP8}) ->
IP1 bsl 16 bor IP2 bsl 16 bor IP3 bsl 16 bor IP4 bsl 16
bor IP5
bsl 16
bor IP6
bsl 16
bor IP7
bsl 16
bor IP8.
check_ip_access(IPAddress, IPAccess) ->
acl:match_rule(global, IPAccess, IPAddress).

View File

@ -38,7 +38,7 @@
-export([start/2, start_link/2, stop/1,
get_sm_features/5, process_local_iq/3, process_sm_iq/3,
remove_user/1, route/4]).
remove_user/1, route/4, transform_module_options/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -767,7 +767,7 @@ parse_options(Host, Opts) ->
VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts,
fun(Ls) ->
lists:map(
fun({S, P, L}) ->
fun({S, [{P, L}]}) ->
{iolist_to_binary(S),
iolist_to_binary(P),
[iolist_to_binary(E)
@ -823,6 +823,20 @@ parse_options(Host, Opts) ->
search_reported_attrs = SearchReportedAttrs,
matches = Matches}.
transform_module_options(Opts) ->
lists:map(
fun({ldap_vcard_map, Map}) ->
NewMap = lists:map(
fun({Field, Pattern, Attrs}) ->
{Field, [{Pattern, Attrs}]};
(Opt) ->
Opt
end, Map),
{ldap_vcard_map, NewMap};
(Opt) ->
Opt
end, Opts).
check_filter(F) ->
NewF = iolist_to_binary(F),
{ok, _} = eldap_filter:parse(NewF),

View File

@ -490,13 +490,11 @@ path_to_node(Path) -> node_flat:path_to_node(Path).
%% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) ->
Modules = ejabberd_config:get_local_option({modules, ServerHost}, fun(Ms) when is_list(Ms) -> Ms end),
ModCaps = [mod_caps_enabled || {mod_caps, _Opts} <- Modules],
case ModCaps of
[] ->
case gen_mod:is_loaded(ServerHost, mod_caps) of
false ->
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
"of host ~p. This plugin requires mod_caps "
"to be enabled, but it isn't.",
[ServerHost]);
_ -> ok
true -> ok
end.

View File

@ -433,7 +433,7 @@ path_to_node(Path) -> node_flat_odbc:path_to_node(Path).
%% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) ->
Modules = ejabberd_config:get_local_option({modules,
Modules = ejabberd_config:get_option({modules,
ServerHost},
fun(Ms) when is_list(Ms) -> Ms end),
ModCaps = [mod_caps_enabled

View File

@ -219,13 +219,15 @@ list_users(LServer,
[Prefix, Limit, Offset]))]).
users_number(LServer) ->
case element(1,
ejabberd_config:get_local_option(
{odbc_server, LServer}, fun(V) -> V end))
of
Type = ejabberd_config:get_option({odbc_type, LServer},
fun(pgsql) -> pgsql;
(mysql) -> mysql;
(odbc) -> odbc
end, odbc),
case Type of
pgsql ->
case
ejabberd_config:get_local_option(
ejabberd_config:get_option(
{pgsql_users_number_estimate, LServer},
fun(V) when is_boolean(V) -> V end,
false)

View File

@ -28,7 +28,8 @@
-author('alexey@process-one.net').
-export([new/1, new1/1, update/2]).
-export([start/0, new/1, new1/1, update/2,
transform_options/1, load_from_config/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
@ -37,32 +38,66 @@
lastrate = 0.0 :: float(),
lasttime = 0 :: integer()}).
-type maxrate() :: none | #maxrate{}.
-record(shaper, {name :: {atom(), global},
maxrate :: integer()}).
-type shaper() :: maxrate() | {maxrate(), integer()}.
-type shaper() :: none | #maxrate{}.
-export_type([shaper/0]).
-spec new(atom()) -> maxrate().
-spec start() -> ok.
start() ->
mnesia:create_table(shaper,
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, shaper)}]),
mnesia:add_table_copy(shaper, node(), ram_copies),
load_from_config(),
ok.
-spec load_from_config() -> ok | {error, any()}.
load_from_config() ->
Shapers = ejabberd_config:get_option(
shaper, fun(V) -> V end, []),
case mnesia:transaction(
fun() ->
lists:foreach(
fun({Name, MaxRate}) ->
mnesia:write(#shaper{name = {Name, global},
maxrate = MaxRate})
end, Shapers)
end) of
{atomic, ok} ->
ok;
Err ->
{error, Err}
end.
-spec new(atom()) -> shaper().
new(none) ->
none;
new(Name) ->
Data = ejabberd_config:get_global_option(
{shaper, Name, global},
fun({maxrate, R}) when is_integer(R), R>0 ->
{maxrate, R};
(none) ->
none
end, none),
new1(Data).
MaxRate = case ets:lookup(shaper, {Name, global}) of
[#shaper{maxrate = R}] ->
R;
[] ->
?WARNING_MSG("Attempt to initialize an "
"unspecified shaper '~s'", [Name]),
none
end,
new1(MaxRate).
-spec new1(none | {maxrate, integer()}) -> maxrate().
-spec new1(none | integer()) -> shaper().
new1(none) -> none;
new1({maxrate, MaxRate}) ->
new1(MaxRate) ->
#maxrate{maxrate = MaxRate, lastrate = 0.0,
lasttime = now_to_usec(now())}.
-spec update(maxrate(), integer()) -> {maxrate(), integer()}.
-spec update(shaper(), integer()) -> {shaper(), integer()}.
update(none, _Size) -> {none, 0};
update(#maxrate{} = State, Size) ->
@ -84,5 +119,15 @@ update(#maxrate{} = State, Size) ->
lasttime = NextNow},
Pause}.
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({shaper, Name, {maxrate, N}}, Opts) ->
[{shaper, [{Name, N}]}|Opts];
transform_options({shaper, Name, none}, Opts) ->
[{shaper, [{Name, none}]}|Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].
now_to_usec({MSec, Sec, USec}) ->
(MSec * 1000000 + Sec) * 1000000 + USec.

View File

@ -0,0 +1,267 @@
host_config:
"pgsql.localhost":
odbc_username: "ejabberd_test"
odbc_type: pgsql
odbc_server: "localhost"
odbc_port: 5432
odbc_pool_size: 1
odbc_password: "ejabberd_test"
odbc_database: "ejabberd_test"
auth_method: odbc
modules:
mod_announce:
db_type: odbc
mod_blocking:
db_type: odbc
mod_caps:
db_type: odbc
mod_last:
db_type: odbc
mod_muc:
db_type: odbc
mod_offline:
db_type: odbc
mod_privacy:
db_type: odbc
mod_private:
db_type: odbc
mod_pubsub_odbc:
access_createnode: pubsub_createnode
ignore_pep_from_offline: true
last_item_cache: false
plugins:
- "flat"
- "hometree"
- "pep"
mod_roster:
db_type: odbc
mod_mam:
db_type: odbc
mod_vcard:
db_type: odbc
mod_adhoc: []
mod_configure: []
mod_disco: []
mod_ping: []
mod_proxy65: []
mod_register:
welcome_message:
subject: "Welcome!"
body: "Hi.
Welcome to this XMPP server."
mod_stats: []
mod_time: []
mod_version: []
host_config:
"mysql.localhost":
odbc_username: "ejabberd_test"
odbc_type: mysql
odbc_server: "localhost"
odbc_port: 3306
odbc_pool_size: 1
odbc_password: "ejabberd_test"
odbc_database: "ejabberd_test"
auth_method: odbc
modules:
mod_announce:
db_type: odbc
mod_blocking:
db_type: odbc
mod_caps:
db_type: odbc
mod_last:
db_type: odbc
mod_muc:
db_type: odbc
mod_offline:
db_type: odbc
mod_privacy:
db_type: odbc
mod_private:
db_type: odbc
mod_pubsub_odbc:
access_createnode: pubsub_createnode
ignore_pep_from_offline: true
last_item_cache: false
plugins:
- "flat"
- "hometree"
- "pep"
mod_roster:
db_type: odbc
mod_mam:
db_type: odbc
mod_vcard:
db_type: odbc
mod_adhoc: []
mod_configure: []
mod_disco: []
mod_ping: []
mod_proxy65: []
mod_register:
welcome_message:
subject: "Welcome!"
body: "Hi.
Welcome to this XMPP server."
mod_stats: []
mod_time: []
mod_version: []
host_config:
"mnesia.localhost":
auth_method: internal
modules:
mod_announce:
db_type: internal
mod_blocking:
db_type: internal
mod_caps:
db_type: internal
mod_last:
db_type: internal
mod_muc:
db_type: internal
mod_offline:
db_type: internal
mod_privacy:
db_type: internal
mod_private:
db_type: internal
mod_pubsub:
access_createnode: pubsub_createnode
ignore_pep_from_offline: true
last_item_cache: false
plugins:
- "flat"
- "hometree"
- "pep"
mod_roster:
db_type: internal
mod_mam:
db_type: internal
mod_vcard:
db_type: internal
mod_adhoc: []
mod_configure: []
mod_disco: []
mod_ping: []
mod_proxy65: []
mod_register:
welcome_message:
subject: "Welcome!"
body: "Hi.
Welcome to this XMPP server."
mod_stats: []
mod_time: []
mod_version: []
host_config:
"localhost":
auth_method: internal
host_config:
"ldap.localhost":
ldap_servers:
- "localhost"
ldap_rootdn: "cn=admin,dc=localhost"
ldap_port: 1389
ldap_password: "password"
ldap_base: "ou=users,dc=localhost"
auth_method: ldap
modules:
mod_vcard_ldap: []
mod_adhoc: []
mod_configure: []
mod_disco: []
mod_ping: []
mod_proxy65: []
mod_register:
welcome_message:
subject: "Welcome!"
body: "Hi.
Welcome to this XMPP server."
mod_stats: []
mod_time: []
mod_version: []
host_config:
"extauth.localhost":
extauth_program: "python extauth.py"
auth_method: external
hosts:
- "localhost"
- "mnesia.localhost"
- "mysql.localhost"
- "pgsql.localhost"
- "extauth.localhost"
- "ldap.localhost"
access:
announce:
admin: allow
c2s:
blocked: deny
all: allow
c2s_shaper:
admin: none
all: normal
configure:
admin: allow
local:
local: allow
max_user_offline_messages:
admin: 5000
all: 100
max_user_sessions:
all: 10
muc:
all: allow
muc_admin:
admin: allow
muc_create:
local: allow
pubsub_createnode:
local: allow
register:
all: allow
s2s_shaper:
all: fast
acl:
local:
user_regexp:
- []
define_macro:
CERTFILE: "cert.pem"
language: "en"
listen:
-
port: 5222
module: ejabberd_c2s
max_stanza_size: 65536
certfile: CERTFILE
zlib: true
starttls: true
shaper: c2s_shaper
access: c2s
-
port: 5269
module: ejabberd_s2s_in
-
port: 5280
module: ejabberd_http
captcha: true
loglevel: 4
max_fsm_queue: 1000
modules:
mod_adhoc: []
mod_configure: []
mod_disco: []
mod_ping: []
mod_proxy65: []
mod_register:
welcome_message:
subject: "Welcome!"
body: "Hi.
Welcome to this XMPP server."
mod_stats: []
mod_time: []
mod_version: []
registration_timeout: infinity
shaper:
fast: 50000
normal: 1000

View File

@ -21,7 +21,7 @@ init_config(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
[_, _|Tail] = lists:reverse(filename:split(DataDir)),
BaseDir = filename:join(lists:reverse(Tail)),
ConfigPath = filename:join([DataDir, "ejabberd.cfg"]),
ConfigPath = filename:join([DataDir, "ejabberd.yml"]),
LogPath = filename:join([PrivDir, "ejabberd.log"]),
SASLPath = filename:join([PrivDir, "sasl.log"]),
MnesiaDir = filename:join([PrivDir, "mnesia"]),