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

1
README
View File

@ -9,6 +9,7 @@ To compile ejabberd you need:
- GNU Make - GNU Make
- GCC - GCC
- Libexpat 1.95 or higher - Libexpat 1.95 or higher
- Libyaml 1.4 or higher
- Erlang/OTP R15B or higher. - Erlang/OTP R15B or higher.
- OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption. - OpenSSL 0.9.8 or higher, for STARTTLS, SASL and SSL encryption.
- Zlib 1.2.3 or higher, for Stream Compression support - 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" . "$EJABBERDCTL_CONFIG_PATH"
fi fi
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.cfg EJABBERD_CONFIG_PATH=$ETCDIR/ejabberd.yml
fi fi
if [ "$LOGS_DIR" = "" ] ; then if [ "$LOGS_DIR" = "" ] ; then
LOGS_DIR={{localstatedir}}/log/ejabberd 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_tls, ".*", {git, "git://github.com/processone/tls"}},
{p1_stringprep, ".*", {git, "git://github.com/processone/stringprep"}}, {p1_stringprep, ".*", {git, "git://github.com/processone/stringprep"}},
{p1_xml, ".*", {git, "git://github.com/processone/xml"}}, {p1_xml, ".*", {git, "git://github.com/processone/xml"}},
{p1_yaml, ".*", {git, "git://github.com/processone/p1_yaml"}},
{xmlrpc, ".*", {git, "git://github.com/rds13/xmlrpc"}}], {xmlrpc, ".*", {git, "git://github.com/rds13/xmlrpc"}}],
ConfigureCmd = fun(Pkg, Flags) -> ConfigureCmd = fun(Pkg, Flags) ->

View File

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

View File

@ -29,35 +29,38 @@
-author('alexey@process-one.net'). -author('alexey@process-one.net').
-export([start/0, to_record/3, add/3, add_list/3, -export([start/0, to_record/3, add/3, add_list/3,
add_local/3, add_list_local/3, add_local/3, add_list_local/3, load_from_config/0,
match_rule/3, match_acl/3]). match_rule/3, match_acl/3, transform_options/1]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
-include("jlib.hrl"). -include("jlib.hrl").
-record(acl, {aclname, aclspec}). -record(acl, {aclname, aclspec}).
-record(access, {name :: access_name(),
rules = [] :: [access_rule()]}).
-type regexp() :: binary(). -type regexp() :: binary().
-type glob() :: binary(). -type glob() :: binary().
-type access_name() :: atom().
-type access_rule() :: {atom(), any()}.
-type host() :: binary().
-type aclname() :: {atom(), binary() | global}. -type aclname() :: {atom(), binary() | global}.
-type aclspec() :: all | none | -type aclspec() :: all | none |
{user, binary()} | {user, {binary(), host()} | binary()} |
{user, binary(), binary()} |
{server, binary()} | {server, binary()} |
{resource, binary()} | {resource, binary()} |
{user_regexp, regexp()} | {user_regexp, {regexp(), host()} | regexp()} |
{shared_group, binary()} | {shared_group, {binary(), host()} | binary()} |
{shared_group, binary(), binary()} | {user_regexp, {regexp(), host()} | regexp()} |
{user_regexp, regexp(), binary()} |
{server_regexp, regexp()} | {server_regexp, regexp()} |
{resource_regexp, regexp()} | {resource_regexp, regexp()} |
{node_regexp, regexp(), regexp()} | {node_regexp, {regexp(), regexp()}} |
{user_glob, glob()} | {user_glob, {glob(), host()} | glob()} |
{user_glob, glob(), binary()} |
{server_glob, glob()} | {server_glob, glob()} |
{resource_glob, glob()} | {resource_glob, glob()} |
{node_glob, glob(), glob()}. {ip, {inet:ip_address(), integer()}} |
{node_glob, {glob(), glob()}}.
-type acl() :: #acl{aclname :: aclname(), -type acl() :: #acl{aclname :: aclname(),
aclspec :: aclspec()}. aclspec :: aclspec()}.
@ -65,12 +68,23 @@
-export_type([acl/0]). -export_type([acl/0]).
start() -> start() ->
case catch mnesia:table_info(acl, storage_type) of
disc_copies ->
mnesia:delete_table(acl);
_ ->
ok
end,
mnesia:create_table(acl, mnesia:create_table(acl,
[{disc_copies, [node()]}, {type, bag}, [{ram_copies, [node()]}, {type, bag},
{local_content, true}, {local_content, true},
{attributes, record_info(fields, acl)}]), {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), mnesia:add_table_copy(acl, node(), ram_copies),
update_table(), mnesia:add_table_copy(access, node(), ram_copies),
load_from_config(),
ok. ok.
-spec to_record(binary(), atom(), aclspec()) -> acl(). -spec to_record(binary(), atom(), aclspec()) -> acl().
@ -82,7 +96,7 @@ to_record(Host, ACLName, ACLSpec) ->
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}. -spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
add(Host, ACLName, ACLSpec) -> 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, ?MODULE, add_local,
[Host, ACLName, ACLSpec]), [Host, ACLName, ACLSpec]),
case lists:keyfind(aborted, 1, ResL) of 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()}. -spec add_list(binary(), [acl()], boolean()) -> ok | {error, any()}.
add_list(Host, ACLs, Clear) -> 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, ?MODULE, add_list_local,
[Host, ACLs, Clear]), [Host, ACLs, Clear]),
case lists:keyfind(aborted, 1, ResL) of case lists:keyfind(aborted, 1, ResL) of
@ -147,130 +161,196 @@ add_list_local(Host, ACLs, Clear) ->
end, end,
mnesia:transaction(F). 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)}; add_access(Host, Access, Rules) ->
normalize_spec({A, B, C}) -> case mnesia:transaction(
{A, normalize(B), normalize(C)}; fun() ->
normalize_spec(all) -> all; mnesia:write(
normalize_spec(none) -> none. #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) -> load_from_config() ->
case Rule of Hosts = [global|?MYHOSTS],
all -> allow; lists:foreach(
none -> deny; fun(Host) ->
_ -> ACLs = ejabberd_config:get_option(
case ejabberd_config:get_global_option( {acl, Host}, fun(V) -> V end, []),
{access, Rule, global}, fun(V) -> V end) AccessRules = ejabberd_config:get_option(
of {access, Host}, fun(V) -> V end, []),
undefined -> deny; lists:foreach(
GACLs -> match_acls(GACLs, JID, global) fun({ACLName, SpecList}) ->
end lists:foreach(
end; fun({ACLType, ACLSpecs}) when is_list(ACLSpecs) ->
match_rule(Host, Rule, JID) -> lists:foreach(
case Rule of fun(ACLSpec) ->
all -> allow; add(Host, ACLName,
none -> deny; {ACLType, ACLSpec})
_ -> end, lists:flatten(ACLSpecs));
case ejabberd_config:get_global_option( ({ACLType, ACLSpecs}) ->
{access, Rule, global}, fun(V) -> V end) add(Host, ACLName, {ACLType, ACLSpecs})
of end, lists:flatten(SpecList))
undefined -> end, ACLs),
case ejabberd_config:get_global_option( lists:foreach(
{access, Rule, Host}, fun(V) -> V end) fun({Access, Rules}) ->
of add_access(Host, Access, Rules)
undefined -> deny; end, AccessRules)
ACLs -> match_acls(ACLs, JID, Host) end, Hosts).
end;
GACLs -> b(S) ->
case ejabberd_config:get_global_option( iolist_to_binary(S).
{access, Rule, Host}, fun(V) -> V end)
of nodeprep(S) ->
undefined -> match_acls(GACLs, JID, Host); jlib:nodeprep(b(S)).
ACLs ->
case lists:reverse(GACLs) of nameprep(S) ->
[{allow, all} | Rest] -> jlib:nameprep(b(S)).
match_acls(lists:reverse(Rest) ++
ACLs ++ [{allow, all}], resourceprep(S) ->
JID, Host); jlib:resourceprep(b(S)).
_ -> match_acls(GACLs ++ ACLs, JID, Host)
end normalize_spec(Spec) ->
end case Spec of
end 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. end.
match_acls([], _, _Host) -> deny; 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 case match_acl(ACL, JID, Host) of
true -> Access; true -> Access;
_ -> match_acls(ACLs, JID, Host) _ -> match_acls(ACLs, JID, Host)
end. 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) -> match_acl(ACL, JID, Host) ->
case ACL of {User, Server, Resource} = jlib:jid_tolower(JID),
all -> true; lists:any(
none -> false; fun(#acl{aclspec = Spec}) ->
_ -> case Spec of
{User, Server, Resource} = jlib:jid_tolower(JID), all -> true;
lists:any(fun (#acl{aclspec = Spec}) -> {user, {U, S}} -> U == User andalso S == Server;
case Spec of {user, U} ->
all -> true; U == User andalso
{user, U} -> lists:member(Server, ?MYHOSTS);
U == User andalso {server, S} -> S == Server;
(Host == Server orelse {resource, R} -> R == Resource;
Host == global andalso {shared_group, {G, H}} ->
lists:member(Server, ?MYHOSTS)); Mod = loaded_shared_roster_module(H),
{user, U, S} -> U == User andalso S == Server; Mod:is_user_in_group({User, Server}, G, H);
{server, S} -> S == Server; {shared_group, G} ->
{resource, R} -> R == Resource; Mod = loaded_shared_roster_module(Host),
{user_regexp, UR} -> Mod:is_user_in_group({User, Server}, G, Host);
(Host == Server orelse {user_regexp, {UR, S}} ->
Host == global andalso S == Server andalso is_regexp_match(User, UR);
lists:member(Server, ?MYHOSTS)) {user_regexp, UR} ->
andalso is_regexp_match(User, UR); lists:member(Server, ?MYHOSTS)
{shared_group, G} -> andalso is_regexp_match(User, UR);
Mod = loaded_shared_roster_module(Host), {server_regexp, SR} ->
Mod:is_user_in_group({User, Server}, G, Host); is_regexp_match(Server, SR);
{shared_group, G, H} -> {resource_regexp, RR} ->
Mod = loaded_shared_roster_module(H), is_regexp_match(Resource, RR);
Mod:is_user_in_group({User, Server}, G, H); {node_regexp, {UR, SR}} ->
{user_regexp, UR, S} -> is_regexp_match(Server, SR) andalso
S == Server andalso is_regexp_match(User, UR); is_regexp_match(User, UR);
{server_regexp, SR} -> {user_glob, {UR, S}} ->
is_regexp_match(Server, SR); S == Server andalso is_glob_match(User, UR);
{resource_regexp, RR} -> {user_glob, UR} ->
is_regexp_match(Resource, RR); lists:member(Server, ?MYHOSTS)
{node_regexp, UR, SR} -> andalso is_glob_match(User, UR);
is_regexp_match(Server, SR) andalso {server_glob, SR} -> is_glob_match(Server, SR);
is_regexp_match(User, UR); {resource_glob, RR} ->
{user_glob, UR} -> is_glob_match(Resource, RR);
(Host == Server orelse {node_glob, {UR, SR}} ->
Host == global andalso is_glob_match(Server, SR) andalso
lists:member(Server, ?MYHOSTS)) is_glob_match(User, UR);
andalso is_glob_match(User, UR); WrongSpec ->
{user_glob, UR, S} -> ?ERROR_MSG("Wrong ACL expression: ~p~nCheck your "
S == Server andalso is_glob_match(User, UR); "config file and reload it with the override_a"
{server_glob, SR} -> is_glob_match(Server, SR); "cls option enabled",
{resource_glob, RR} -> [WrongSpec]),
is_glob_match(Resource, RR); false
{node_glob, UR, SR} -> end
is_glob_match(Server, SR) andalso end,
is_glob_match(User, UR); ets:lookup(acl, {ACL, Host}) ++
WrongSpec -> ets:lookup(acl, {ACL, global})).
?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.
is_regexp_match(String, RegExp) -> is_regexp_match(String, RegExp) ->
case ejabberd_regexp:run(String, RegExp) of case ejabberd_regexp:run(String, RegExp) of
@ -286,34 +366,115 @@ is_glob_match(String, Glob) ->
is_regexp_match(String, is_regexp_match(String,
ejabberd_regexp:sh_to_awk(Glob)). 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) -> loaded_shared_roster_module(Host) ->
case gen_mod:is_loaded(Host, mod_shared_roster_ldap) of case gen_mod:is_loaded(Host, mod_shared_roster_ldap) of
true -> mod_shared_roster_ldap; true -> mod_shared_roster_ldap;
false -> mod_shared_roster false -> mod_shared_roster
end. end.
update_table() -> parse_ip_netmask(S) ->
Fields = record_info(fields, acl), case str:tokens(S, <<"/">>) of
case mnesia:table_info(acl, attributes) of [IPStr] ->
Fields -> case inet_parse:address(binary_to_list(IPStr)) of
ejabberd_config:convert_table_to_binary( {ok, {_, _, _, _} = IP} -> {ok, IP, 32};
acl, Fields, bag, {ok, {_, _, _, _, _, _, _, _} = IP} -> {ok, IP, 128};
fun(#acl{aclspec = Spec}) when is_tuple(Spec) -> _ -> error
element(2, Spec); end;
(_) -> [IPStr, MaskStr] ->
'$next' case catch jlib:binary_to_integer(MaskStr) of
end, Mask when is_integer(Mask), Mask >= 0 ->
fun(#acl{aclname = {ACLName, Host}, case inet_parse:address(binary_to_list(IPStr)) of
aclspec = Spec} = R) -> {ok, {_, _, _, _} = IP} when Mask =< 32 ->
NewHost = if Host == global -> {ok, IP, Mask};
Host; {ok, {_, _, _, _, _, _, _, _} = IP} when Mask =< 128 ->
true -> {ok, IP, Mask};
iolist_to_binary(Host) _ -> error
end, end;
R#acl{aclname = {ACLName, NewHost}, _ -> error
aclspec = normalize_spec(Spec)} end;
end); _ -> error
_ ->
?INFO_MSG("Recreating acl table", []),
mnesia:transform_table(acl, ignore, Fields)
end. 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; Str when is_binary(Str) -> Str;
_ -> _ ->
<<"unknown-fqdn, please configure fqdn " <<"unknown-fqdn, please configure fqdn "
"option in ejabberd.cfg!">> "option in ejabberd.yml!">>
end. end.
get_local_fqdn2() -> get_local_fqdn2() ->
case ejabberd_config:get_local_option( case ejabberd_config:get_option(
fqdn, fun iolist_to_binary/1) of fqdn, fun iolist_to_binary/1) of
ConfiguredFqdn when is_binary(ConfiguredFqdn) -> ConfiguredFqdn when is_binary(ConfiguredFqdn) ->
ConfiguredFqdn; ConfiguredFqdn;

View File

@ -164,6 +164,12 @@ commands() ->
module = ejd2odbc, function = export, module = ejd2odbc, function = export,
args = [{host, string}, {file, string}], result = {res, rescode}}, 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], #ejabberd_commands{name = delete_expired_messages, tags = [purge],
desc = "Delete expired offline messages from database", desc = "Delete expired offline messages from database",
module = ?MODULE, function = delete_expired_messages, module = ?MODULE, function = delete_expired_messages,

View File

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

View File

@ -423,7 +423,7 @@ auth_modules() ->
%% Return the list of authenticated modules for a given host %% Return the list of authenticated modules for a given host
auth_modules(Server) -> auth_modules(Server) ->
LServer = jlib:nameprep(Server), LServer = jlib:nameprep(Server),
Methods = ejabberd_config:get_local_option( Methods = ejabberd_config:get_option(
{auth_method, LServer}, {auth_method, LServer},
fun(V) when is_list(V) -> fun(V) when is_list(V) ->
true = lists:all(fun is_atom/1, 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 %% Return the anonymous protocol to use: sasl_anon|login_anon|both
%% defaults to login_anon %% defaults to login_anon
anonymous_protocol(Host) -> anonymous_protocol(Host) ->
ejabberd_config:get_local_option( ejabberd_config:get_option(
{anonymous_protocol, Host}, {anonymous_protocol, Host},
fun(sasl_anon) -> sasl_anon; fun(sasl_anon) -> sasl_anon;
(login_anon) -> login_anon; (login_anon) -> login_anon;
@ -115,7 +115,7 @@ anonymous_protocol(Host) ->
%% Return true if multiple connections have been allowed in the config file %% Return true if multiple connections have been allowed in the config file
%% defaults to false %% defaults to false
allow_multiple_connections(Host) -> allow_multiple_connections(Host) ->
ejabberd_config:get_local_option( ejabberd_config:get_option(
{allow_multiple_connections, Host}, {allow_multiple_connections, Host},
fun(V) when is_boolean(V) -> V end, fun(V) when is_boolean(V) -> V end,
false). false).

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,16 +27,16 @@
-module(ejabberd_config). -module(ejabberd_config).
-author('alexey@process-one.net'). -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, add_global_option/2, add_local_option/2,
get_global_option/2, get_local_option/2, get_global_option/2, get_local_option/2,
get_global_option/3, get_local_option/3, get_global_option/3, get_local_option/3,
get_option/2, get_option/3, add_option/2]). get_option/2, get_option/3, add_option/2,
-export([get_vh_by_auth_method/1]). get_vh_by_auth_method/1, is_file_readable/1,
-export([is_file_readable/1]). get_version/0, get_myhosts/0, get_mylang/0,
-export([get_version/0, get_myhosts/0, get_mylang/0]). prepare_opt_val/4, convert_table_to_binary/5,
-export([prepare_opt_val/4]). transform_options/1, collect_options/1,
-export([convert_table_to_binary/5]). convert_to_yaml/1, convert_to_yaml/2]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -53,21 +53,29 @@
start() -> 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, mnesia:create_table(local_config,
[{disc_copies, [node()]}, [{ram_copies, [node()]},
{local_content, true}, {local_content, true},
{attributes, record_info(fields, local_config)}]), {attributes, record_info(fields, local_config)}]),
mnesia:add_table_copy(local_config, node(), ram_copies), mnesia:add_table_copy(local_config, node(), ram_copies),
Config = get_ejabberd_config_path(), Config = get_ejabberd_config_path(),
load_file(Config), State = read_file(Config),
%% This start time is used by mod_last: %% This start time is used by mod_last:
add_option(node_start, now()), {MegaSecs, Secs, _} = now(),
ok. UnixTime = MegaSecs*1000000 + Secs,
State1 = set_option({node_start, global}, UnixTime, State),
set_opts(State1).
%% @doc Get the filename of the ejabberd configuration file. %% @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. %% 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() %% @spec () -> string()
get_ejabberd_config_path() -> get_ejabberd_config_path() ->
case application:get_env(config) of case application:get_env(config) of
@ -81,16 +89,59 @@ get_ejabberd_config_path() ->
end end
end. end.
%% @doc Load the ejabberd configuration file. %% @doc Read the ejabberd configuration file.
%% It also includes additional configuration files and replaces macros. %% It also includes additional configuration files and replaces macros.
%% This function will crash if finds some error in the configuration file. %% This function will crash if finds some error in the configuration file.
%% @spec (File::string()) -> ok %% @spec (File::string()) -> #state{}.
load_file(File) -> read_file(File) ->
Terms = get_plain_terms_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), State = lists:foldl(fun search_hosts/2, #state{}, Terms),
Terms_macros = replace_macros(Terms), {Head, Tail} = lists:partition(
Res = lists:foldl(fun process_term/2, State, Terms_macros), fun({host_config, _}) -> false;
set_opts(Res). ({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. %% @doc Read an ejabberd configuration file and return the terms.
%% Input is an absolute or relative path to an ejabberd config file. %% 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. %% and the terms in those files were included.
%% @spec(string()) -> [term()] %% @spec(string()) -> [term()]
%% @spec(iolist()) -> [term()] %% @spec(iolist()) -> [term()]
get_plain_terms_file(File) when is_binary(File) -> get_plain_terms_file(File) ->
get_plain_terms_file(binary_to_list(File)); get_plain_terms_file(File, [{include_files, true}]).
get_plain_terms_file(File1) ->
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), File = get_absolute_path(File1),
case file:consult(File) of case consult(File) of
{ok, Terms} -> {ok, Terms} ->
BinTerms = strings_to_binary(Terms), BinTerms = strings_to_binary(Terms),
include_config_files(BinTerms); case proplists:get_bool(include_files, Opts) of
{error, {LineNumber, erl_parse, _ParseMessage} = Reason} -> true ->
ExitText = describe_config_problem(File, Reason, LineNumber), include_config_files(BinTerms);
?ERROR_MSG(ExitText, []), false ->
exit_or_halt(ExitText); BinTerms
end;
{error, Reason} -> {error, Reason} ->
ExitText = describe_config_problem(File, Reason), ?ERROR_MSG(Reason, []),
?ERROR_MSG(ExitText, []), exit_or_halt(Reason)
exit_or_halt(ExitText) 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. end.
%% @doc Convert configuration filename to absolute path. %% @doc Convert configuration filename to absolute path.
@ -158,7 +234,7 @@ search_hosts(Term, State) ->
add_hosts_to_option(Hosts, State) -> add_hosts_to_option(Hosts, State) ->
PrepHosts = normalize_hosts(Hosts), 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) ->
normalize_hosts(Hosts,[]). normalize_hosts(Hosts,[]).
@ -232,21 +308,37 @@ exit_or_halt(ExitText) ->
%% @doc Include additional configuration files in the list of terms. %% @doc Include additional configuration files in the list of terms.
%% @spec ([term()]) -> [term()] %% @spec ([term()]) -> [term()]
include_config_files(Terms) -> 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) -> transform_include_option({include_config_file, File}) when is_list(File) ->
Res; case is_string(File) of
include_config_files([{include_config_file, Filename} | Terms], Res) -> true -> {File, []};
include_config_files([{include_config_file, Filename, []} | Terms], Res); false -> File
include_config_files([{include_config_file, Filename, Options} | Terms], Res) -> 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), Included_terms = get_plain_terms_file(Filename),
Disallow = proplists:get_value(disallow, Options, []), Disallow = proplists:get_value(disallow, Options, []),
Included_terms2 = delete_disallowed(Disallow, Included_terms), Included_terms2 = delete_disallowed(Disallow, Included_terms),
Allow_only = proplists:get_value(allow_only, Options, all), Allow_only = proplists:get_value(allow_only, Options, all),
Included_terms3 = keep_only_allowed(Allow_only, Included_terms2), 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]).
%% @doc Filter from the list of terms the disallowed. %% @doc Filter from the list of terms the disallowed.
%% Returns a sublist of Terms without the ones which first element is %% Returns a sublist of Terms without the ones which first element is
@ -308,12 +400,19 @@ split_terms_macros(Terms) ->
fun(Term, {TOs, Ms}) -> fun(Term, {TOs, Ms}) ->
case Term of case Term of
{define_macro, Key, Value} -> {define_macro, Key, Value} ->
case is_atom(Key) and is_all_uppercase(Key) of case is_correct_macro({Key, Value}) of
true -> true ->
{TOs, Ms++[{Key, Value}]}; {TOs, Ms++[{Key, Value}]};
false -> false ->
exit({macro_not_properly_defined, Term}) exit({macro_not_properly_defined, Term})
end; 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 -> Term ->
{TOs ++ [Term], Ms} {TOs ++ [Term], Ms}
end end
@ -321,6 +420,11 @@ split_terms_macros(Terms) ->
{[], []}, {[], []},
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. %% @doc Recursively replace in Terms macro usages with the defined value.
%% @spec (Terms, Macros) -> Terms %% @spec (Terms, Macros) -> Terms
%% Terms = [term()] %% Terms = [term()]
@ -328,7 +432,9 @@ split_terms_macros(Terms) ->
replace([], _) -> replace([], _) ->
[]; [];
replace([Term|Terms], Macros) -> 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) -> replace_term(Key, Macros) when is_atom(Key) ->
case is_all_uppercase(Key) of case is_all_uppercase(Key) of
@ -362,121 +468,65 @@ is_all_uppercase(Atom) ->
process_term(Term, State) -> process_term(Term, State) ->
case Term of case Term of
override_global -> {host_config, HostTerms} ->
State#state{override_global = true}; lists:foldl(
override_local -> fun({Host, Terms}, AccState) ->
State#state{override_local = true}; lists:foldl(fun(T, S) ->
override_acls -> process_host_term(T, Host, S, set)
State#state{override_acls = true}; end, AccState, Terms)
{host_config, Host, Terms} -> end, State, HostTerms);
lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end, {append_host_config, HostTerms} ->
State, Terms); lists:foldl(
{listen, Listeners} -> fun({Host, Terms}, AccState) ->
Listeners2 = lists:foldl(fun(T, S) ->
lists:map( process_host_term(T, Host, S, append)
fun({PortIP, Module, Opts}) -> end, AccState, Terms)
{Port, IPT, _, _, Proto, OptsClean} = end, State, HostTerms);
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;
_ -> _ ->
lists:foldl(fun(Host, S) -> process_host_term(Term, Host, S) end, process_host_term(Term, global, State, set)
State, [global|State#state.hosts])
end. end.
process_host_term(Term, Host, State) -> process_host_term(Term, Host, State, Action) ->
case Term of case Term of
{acl, ACLName, ACLData} -> {modules, Modules} when Action == set ->
State#state{opts = set_option({modules, Host}, replace_modules(Modules), State);
[acl:to_record(Host, ACLName, ACLData) | State#state.opts]}; {modules, Modules} when Action == append ->
{access, RuleName, Rules} -> append_option({modules, Host}, replace_modules(Modules), State);
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);
{host, _} -> {host, _} ->
State; State;
{hosts, _} -> {hosts, _} ->
State; State;
{Opt, Val} -> {Opt, Val} when Action == set ->
add_option({Opt, Host}, Val, State) 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. end.
add_option(Opt, Val, State) when is_atom(Opt) -> set_option(Opt, Val, State) ->
add_option({Opt, global}, Val, State); State#state{opts = [#local_config{key = Opt, value = Val} |
add_option(Opt, Val, State) -> State#state.opts]}.
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.
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) -> set_opts(State) ->
Opts = lists:reverse(State#state.opts), Opts = State#state.opts,
F = fun() -> 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) -> lists:foreach(fun(R) ->
mnesia:write(R) mnesia:write(R)
end, Opts) end, Opts)
@ -565,11 +615,22 @@ get_option(Opt, F) ->
get_option(Opt, F, Default) when is_atom(Opt) -> get_option(Opt, F, Default) when is_atom(Opt) ->
get_option({Opt, global}, F, Default); get_option({Opt, global}, F, Default);
get_option(Opt, 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 case ets:lookup(local_config, Opt) of
[#local_config{value = Val}] -> [#local_config{value = Val}] ->
prepare_opt_val(Opt, Val, F, Default); 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. end.
-spec get_vh_by_auth_method(atom()) -> [binary()]. -spec get_vh_by_auth_method(atom()) -> [binary()].
@ -632,14 +693,14 @@ replace_modules(Modules) ->
emit_deprecation_warning(Module, NewModule, DBType), emit_deprecation_warning(Module, NewModule, DBType),
NewOpts = [{db_type, DBType} | NewOpts = [{db_type, DBType} |
lists:keydelete(db_type, 1, Opts)], lists:keydelete(db_type, 1, Opts)],
{NewModule, NewOpts}; {NewModule, transform_module_options(Module, NewOpts)};
NewModule -> NewModule ->
if Module /= NewModule -> if Module /= NewModule ->
emit_deprecation_warning(Module, NewModule); emit_deprecation_warning(Module, NewModule);
true -> true ->
ok ok
end, end,
{NewModule, Opts} {NewModule, transform_module_options(Module, Opts)}
end end
end, Modules). end, Modules).
@ -695,6 +756,142 @@ format_term(S) when is_list(S), S /= [] ->
format_term(T) -> format_term(T) ->
io_lib:format("~p", [binary_to_strings(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(), -spec convert_table_to_binary(atom(), [atom()], atom(),
fun(), fun()) -> ok. fun(), fun()) -> ok.

View File

@ -237,7 +237,7 @@ process2(Args, Auth, AccessCommands) ->
end. end.
get_accesscommands() -> 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, []). fun(V) when is_list(V) -> V end, []).
%%----------------------------- %%-----------------------------

View File

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

View File

@ -30,7 +30,8 @@
%% External exports %% External exports
-export([start/2, start_link/2, become_controller/1, -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 %% Callbacks
-export([init/2]). -export([init/2]).
@ -91,7 +92,7 @@ start_link(SockData, Opts) ->
[SockData, Opts])}. [SockData, Opts])}.
init({SockMod, Socket}, Opts) -> init({SockMod, Socket}, Opts) ->
TLSEnabled = lists:member(tls, Opts), TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts1 = lists:filter(fun ({certfile, _}) -> true; TLSOpts1 = lists:filter(fun ({certfile, _}) -> true;
(_) -> false (_) -> false
end, end,
@ -133,12 +134,13 @@ init({SockMod, Socket}, Opts) ->
true -> [{[<<"http-poll">>], ejabberd_http_poll}]; true -> [{[<<"http-poll">>], ejabberd_http_poll}];
false -> [] false -> []
end, end,
DefinedHandlers = case lists:keysearch(request_handlers, DefinedHandlers = gen_mod:get_opt(
1, Opts) request_handlers, Opts,
of fun(Hs) ->
{value, {request_handlers, H}} -> H; [{str:tokens(
false -> [] iolist_to_binary(Path), <<"/">>),
end, Mod} || {Path, Mod} <- Hs]
end, []),
RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++ RequestHandlers = DefinedHandlers ++ Captcha ++ Register ++
Admin ++ Bind ++ Poll, Admin ++ Bind ++ Poll,
?DEBUG("S: ~p~n", [RequestHandlers]), ?DEBUG("S: ~p~n", [RequestHandlers]),
@ -484,7 +486,7 @@ analyze_ip_xff(IP, [], _Host) -> IP;
analyze_ip_xff({IPLast, Port}, XFF, Host) -> analyze_ip_xff({IPLast, Port}, XFF, Host) ->
[ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++ [ClientIP | ProxiesIPs] = str:tokens(XFF, <<", ">>) ++
[jlib:ip_to_list(IPLast)], [jlib:ip_to_list(IPLast)],
TrustedProxies = ejabberd_config:get_local_option( TrustedProxies = ejabberd_config:get_option(
{trusted_proxies, Host}, {trusted_proxies, Host},
fun(TPs) -> fun(TPs) ->
[iolist_to_binary(TP) || TP <- TPs] [iolist_to_binary(TP) || TP <- TPs]
@ -834,3 +836,25 @@ normalize_path([_Parent, <<"..">>|Path], Norm) ->
normalize_path(Path, Norm); normalize_path(Path, Norm);
normalize_path([Part | Path], Norm) -> normalize_path([Part | Path], Norm) ->
normalize_path(Path, [Part|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]) -> init([ID, Key, IP]) ->
?INFO_MSG("started: ~p", [{ID, Key, IP}]), ?INFO_MSG("started: ~p", [{ID, Key, IP}]),
Opts = ejabberd_c2s_config:get_c2s_limits(), Opts = ejabberd_c2s_config:get_c2s_limits(),
HTTPPollTimeout = ejabberd_config:get_local_option( HTTPPollTimeout = ejabberd_config:get_option(
{http_poll_timeout, ?MYNAME}, {http_poll_timeout, ?MYNAME},
fun(I) when is_integer(I), I>0 -> I end, fun(I) when is_integer(I), I>0 -> I end,
?HTTP_POLL_TIMEOUT) * 1000, ?HTTP_POLL_TIMEOUT) * 1000,

View File

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

View File

@ -84,7 +84,12 @@ get_closest_node(Name) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
init([]) -> init([]) ->
{FE, BE} = {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 -> frontend ->
{true, false}; {true, false};
backend -> backend ->

View File

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

View File

@ -30,11 +30,15 @@
%% API %% API
-export([start_link/1, init/1, add_pid/2, remove_pid/2, -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("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
-define(PGSQL_PORT, 5432).
-define(MYSQL_PORT, 3306).
-define(DEFAULT_POOL_SIZE, 10). -define(DEFAULT_POOL_SIZE, 10).
-define(DEFAULT_ODBC_START_INTERVAL, 30). -define(DEFAULT_ODBC_START_INTERVAL, 30).
@ -56,11 +60,11 @@ start_link(Host) ->
?MODULE, [Host]). ?MODULE, [Host]).
init([Host]) -> init([Host]) ->
PoolSize = ejabberd_config:get_local_option( PoolSize = ejabberd_config:get_option(
{odbc_pool_size, Host}, {odbc_pool_size, Host},
fun(I) when is_integer(I), I>0 -> I end, fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_POOL_SIZE), ?DEFAULT_POOL_SIZE),
StartInterval = ejabberd_config:get_local_option( StartInterval = ejabberd_config:get_option(
{odbc_start_interval, Host}, {odbc_start_interval, Host},
fun(I) when is_integer(I), I>0 -> I end, fun(I) when is_integer(I), I>0 -> I end,
?DEFAULT_ODBC_START_INTERVAL), ?DEFAULT_ODBC_START_INTERVAL),
@ -93,3 +97,20 @@ remove_pid(Host, Pid) ->
mnesia:delete_object(#sql_pool{host = Host, pid = Pid}) mnesia:delete_object(#sql_pool{host = Host, pid = Pid})
end, end,
mnesia:ets(F). 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) start_odbc(Host, App)
end. 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) -> needs_odbc(Host) ->
LHost = jlib:nameprep(Host), LHost = jlib:nameprep(Host),
case ejabberd_config:get_local_option( case ejabberd_config:get_option({odbc_type, LHost},
{odbc_server, LHost}, fun(Res) -> Res end) of fun(mysql) -> mysql;
{mysql, _, _, _, _} -> {true, p1_mysql}; (pgsql) -> pgsql;
{pgsql, _, _, _, _} -> {true, p1_pgsql}; (odbc) -> odbc
{mysql, _, _, _, _, _} -> {true, p1_mysql}; end, undefined) of
{pgsql, _, _, _, _, _} -> {true, p1_pgsql}; mysql -> {true, p1_mysql};
S -> pgsql -> {true, p1_pgsql};
case catch iolist_to_binary(S) of odbc -> {true, odbc};
{'EXIT', _} -> false; undefined -> false
_ -> true
end
end. end.

View File

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

View File

@ -45,7 +45,7 @@
handle_info/2, terminate/2, code_change/3]). handle_info/2, terminate/2, code_change/3]).
%% ejabberd API %% ejabberd API
-export([get_info_s2s_connections/1]). -export([get_info_s2s_connections/1, transform_options/1]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -461,12 +461,12 @@ needed_connections_number(Ls, MaxS2SConnectionsNumber,
%% -------------------------------------------------------------------- %% --------------------------------------------------------------------
is_service(From, To) -> is_service(From, To) ->
LFromDomain = From#jid.lserver, LFromDomain = From#jid.lserver,
case ejabberd_config:get_local_option( case ejabberd_config:get_option(
{route_subdomains, LFromDomain}, {route_subdomains, LFromDomain},
fun(s2s) -> s2s end) of fun(s2s) -> s2s; (local) -> local end, local) of
s2s -> % bypass RFC 3920 10.3 s2s -> % bypass RFC 3920 10.3
false; false;
undefined -> local ->
Hosts = (?MYHOSTS), Hosts = (?MYHOSTS),
P = fun (ParentDomain) -> P = fun (ParentDomain) ->
lists:member(ParentDomain, Hosts) lists:member(ParentDomain, Hosts)
@ -548,34 +548,50 @@ allow_host2(MyServer, S2SHost) ->
end. end.
allow_host1(MyHost, S2SHost) -> allow_host1(MyHost, S2SHost) ->
case ejabberd_config:get_local_option( Rule = ejabberd_config:get_option(
{{s2s_host, S2SHost}, MyHost}, s2s_access,
fun(deny) -> deny; (allow) -> allow end) fun(A) when is_atom(A) -> A end,
of all),
deny -> false; JID = jlib:make_jid(<<"">>, S2SHost, <<"">>),
allow -> true; case acl:match_rule(MyHost, Rule, JID) of
undefined -> deny -> false;
case ejabberd_config:get_local_option( allow ->
{s2s_default_policy, MyHost}, case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
fun(deny) -> deny; (allow) -> allow end) allow, [MyHost, S2SHost]) of
of deny -> false;
deny -> false; allow -> true;
_ -> _ -> true
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost, end
allow, [MyHost, S2SHost])
of
deny -> false;
allow -> true;
_ -> true
end
end
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. %% Get information about S2S connections of the specified type.
%% @spec (Type) -> [Info] %% @spec (Type) -> [Info]
%% where Type = in | out %% where Type = in | out
%% Info = [{InfoName::atom(), InfoValue::any()}] %% Info = [{InfoName::atom(), InfoValue::any()}]
get_info_s2s_connections(Type) -> get_info_s2s_connections(Type) ->
ChildType = case Type of ChildType = case Type of
in -> ejabberd_s2s_in_sup; in -> ejabberd_s2s_in_sup;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,7 +33,7 @@
%% API %% API
-export([start_link/3, add_iq_handler/6, -export([start_link/3, add_iq_handler/6,
remove_iq_handler/3, stop_iq_handler/3, handle/7, 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 %% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, -export([init/1, handle_call/3, handle_cast/2,
@ -46,7 +46,7 @@
-record(state, {host, module, function}). -record(state, {host, module, function}).
-type component() :: ejabberd_sm | ejabberd_local. -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. -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]), [Host, Module, Function]),
Component:register_iq_handler(Host, NS, Module, Component:register_iq_handler(Host, NS, Module,
Function, {one_queue, Pid}); Function, {one_queue, Pid});
{queues, N} -> N when is_integer(N) ->
Pids = lists:map(fun (_) -> Pids = lists:map(fun (_) ->
{ok, Pid} = {ok, Pid} =
supervisor:start_child(ejabberd_iq_sup, 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(no_queue) -> no_queue;
check_type(one_queue) -> one_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. 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 %% gen_server callbacks
%%==================================================================== %%====================================================================

View File

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

View File

@ -3,7 +3,7 @@
%%% Author : Eric Cestari <ecestari@process-one.net> %%% Author : Eric Cestari <ecestari@process-one.net>
%%% Purpose : Message Carbons XEP-0280 0.8 %%% Purpose : Message Carbons XEP-0280 0.8
%%% Created : 5 May 2008 by Mickael Remond <mremond@process-one.net> %%% 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, []} %%% {mod_carboncopy, []}
%%% %%%
%%% %%%

View File

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

View File

@ -36,7 +36,8 @@
process_sm_iq_items/3, process_sm_iq_info/3, process_sm_iq_items/3, process_sm_iq_info/3,
get_sm_identity/5, get_sm_features/5, get_sm_items/5, get_sm_identity/5, get_sm_features/5, get_sm_items/5,
get_info/5, register_feature/2, unregister_feature/2, 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("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -440,6 +441,22 @@ get_user_resources(User, Server) ->
end, end,
lists:sort(Rs)). 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 %%% 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_info(Acc, _, _, _Node, _) -> Acc.
get_fields_xml(Host, Module) -> get_fields_xml(Host, Module) ->
Fields = gen_mod:get_module_opt(Host, ?MODULE, server_info, Fields = gen_mod:get_module_opt(
fun(L) when is_list(L) -> L end, 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, _, _}) -> Fields_good = lists:filter(fun ({Modules, _, _}) ->
case Modules of case Modules of
all -> true; all -> true;

View File

@ -32,7 +32,8 @@
-export([start/2, stop/1, process_local_iq/3, export/1, -export([start/2, stop/1, process_local_iq/3, export/1,
process_sm_iq/3, on_presence_update/4, import/1, import/3, 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("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -101,18 +102,13 @@ process_local_iq(_From, _To,
%% @doc Get the uptime of the ejabberd node, expressed in seconds. %% @doc Get the uptime of the ejabberd node, expressed in seconds.
%% When ejabberd is starting, ejabberd_config:start/0 stores the datetime. %% When ejabberd is starting, ejabberd_config:start/0 stores the datetime.
get_node_uptime() -> get_node_uptime() ->
case ejabberd_config:get_local_option( case ejabberd_config:get_option(
node_start, node_start,
fun({MegaSecs, Secs, MicroSecs} = Now) fun(S) when is_integer(S), S >= 0 -> S end) of
when is_integer(MegaSecs), MegaSecs >= 0,
is_integer(Secs), Secs >= 0,
is_integer(MicroSecs), MicroSecs >= 0 ->
Now
end) of
undefined -> undefined ->
trunc(element(1, erlang:statistics(wall_clock)) / 1000); trunc(element(1, erlang:statistics(wall_clock)) / 1000);
StartNow -> Now ->
now_to_seconds(now()) - now_to_seconds(StartNow) now_to_seconds(now()) - Now
end. end.
now_to_seconds({MegaSecs, Secs, _MicroSecs}) -> now_to_seconds({MegaSecs, Secs, _MicroSecs}) ->
@ -319,3 +315,13 @@ import(_LServer, mnesia, #last_activity{} = LA) ->
mnesia:dirty_write(LA); mnesia:dirty_write(LA);
import(_, _, _) -> import(_, _, _) ->
pass. 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). -behaviour(gen_mod).
%% API %% 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]). check_access_log/2, add_to_log/5]).
%% gen_server callbacks %% gen_server callbacks
@ -111,6 +111,14 @@ check_access_log(Host, From) ->
Res -> Res Res -> Res
end. end.
transform_module_options(Opts) ->
lists:map(
fun({top_link, {S1, S2}}) ->
{top_link, [{S1, S2}]};
(Opt) ->
Opt
end, Opts).
%%==================================================================== %%====================================================================
%% gen_server callbacks %% gen_server callbacks
%%==================================================================== %%====================================================================
@ -152,14 +160,14 @@ init([Host, Opts]) ->
(universal) -> universal (universal) -> universal
end, local), end, local),
Top_link = gen_mod:get_opt(top_link, Opts, Top_link = gen_mod:get_opt(top_link, Opts,
fun({S1, S2}) -> fun([{S1, S2}]) ->
{iolist_to_binary(S1), {iolist_to_binary(S1),
iolist_to_binary(S2)} iolist_to_binary(S2)}
end, {<<"/">>, <<"Home">>}), end, {<<"/">>, <<"Home">>}),
NoFollow = gen_mod:get_opt(spam_prevention, Opts, NoFollow = gen_mod:get_opt(spam_prevention, Opts,
fun(B) when is_boolean(B) -> B end, fun(B) when is_boolean(B) -> B end,
true), true),
Lang = ejabberd_config:get_local_option( Lang = ejabberd_config:get_option(
{language, Host}, {language, Host},
fun iolist_to_binary/1, fun iolist_to_binary/1,
?MYLANG), ?MYLANG),

View File

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

View File

@ -35,7 +35,7 @@
handle_cast/2, terminate/2, code_change/3]). handle_cast/2, terminate/2, code_change/3]).
%% API. %% API.
-export([start_link/2, add_listener/2, -export([start_link/2, add_listener/2, transform_module_options/1,
delete_listener/1]). delete_listener/1]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
@ -261,16 +261,15 @@ parse_options(ServerHost, Opts) ->
Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1, Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1,
<<"SOCKS5 Bytestreams">>), <<"SOCKS5 Bytestreams">>),
IP = gen_mod:get_opt(ip, Opts, IP = gen_mod:get_opt(ip, Opts,
fun(Addr) -> fun(S) ->
jlib:ip_to_list(Addr), {ok, Addr} = inet_parse:address(
binary_to_list(
iolist_to_binary(S))),
Addr Addr
end, get_my_ip()), end, get_my_ip()),
HostName = gen_mod:get_opt(hostname, Opts, HostName = gen_mod:get_opt(hostname, Opts,
fun(Addr) when is_tuple(Addr) -> fun iolist_to_binary/1,
jlib:ip_to_list(Addr); jlib:ip_to_list(IP)),
(S) ->
iolist_to_binary(S)
end, jlib:ip_to_list(IP)),
StreamAddr = [{<<"jid">>, MyHost}, StreamAddr = [{<<"jid">>, MyHost},
{<<"host">>, HostName}, {<<"host">>, HostName},
{<<"port">>, jlib:integer_to_binary(Port)}], {<<"port">>, jlib:integer_to_binary(Port)}],
@ -278,6 +277,16 @@ parse_options(ServerHost, Opts) ->
name = Name, port = Port, ip = IP, name = Name, port = Port, ip = IP,
stream_addr = StreamAddr, acl = ACL}. 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() -> get_my_ip() ->
{ok, MyHostName} = inet:gethostname(), {ok, MyHostName} = inet:gethostname(),
case inet:getaddr(MyHostName, inet) of 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. %% Obviously, we must use shaper with maximum rate.
find_maxrate(Shaper, JID1, JID2, Host) -> find_maxrate(Shaper, JID1, JID2, Host) ->
MaxRate1 = shaper:new(acl:match_rule(Host, Shaper, MaxRate1 = case acl:match_rule(Host, Shaper, JID1) of
JID1)), deny -> none;
MaxRate2 = shaper:new(acl:match_rule(Host, Shaper, R1 -> shaper:new(R1)
JID2)), end,
MaxRate2 = case acl:match_rule(Host, Shaper, JID2) of
deny -> none;
R2 -> shaper:new(R2)
end,
if MaxRate1 == none; MaxRate2 == none -> none; if MaxRate1 == none; MaxRate2 == none -> none;
true -> lists:max([MaxRate1, MaxRate2]) true -> lists:max([MaxRate1, MaxRate2])
end. end.

View File

@ -32,7 +32,8 @@
-export([start/2, stop/1, stream_feature_register/2, -export([start/2, stop/1, stream_feature_register/2,
unauthenticated_iq_register/4, try_register/5, 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("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -418,7 +419,11 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
send_welcome_message(JID) -> send_welcome_message(JID) ->
Host = JID#jid.lserver, Host = JID#jid.lserver,
case gen_mod:get_module_opt(Host, ?MODULE, welcome_message, 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(S),
iolist_to_binary(B)} iolist_to_binary(B)}
end, {<<"">>, <<"">>}) end, {<<"">>, <<"">>})
@ -483,7 +488,7 @@ check_from(JID, Server) ->
check_timeout(undefined) -> true; check_timeout(undefined) -> true;
check_timeout(Source) -> check_timeout(Source) ->
Timeout = ejabberd_config:get_local_option( Timeout = ejabberd_config:get_option(
registration_timeout, registration_timeout,
fun(TO) when is_integer(TO), TO > 0 -> fun(TO) when is_integer(TO), TO > 0 ->
TO; TO;
@ -537,7 +542,7 @@ clean_treap(Treap, CleanPriority) ->
remove_timeout(undefined) -> true; remove_timeout(undefined) -> true;
remove_timeout(Source) -> remove_timeout(Source) ->
Timeout = ejabberd_config:get_local_option( Timeout = ejabberd_config:get_option(
registration_timeout, registration_timeout,
fun(TO) when is_integer(TO), TO > 0 -> fun(TO) when is_integer(TO), TO > 0 ->
TO; TO;
@ -604,6 +609,54 @@ is_strong_password(Server, Password) ->
ejabberd_auth:entropy(Password) >= Entropy ejabberd_auth:entropy(Password) >= Entropy
end. 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 %%% ip_access management
%%% %%%
@ -614,75 +667,15 @@ may_remove_resource(From) -> From.
get_ip_access(Host) -> get_ip_access(Host) ->
gen_mod:get_module_opt(Host, ?MODULE, ip_access, gen_mod:get_module_opt(Host, ?MODULE, ip_access,
fun(IPAccess) -> fun(A) when is_atom(A) -> A end,
lists:flatmap( all).
fun({Access, S}) ->
{ok, IP, Mask} =
parse_ip_netmask(
iolist_to_binary(S)),
[{Access, IP, Mask}]
end, IPAccess)
end, []).
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) -> check_ip_access({User, Server, Resource}, IPAccess) ->
case ejabberd_sm:get_user_ip(User, Server, Resource) of case ejabberd_sm:get_user_ip(User, Server, Resource) of
{IPAddress, _PortNumber} -> {IPAddress, _PortNumber} ->
check_ip_access(IPAddress, IPAccess); check_ip_access(IPAddress, IPAccess);
_ -> true _ ->
deny
end; end;
check_ip_access({_, _, _, _} = IP, check_ip_access(IPAddress, IPAccess) ->
[{Access, {_, _, _, _} = Net, Mask} | IPAccess]) -> acl:match_rule(global, IPAccess, IPAddress).
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.

View File

@ -38,7 +38,7 @@
-export([start/2, start_link/2, stop/1, -export([start/2, start_link/2, stop/1,
get_sm_features/5, process_local_iq/3, process_sm_iq/3, 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("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -767,7 +767,7 @@ parse_options(Host, Opts) ->
VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts, VCardMap = gen_mod:get_opt(ldap_vcard_map, Opts,
fun(Ls) -> fun(Ls) ->
lists:map( lists:map(
fun({S, P, L}) -> fun({S, [{P, L}]}) ->
{iolist_to_binary(S), {iolist_to_binary(S),
iolist_to_binary(P), iolist_to_binary(P),
[iolist_to_binary(E) [iolist_to_binary(E)
@ -823,6 +823,20 @@ parse_options(Host, Opts) ->
search_reported_attrs = SearchReportedAttrs, search_reported_attrs = SearchReportedAttrs,
matches = Matches}. 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) -> check_filter(F) ->
NewF = iolist_to_binary(F), NewF = iolist_to_binary(F),
{ok, _} = eldap_filter:parse(NewF), {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 %% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file. %% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) -> complain_if_modcaps_disabled(ServerHost) ->
Modules = ejabberd_config:get_local_option({modules, ServerHost}, fun(Ms) when is_list(Ms) -> Ms end), case gen_mod:is_loaded(ServerHost, mod_caps) of
ModCaps = [mod_caps_enabled || {mod_caps, _Opts} <- Modules], false ->
case ModCaps of
[] ->
?WARNING_MSG("The PEP plugin is enabled in mod_pubsub " ?WARNING_MSG("The PEP plugin is enabled in mod_pubsub "
"of host ~p. This plugin requires mod_caps " "of host ~p. This plugin requires mod_caps "
"to be enabled, but it isn't.", "to be enabled, but it isn't.",
[ServerHost]); [ServerHost]);
_ -> ok true -> ok
end. 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 %% Check that the mod_caps module is enabled in that Jabber Host
%% If not, show a warning message in the ejabberd log file. %% If not, show a warning message in the ejabberd log file.
complain_if_modcaps_disabled(ServerHost) -> complain_if_modcaps_disabled(ServerHost) ->
Modules = ejabberd_config:get_local_option({modules, Modules = ejabberd_config:get_option({modules,
ServerHost}, ServerHost},
fun(Ms) when is_list(Ms) -> Ms end), fun(Ms) when is_list(Ms) -> Ms end),
ModCaps = [mod_caps_enabled ModCaps = [mod_caps_enabled

View File

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

View File

@ -28,7 +28,8 @@
-author('alexey@process-one.net'). -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("ejabberd.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -37,32 +38,66 @@
lastrate = 0.0 :: float(), lastrate = 0.0 :: float(),
lasttime = 0 :: integer()}). 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]). -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) -> new(Name) ->
Data = ejabberd_config:get_global_option( MaxRate = case ets:lookup(shaper, {Name, global}) of
{shaper, Name, global}, [#shaper{maxrate = R}] ->
fun({maxrate, R}) when is_integer(R), R>0 -> R;
{maxrate, R}; [] ->
(none) -> ?WARNING_MSG("Attempt to initialize an "
none "unspecified shaper '~s'", [Name]),
end, none), none
new1(Data). end,
new1(MaxRate).
-spec new1(none | {maxrate, integer()}) -> maxrate(). -spec new1(none | integer()) -> shaper().
new1(none) -> none; new1(none) -> none;
new1({maxrate, MaxRate}) -> new1(MaxRate) ->
#maxrate{maxrate = MaxRate, lastrate = 0.0, #maxrate{maxrate = MaxRate, lastrate = 0.0,
lasttime = now_to_usec(now())}. lasttime = now_to_usec(now())}.
-spec update(maxrate(), integer()) -> {maxrate(), integer()}. -spec update(shaper(), integer()) -> {shaper(), integer()}.
update(none, _Size) -> {none, 0}; update(none, _Size) -> {none, 0};
update(#maxrate{} = State, Size) -> update(#maxrate{} = State, Size) ->
@ -84,5 +119,15 @@ update(#maxrate{} = State, Size) ->
lasttime = NextNow}, lasttime = NextNow},
Pause}. 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}) -> now_to_usec({MSec, Sec, USec}) ->
(MSec * 1000000 + Sec) * 1000000 + 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), PrivDir = proplists:get_value(priv_dir, Config),
[_, _|Tail] = lists:reverse(filename:split(DataDir)), [_, _|Tail] = lists:reverse(filename:split(DataDir)),
BaseDir = filename:join(lists:reverse(Tail)), BaseDir = filename:join(lists:reverse(Tail)),
ConfigPath = filename:join([DataDir, "ejabberd.cfg"]), ConfigPath = filename:join([DataDir, "ejabberd.yml"]),
LogPath = filename:join([PrivDir, "ejabberd.log"]), LogPath = filename:join([PrivDir, "ejabberd.log"]),
SASLPath = filename:join([PrivDir, "sasl.log"]), SASLPath = filename:join([PrivDir, "sasl.log"]),
MnesiaDir = filename:join([PrivDir, "mnesia"]), MnesiaDir = filename:join([PrivDir, "mnesia"]),