Compare commits

...

557 Commits

Author SHA1 Message Date
Evgeniy Khramtsov a35b9dd9cc Close accepted socket if sockname/peername has failed
Fixes #1834
2017-07-06 14:49:21 +03:00
Paweł Chmielowski a58de70f06 Fix invalid argument in get_messages_susbset
This should fix #1818
2017-06-30 14:24:35 +02:00
Christophe Romain 800965a957 Avoid useless calls on simples subscriptions (#1313) 2017-06-29 15:24:18 +02:00
Alexey Shchepin fcf672c50e Add allow_local_users to mod_block_strangers (#1804, #1809) 2017-06-29 14:55:24 +03:00
Badlop b66e369a1d Fix Salt import from prosody SCRAMmed password (#1803) 2017-06-29 10:28:44 +02:00
Paweł Chmielowski 9dd03c873c Fix clone code in update-deps-release 2017-06-28 16:47:31 +02:00
Paweł Chmielowski e42bb47ce3 Update deps 2017-06-28 16:46:48 +02:00
Paweł Chmielowski dc7fa076d7 Fix problem with updating deps in rebar.config for non-tags 2017-06-28 16:36:59 +02:00
Paweł Chmielowski 960cf495c6 Don't use asn1rt:decode, it's not available on R20 2017-06-28 14:51:45 +02:00
Christophe Romain 0f12804a49 Quote paths to allow spaces (#1789) 2017-06-28 11:39:05 +02:00
Badlop 3c7c71cfa6 In offline export to SQL, first write all DELETE, later all INSERT (#1509) 2017-06-28 11:14:59 +02:00
Paweł Chmielowski aac190255b Update fast_tls 2017-06-27 15:02:23 +02:00
Paweł Chmielowski 85a08a087b Improve update-deps-releases deps parsing 2017-06-27 14:56:00 +02:00
Badlop 1bfb0ab39c Fix username in mam export (#1510)(thanks to themaverik) 2017-06-26 14:38:12 +02:00
Badlop 4ef1cdec12 Write validator for mod_multicast's limits option 2017-06-26 13:39:50 +02:00
Badlop 0534678028 Use YAML syntax for limits option in mod_multicast 2017-06-26 11:26:53 +02:00
Paweł Chmielowski 70606d7f1a Catch exception that may happen when sending data over websocket
This fixes #1667
2017-06-23 17:19:37 +02:00
Mickaël Rémond bb39ecbc08 More explicit bosh configuration handler
I also updated default url from to match URL suggested by XEP-0156
2017-06-23 16:47:14 +02:00
Evgeny Khramtsov 54e6e1a5fb Merge pull request #1793 from marcphilipp/bugfix/set_room_affiliation_master
Fix mod_muc_admin:set_room_affiliation
2017-06-22 18:28:12 +04:00
Evgeniy Khramtsov 5bb7a0b0db Don't let a receiver to crash if a controller is unavailable
Fixes #1796
2017-06-22 16:58:46 +03:00
Marc Philipp 976a8c9cc9 Fix mod_muc_admin:set_room_affiliation 2017-06-21 17:20:58 +02:00
Christophe Romain a095477b4c Fix outgoing_s2s_timeout description (#1684) 2017-06-21 16:30:51 +02:00
Holger Weiss 950aca380c mod_client_state: Reset state on session resume
Don't restore the previous CSI state when a stream management session is
resumed.
2017-06-21 01:05:46 +02:00
Holger Weiss 985b0a1933 mod_stream_mgmt: Add missing function specs 2017-06-21 01:00:29 +02:00
Christophe Romain a7841ed486 Improve API documentation generator 2017-06-20 14:45:57 +02:00
Christophe Romain a11e833a98 Make ext_mod api return rescode 2017-06-20 14:45:31 +02:00
Paweł Chmielowski 62ee051c6e Fix invalid {args,result}_examples in mod_muc_admin 2017-06-19 16:31:07 +02:00
Paweł Chmielowski 5424ead01d Generate better errors when not being able to generate documentation 2017-06-19 16:30:45 +02:00
Paweł Chmielowski 96d385bf82 Another tweak to md generator 2017-06-19 15:10:34 +02:00
Paweł Chmielowski 8e2258b16a Update markdown api document generator 2017-06-19 15:02:02 +02:00
Badlop f87b46f454 Fix srg_user_add/del for non-Mnesia database backends (#1780) 2017-06-15 11:05:41 +02:00
Christophe Romain 5418b37314 Add pubsub import from prosody/metronome 2017-06-15 09:56:05 +02:00
Paweł Chmielowski 6353a06a5d Catch exception from Elixir.ExUnit.Server.cases_loaded 2017-06-14 14:56:59 +02:00
Christophe Romain 58b9077b51 Fix OTP-17.5 support 2017-06-14 14:18:35 +02:00
Paweł Chmielowski 10fcfa860a Show operations to perform before asking to apply them 2017-06-14 14:05:41 +02:00
Holger Weiss 5f2dcc51ce Bump xmpp version 2017-06-14 01:05:15 +02:00
Evgeniy Khramtsov 0aa64381ff Fix IP address parsing for mod_metrics 2017-06-13 16:54:29 +03:00
Christophe Romain 6c8b037422 Fix refactor bug on wait_status 2017-06-13 12:37:27 +02:00
Christophe Romain d63ea000c7 Prepare package for 17.06-beta 2017-06-13 11:02:30 +02:00
Christophe Romain 5e148df0a9 Update esip and stun dependencies 2017-06-13 10:35:00 +02:00
Paweł Chmielowski d8f05acb67 Add script for managing updates to deps 2017-06-12 19:23:41 +02:00
Paweł Chmielowski d6f4c99243 Remove luerl from floating_deps 2017-06-12 19:23:41 +02:00
Badlop 63b6e0d381 Switch access rule delete_old_users with protect_old_users (#1772) 2017-06-09 19:18:47 +02:00
Paweł Chmielowski 8c1568ff93 Add more ipv6 loopback addresses 2017-06-09 14:38:34 +02:00
Paweł Chmielowski 7b5895c90d Allow api access on both ipv4 and 6 loopback addresses
This should fix issue #1769
2017-06-09 13:57:26 +02:00
Paweł Chmielowski 115cb23bd8 Fix elixir tests on elixir 1.4 2017-06-09 12:59:47 +02:00
Paweł Chmielowski 62806607bf Add missing , 2017-06-09 12:10:40 +02:00
Badlop b25b5c2f98 Improve export2sql explanation; remove obsolete and duplicated command 2017-06-09 12:02:49 +02:00
Christophe Romain 444c385f23 Update dependencies 2017-06-09 10:34:35 +02:00
Badlop ee8bbccb2a Fix and document push_roster_all command 2017-06-08 19:54:34 +02:00
Christophe Romain 66237abd35 Merge pull request #1766 from IRog/master
fixing exec_iex bug with proper --name arguement
2017-06-08 10:41:26 +02:00
Ivy Rogatko 0973a8d6c1 fixing iex bug with proper --name arguement 2017-06-07 21:15:17 -07:00
Christophe Romain fbead19c88 Update elixir 2017-06-07 17:09:06 +02:00
Christophe Romain baf574d6c4 Update lager p1_mysql and p1_pgsql dependencies 2017-06-07 16:56:00 +02:00
Christophe Romain e3c801f1f5 Update dependencies 2017-06-07 16:18:41 +02:00
Paweł Chmielowski f773edcb98 Override version of subdeps with version from main rebar.config 2017-06-07 16:06:28 +02:00
Christophe Romain 2a73068aac Add missing space separator on EJABBERD_OPTS 2017-06-06 15:41:48 +02:00
Evgeny Khramtsov 5971eb3da0 Merge pull request #1758 from reneklacan/fix-mix-warnings
Fix mix warnings
2017-06-04 14:25:31 +04:00
Rene Klacan 04fd5567a7 Fix mix warnings 2017-06-04 12:24:35 +02:00
Evgeny Khramtsov 4f8c132b53 Merge pull request #1759 from reneklacan/fix-version-to-be-semver
Fix version to be SemVer compatible
2017-06-04 14:18:39 +04:00
Rene Klacan a98685e0bb Fix version to be SemVer compatible 2017-06-04 03:01:51 +02:00
Christophe Romain 12733bd21b Fix EJABBERD_OPTS 2017-06-02 17:56:57 +02:00
Badlop f6767ed061 Fix rooms list in WebAdmin (#1753) 2017-06-01 19:27:41 +02:00
Christophe Romain de10a7a8ce Respect INSTALLUSER when creating spool directory 2017-06-01 17:48:44 +02:00
Christophe Romain 5081a180fa Create spool directory at start if not exists 2017-06-01 17:44:23 +02:00
Christophe Romain a576f3a6d1 Remove use of getopt to support simpler shells 2017-06-01 12:10:06 +02:00
Christophe Romain 3201f8e513 Improve ejabberdctl parameters parsing 2017-06-01 11:48:11 +02:00
Christophe Romain 92003fa4dc Minor ejabberdctl improvements 2017-06-01 08:04:11 +02:00
Christophe Romain 818d9c8c42 Merge branch 'joudinet-master' 2017-05-31 18:12:26 +02:00
Christophe Romain cbe6553baa Refactor ejabberdctl 2017-05-31 18:11:45 +02:00
Paweł Chmielowski 5d3870faa3 Add --enable-system-deps configure option 2017-05-31 11:30:34 +02:00
Christophe Romain 2d8ce266bd Add license files into lib and deps directories 2017-05-30 15:03:06 +02:00
Christophe Romain 0042f18c1f Merge branch 'master' of https://github.com/joudinet/ejabberd into joudinet-master 2017-05-30 12:37:27 +02:00
Badlop 0982a9bc3c Parse correctly presence_broadcast option in change_room_option command 2017-05-29 12:49:53 +02:00
Evgeniy Khramtsov 50327a0cfc Fix case clause
Fixes #1746
2017-05-25 13:46:17 +03:00
Holger Weiss 5802062746 Cosmetic change: Fix indentation errors 2017-05-24 17:16:16 +02:00
Evgeniy Khramtsov 69de1780a0 Introduce --enable-stun and --enable-sip configure options
STUN/TURN and SIP is not compiled by default anymore.
Use --enable-stun, --enable-sip or --enable-all to enable them.
2017-05-23 13:12:48 +03:00
Evgeniy Khramtsov 6e8895f9e9 Get rid of sql_queries.erl 2017-05-23 12:25:13 +03:00
Evgeniy Khramtsov e93762a720 Deprecate misc:encode_base64/1 and misc:decode_base64/1 2017-05-23 10:43:26 +03:00
Evgeniy Khramtsov 268065e5c4 Validate all certfiles on startup 2017-05-23 09:27:52 +03:00
Evgeniy Khramtsov d7878ef131 Implement cache for mod_announce 2017-05-22 16:14:28 +03:00
Badlop 908bedeaa6 Describe command arguments and results in mod_muc_admin 2017-05-22 12:55:32 +02:00
Evgeniy Khramtsov 504860f065 Don't leak with UDP sockets 2017-05-22 11:29:53 +03:00
Evgeniy Khramtsov 3a96d72a7f Implement cache for mod_private 2017-05-22 10:34:57 +03:00
Evgeniy Khramtsov d88e4d495f Don't store messages via a single process 2017-05-21 23:21:13 +03:00
Evgeniy Khramtsov 66a4e405e0 Improve mod_metrics
* Do not spawn a process per event
* Avoid UDP socket creation on every event
* Get rid of calls to str.erl module
* Add options 'ip' and 'port'
2017-05-21 14:24:57 +03:00
Evgeniy Khramtsov 0a77b9f43e Get rid of a workaround against old Erlang bug 2017-05-21 13:30:46 +03:00
Evgeniy Khramtsov 470669fa6b Get rid of db_type warning for mod_vcard_xupdate 2017-05-21 11:40:24 +03:00
Evgeniy Khramtsov af29fb21df Get rid of detection of modules' db_type detection
The detection sometimes leads to errorneous warnings.
We need to improve it later. For now I just remove the
detection as it doesn't fully work anyway.
2017-05-21 11:33:16 +03:00
Evgeniy Khramtsov be50d57ddd Declare ejabberd_oauth behaviour 2017-05-21 11:31:30 +03:00
Evgeniy Khramtsov 35d19b32f4 Implement cache for mod_privacy/mod_blocking 2017-05-20 22:36:32 +03:00
Paweł Chmielowski 654d907dcf export_all is not needed here 2017-05-19 17:03:41 +02:00
Paweł Chmielowski b013c29c7e Fix values put in args_examples 2017-05-19 16:56:37 +02:00
Evgeniy Khramtsov 0ed23980a6 Get rid of Mnesia transaction in get_vcard/2 2017-05-18 21:24:47 +03:00
Evgeniy Khramtsov a78862e05e The default 'iqdisc' is now 'no_queue' 2017-05-18 19:13:18 +03:00
Evgeniy Khramtsov bcb44ccb6f Implement cache for mod_last 2017-05-18 13:21:17 +03:00
Evgeniy Khramtsov 736a182544 ?SQL_UPSERT returns 'ok' on success 2017-05-18 12:10:36 +03:00
Evgeniy Khramtsov 97bb1250ba Avoid erroneous usage of ?MODULE macro 2017-05-18 12:09:28 +03:00
Evgeniy Khramtsov b0b7ac101c Fix function_clause after authentication refactoring
Fixes https://github.com/processone/ejabberd-contrib/issues/213
2017-05-18 09:51:04 +03:00
Evgeniy Khramtsov 3e35d44b0f Replace 'if_version_above' directive with 'if_have_fun' 2017-05-17 19:37:06 +03:00
Evgeniy Khramtsov 6691c59a7a Clean up database code related to mod_vcard_xupdate 2017-05-17 19:29:19 +03:00
Evgeniy Khramtsov 1391d5a304 Use disc_only_copies for oauth_token Mnesia table 2017-05-17 17:42:22 +03:00
Evgeniy Khramtsov 8f595b58a7 Increase gen_mod's supervisor shutdown time 2017-05-17 17:33:07 +03:00
Evgeniy Khramtsov 5bdc6c0822 Get rid of deprecated option 'resume_timeout' in test config 2017-05-17 17:21:59 +03:00
Evgeniy Khramtsov 1925b94131 Implement cache for mod_vcard and mod_vcard_xupdate 2017-05-17 17:13:34 +03:00
Evgeniy Khramtsov fc794b680a Add cache options to the validator 2017-05-17 16:03:41 +03:00
Evgeniy Khramtsov a71065fcda Ciphers should be a binary string 2017-05-17 15:42:18 +03:00
Evgeniy Khramtsov 7165196211 Get rid of unused variable 2017-05-17 15:24:32 +03:00
Evgeniy Khramtsov f782955c06 Implement cache for roster 2017-05-17 14:47:35 +03:00
Evgeniy Khramtsov 3f13396d73 Fix use_cache/1 callback 2017-05-15 08:58:37 +03:00
Evgeniy Khramtsov 061d5f2380 Shut up dialyzer/xref if public_key:short_name_hash/1 is not available 2017-05-13 13:11:08 +03:00
Evgeniy Khramtsov 2d17a2850c Only validate certfiles if public_key:short_name_hash/1 is available 2017-05-12 17:51:17 +03:00
Evgeniy Khramtsov cc58ce6301 Introduce Certficate Manager
The major goal is to simplify certificate management in ejabberd.
Currently it requires some effort from a user to configure certficates,
especially in the situation where a lot of virtual domains are hosted.

The task is splitted in several sub-tasks:
* Implement basic certificate validator. The validator should check all
configured certificates for existence, validity, duration and so on. The
validator should not perform any actions in the case of errors except
logging an error message. This is actually implemented by this commit.
* All certificates should be configured inside a single section (something
like 'certfiles') where ejabberd should parse them, check the full-chain,
find the corresponding private keys and, if needed, resort chains and
split the certficates into separate files for easy to use by fast_tls.
* Options like 'domain_certfile', 'c2s_certfile' or 's2s_certfile' should
probably be deprecated, since the process of matching certificates with the
corresponding virtual hosts should be done automatically and these options
only introduce configuration errors without any meaningful purpose.
2017-05-12 16:27:09 +03:00
Evgeniy Khramtsov d3c8fb7705 Check presence of some files during option validation 2017-05-12 09:34:57 +03:00
Evgeniy Khramtsov 9fe16a29e1 Gracefully process malformed passwords during password change 2017-05-11 17:15:23 +03:00
Evgeniy Khramtsov 31a3cc7b10 Gracefully process malformed passwords during registration 2017-05-11 17:09:26 +03:00
Evgeniy Khramtsov a8dc5f80d1 Add 'access_remove' ACL to mod_register 2017-05-11 16:37:01 +03:00
Evgeniy Khramtsov 81d9770d4f Update Elixir tests for using new auth API 2017-05-11 16:15:18 +03:00
Evgeniy Khramtsov cdb191bb48 Rename is_user_exists -> user_exists 2017-05-11 15:49:06 +03:00
Evgeniy Khramtsov 633b68db11 Use cache for authentication backends
The commit introduces the following API incompatibilities:

In ejabberd_auth.erl:
* dirty_get_registered_users/0 is renamed to get_users/0
* get_vh_registered_users/1 is renamed to get_users/1
* get_vh_registered_users/2 is renamed to get_users/2
* get_vh_registered_users_number/1 is renamed to count_users/1
* get_vh_registered_users_number/2 is renamed to count_users/2

In ejabberd_auth callbacks
* plain_password_required/0 is replaced by plain_password_required/1
  where the argument is a virtual host
* store_type/0 is replaced by store_type/1 where the argument is
  a virtual host
* set_password/3 is now an optional callback
* remove_user/3 callback is no longer needed
* remove_user/2 now should return `ok | {error, atom()}`
* is_user_exists/2 now must only be implemented for backends
  with `external` store type
* check_password/6 is no longer needed
* check_password/4 now must only be implemented for backends
  with `external` store type
* try_register/3 is now an optional callback and should return
  `ok | {error, atom()}`
* dirty_get_registered_users/0 is no longer needed
* get_vh_registered_users/1 is no longer needed
* get_vh_registered_users/2 is renamed to get_users/2
* get_vh_registered_users_number/1 is no longer needed
* get_vh_registered_users_number/2 is renamed to count_users/2
* get_password_s/2 is no longer needed
* get_password/2 now must only be implemented for backends with
  `plain` or `scram` store type

Additionally, the commit introduces two new callbacks:
* use_cache/1 where the argument is a virtual host
* cache_nodes/1 where the argument is a virtual host

New options are also introduced: `auth_use_cache`, `auth_cache_missed`,
`auth_cache_life_time` and `auth_cache_size`.
2017-05-11 14:37:21 +03:00
Badlop e890525788 Use misc:atom_to_binary/1 instead of the deprecated jlib.erl (#1510) 2017-05-10 12:05:52 +02:00
Badlop 6b8c61b3a2 Update comment: aux.erl was renamed to misc.erl 2017-05-10 12:03:13 +02:00
Badlop 4849ac9781 Use jid:encode/1 instead of the deprecated jid:to_string/1 (#1510) 2017-05-10 11:22:15 +02:00
Lamtei W cd18d3d8a7 Fix: update sql statement, added missing delimeter for sql queries 2017-05-10 11:22:11 +02:00
Lamtei W a0908ba393 Added export function for mam module 2017-05-10 11:22:07 +02:00
Evgeniy Khramtsov 5d7a704ca5 Remove forgotten 'export_all' 2017-05-08 17:23:29 +03:00
Evgeniy Khramtsov cee90a886e Don't list 'redis_pool_size' option multiple times 2017-05-08 17:22:34 +03:00
Evgeniy Khramtsov 6b6d07745d Split some functions in smaller ones 2017-05-08 16:29:01 +03:00
Evgeniy Khramtsov bf2a2f291f State that Erlang 17.5 or higher is only supported 2017-05-08 15:10:42 +03:00
Evgeniy Khramtsov 8368a0850a Don't call gen_mod:get_opt() outside of modules 2017-05-08 14:34:35 +03:00
Evgeniy Khramtsov 01a2c9fe12 Add type specs for Module:opt_type/1 2017-05-08 12:59:28 +03:00
Evgeniy Khramtsov 6aefd24eb3 LOG_PATH macro should be of string type 2017-05-06 09:42:06 +03:00
Evgeniy Khramtsov 3241c2506b Introduce 'sql_connect_timeout' option (#1698) 2017-05-05 16:25:10 +03:00
Evgeniy Khramtsov 48d6ae1def Introduce 'sql_query_timeout' option
Fixes #1698
2017-05-05 13:20:28 +03:00
Evgeniy Khramtsov f2dc8c0442 Emit deprecation warning for SM related listening options 2017-05-05 12:31:17 +03:00
Evgeniy Khramtsov b174e2c9c6 Improve validation of second-level options 2017-05-05 11:11:17 +03:00
Evgeniy Khramtsov fb17c1b99f Make it possible to validate second-level options 2017-05-04 17:34:32 +03:00
Paweł Chmielowski e790e66f47 Fix elixir tests 2017-05-04 12:17:41 +02:00
Paweł Chmielowski c64e77a08c Catch exceptions from acl:add_list in web admin 2017-05-04 12:01:22 +02:00
Evgeniy Khramtsov cf53d834e9 Introduce 'iqdisc' global option 2017-05-04 12:24:47 +03:00
Evgeniy Khramtsov a2a4a4970e Validate module options on start_module/2 2017-05-04 09:09:10 +03:00
Badlop 31fa36003f Parse ldap_uids in mod_vcard_ldap like in eldap_utils (#319) 2017-05-03 23:32:56 +02:00
Christophe Romain cd1c41e448 Merge pull request #1697 from pipo02mix/dockerfile-17-04
Update Dockerfile to be able to build 17.04 ejabberd version
2017-05-03 09:29:23 +02:00
Evgeniy Khramtsov 54cc49bc70 Validate new options before module reloading 2017-05-01 14:01:12 +03:00
Evgeniy Khramtsov fe662c1a0a Don't forget to delete digraph 2017-05-01 10:14:00 +03:00
Evgeniy Khramtsov fddd6110e0 Don't validate an option in gen_mod:get*opt() functions
The changes are very similar to those from previous commit:
* Now there is no need to pass validating function in
  gen_mod:get_opt() and gen_mod:get_module_opt() functions,
  because the modules' configuration keeps already validated values.
* New functions gen_mod:get_opt/2 and gen_mod:get_module_opt/3 are
  introduced.
* Functions gen_mod:get_opt/4 and get_module_opt/5 are deprecated.
  If the functions are still called, the "function" argument is
  simply ignored.
* Validating callback Mod:listen_opt_type/1 is introduced to validate
  listening options at startup.
2017-04-30 19:01:47 +03:00
Evgeniy Khramtsov 2b63d07329 Merge branch 'new-option-validation' 2017-04-29 11:48:57 +03:00
Evgeniy Khramtsov b82b93f8f0 Don't validate an option in ejabberd_config:get_option() functions
The commit introduces the following changes:
* Now there is no need to pass validating function in
  ejabberd_config:get_option() functions, because the configuration
  keeps already validated values.
* New function ejabberd_config:get_option/1 is introduced
* Function ejabberd_config:get_option/3 is deprecated. If the function
  is still called, the second argument (validating function) is simply
  ignored.
* The second argument for ejabberd_config:get_option/2 is now
  a default value, not a validating function.
2017-04-29 11:39:40 +03:00
Evgeniy Khramtsov 7129aebe76 Don't re-define validation functions in multiple places 2017-04-28 13:23:32 +03:00
Paweł Chmielowski 2bcf822637 Fix elixir tests 2017-04-28 10:08:09 +02:00
Evgeniy Khramtsov 6658c0d386 Bump cache_tab version 2017-04-27 20:07:44 +03:00
Evgeniy Khramtsov 0b93cb7ece Store options using p1_options module 2017-04-27 19:44:58 +03:00
badlop b51e2aa213 Merge pull request #1702 from skuroki/patch-1
Fix typo
2017-04-27 09:58:37 +02:00
Badlop d18d99e8ec Bug requesting non-existent data with private_get command (#1690) 2017-04-26 23:14:30 +02:00
Holger Weiss 9b8364b6c8 Merge remote-tracking branch 'processone/pr/1699'
* processone/pr/1699:
  Add support for HTTP File Upload, version 0.3.0
2017-04-26 21:18:16 +02:00
KUROKI Shinsuke 959419419f Fix typo 2017-04-26 17:35:51 +09:00
Paweł Chmielowski 2988d84cfb Don't check result of jid.start 2017-04-26 09:50:49 +02:00
Badlop c0eb85ce53 Allow a room admin also to subscribe another JID 2017-04-26 01:30:12 +02:00
Holger Weiss 56a4bf8f3c mod_stream_mgmt: Fix typo in variable name 2017-04-25 22:37:27 +02:00
Holger Weiss 9cc332d6b3 mod_stream_mgmt: Fix 'if_offline' detection 2017-04-25 22:32:03 +02:00
Evgeniy Khramtsov 120682ec8b Include original 'id' and 'type' attributes in offline event 2017-04-25 17:59:26 +03:00
Paweł Chmielowski a67b3dc6a6 Don't check result of jid.start 2017-04-25 16:54:01 +02:00
Paweł Chmielowski f4c98f635b Don't check result of jid.start 2017-04-25 16:46:00 +02:00
Evgeniy Khramtsov 069bf6dec6 Make sure only jabber:x:event tag is present in offline event 2017-04-25 17:21:24 +03:00
Fernando Ripoll a59bef1afe Update Dockerfile to be able to build 17.04 ejabberd version
Because the default installation prefix has changed in the new release, it is needed to add in the configure line of Docker file the argument  --prefix=/
2017-04-25 09:35:07 +02:00
Holger Weiss d0f3696596 randoms: Keep compatibility with Erlang/OTP 17 2017-04-24 23:51:01 +02:00
Evgeniy Khramtsov c923bb5c10 Avoid changing configuration on listener deletion 2017-04-23 16:42:54 +03:00
Evgeniy Khramtsov 9a93acc62a Improve Mnesia tables creation and transformation 2017-04-23 16:37:58 +03:00
Evgeniy Khramtsov 8770fc98e1 Use round-robin algorithm when selecting worker from DB pool 2017-04-23 11:54:56 +03:00
Evgeniy Khramtsov 18433e289f Add clear_cache admin command 2017-04-22 11:33:39 +03:00
Holger Weiss 168712ebbd Add support for HTTP File Upload, version 0.3.0
Support the current XEP-0363 version in addition to the previous
revisions.
2017-04-21 18:36:53 +02:00
Paweł Chmielowski 44ae6bcc83 Fix elixir tests 2017-04-21 12:17:23 +02:00
Evgeniy Khramtsov 02790b105e Speedup Mnesia tables initialization 2017-04-21 12:27:15 +03:00
Evgeniy Khramtsov d88c08e074 Use new cache API in mod_shared_roster_ldap 2017-04-21 10:43:14 +03:00
Evgeniy Khramtsov 9937cb48fd Use new cache API in ejabberd_oauth 2017-04-21 09:02:10 +03:00
Evgeniy Khramtsov 5444475b1d Correct option validation 2017-04-20 18:55:16 +03:00
Evgeniy Khramtsov 264a40f217 Use new cache API in mod_mam 2017-04-20 18:52:16 +03:00
Evgeniy Khramtsov a26f90a346 Use new cache API in mod_caps 2017-04-20 18:18:26 +03:00
Badlop ca9d04ba6b Fix private_get command sending a proper xmlel (#1683) 2017-04-20 16:50:08 +02:00
Badlop 4e86a71ab2 When getting user rooms, filter by the serverhost as expected (#1683) 2017-04-20 16:49:32 +02:00
Holger Weiss 3682888655 mod_stream_mgmt: Preserve stanza count on timeout
If a pending stream management session times out, call
ejabberd_c2s:process_terminated/2 *before* storing the incoming stanza
count.  Without this change, the session table entry that holds the
stanza count was purged while closing the session.
2017-04-19 23:04:20 +02:00
Holger Weiss 3adf720bc1 Use #jid{} type for #muc_unsubscribe.jid 2017-04-19 22:18:23 +02:00
Badlop d7a999eaf5 Don't use jid:from_string as it's deprecated, see jid.erl line 43 2017-04-19 21:47:59 +02:00
Evgeniy Khramtsov 64333f69ea Don't try to load already loaded applications 2017-04-19 11:40:58 +03:00
Holger Weiss b8a7720986 ejabberd_c2s: Don't close session on stream resume
Don't let ejabberd_c2s close the session and unset presence if a
'c2s_terminated' callback stops hook execution, as is done in
mod_stream_mgmt:c2s_terminated/2 on resumption.

Fixes #1680.
2017-04-19 01:20:28 +02:00
Evgeniy Khramtsov 7c9415356d Function fix_from_to/2 should not crash when 'from' is undefined
Fixes #1678
2017-04-18 01:38:35 +03:00
Evgeny Khramtsov c97aade33e Merge pull request #1677 from getong/catch_lager_crash_log_not_run
lager_crash_log in some cases not run, catch it
2017-04-17 09:44:00 +04:00
getong ab751d290a lager_crash_log in some cases not run, catch it 2017-04-17 12:07:23 +08:00
Evgeniy Khramtsov f496d22074 Improve logging message 2017-04-16 23:56:12 +03:00
Evgeniy Khramtsov 86b680a3ad Move compile_exprs() to misc module 2017-04-16 20:05:46 +03:00
Evgeniy Khramtsov 78dba217bf Speedup configuration options lookup
We now avoid excessive ETS lookups; instead, we use dynamically
compiled module 'ejabberd_options' keeping the configuration options
2017-04-16 15:29:10 +03:00
Evgeniy Khramtsov 3b14b35252 Default config file should be ejabberd.yml 2017-04-16 01:26:33 +03:00
Evgeniy Khramtsov 878c762cdf Log human readable description when configuration file is not found 2017-04-16 01:22:55 +03:00
Evgeniy Khramtsov 920f2678ac Report configuration file location on startup 2017-04-16 01:02:46 +03:00
Evgeniy Khramtsov b6182e6fe8 Speedup loading of translation files
A dump of 'translations' ETS table is now stored on disc.
The table is only re-created when new/deleted/modified translation
files are detected; otherwise, the ETS table is restored from
the dump file on startup.
2017-04-16 00:29:55 +03:00
Evgeniy Khramtsov 41fe062a8d Lower log level for some messages 2017-04-15 15:47:00 +03:00
Evgeniy Khramtsov 4c5f97bb9a Add Riak as mod_proxy65 RAM backend 2017-04-15 15:38:48 +03:00
Evgeniy Khramtsov f9c24ab16d Add Riak as mod_carboncopy RAM backend 2017-04-15 14:41:14 +03:00
Evgeniy Khramtsov 72b536b52d Add Riak as BOSH RAM backend 2017-04-15 13:52:36 +03:00
Evgeniy Khramtsov 598c79ff86 Fix cleaning of Riak route table 2017-04-15 13:36:29 +03:00
Evgeniy Khramtsov da66eb5714 Add Riak as router RAM backend 2017-04-15 13:07:56 +03:00
Evgeniy Khramtsov c290b4284f Fix closing of outbound S2S connections 2017-04-15 11:15:50 +03:00
Evgeniy Khramtsov fcb978248f Add Riak as session manager RAM backend 2017-04-15 10:02:32 +03:00
Evgeniy Khramtsov 5774edfe79 Improve ejabberd_c2s:close() 2017-04-15 08:30:41 +03:00
Evgeniy Khramtsov 5c23187d2c Make sure stream trailer is sent in the very end 2017-04-14 20:56:01 +03:00
Evgeniy Khramtsov 0a7eb33772 Better process session close 2017-04-14 20:41:25 +03:00
Evgeniy Khramtsov 9de075029b Fix a typo 2017-04-14 20:40:39 +03:00
Evgeniy Khramtsov d110cbb6e2 Fix ejabberd_router:is_my_route/1 2017-04-14 20:34:00 +03:00
Evgeniy Khramtsov 5f1f126613 Don't forget to disconnect 2017-04-14 20:32:26 +03:00
Evgeniy Khramtsov e40baf0bda Use cache in front of Redis/SQL RAM backends 2017-04-14 13:57:52 +03:00
Paweł Chmielowski aa7d5df6a0 Bump xmpp dependency, it's required by previous commit 2017-04-14 09:47:25 +02:00
Badlop 177d5fec86 Allow a room admin to unsubscribe another JID 2017-04-13 22:37:39 +02:00
Holger Weiss 0c0d79fd93 Travis CI: Update MySQL package
The "mysql-server-5.6" package is no longer available.
2017-04-11 13:52:10 +02:00
Holger Weiss 87ae2d7996 mod_muc_room: Replace deprecated function call
Use jid:decode/1 instead of jlib:string_to_jid/1.
2017-04-11 13:38:33 +02:00
Christophe Romain b1acd1183f Rename aux.erl as misc.erl
Thanks Microsoft Windows to not support some filenames
2017-04-11 12:13:58 +02:00
Christophe Romain 265aa54bc2 Use p1_utils 1.0.8 2017-04-11 08:11:29 +02:00
Badlop 1e82db5655 New muc_register_nick command (thanks to Peter Marheine)(#1407) 2017-04-10 12:23:14 +02:00
Christophe Romain f2ca4cb3cd Merge pull request #1666 from weiss/fix-csi
Let CSI keep latest stanzas of each given full JID
2017-04-07 15:10:39 +02:00
Christophe Romain cf784772c9 Merge pull request #1664 from weiss/fix-routing
Fix routing of groupchat and headline messages
2017-04-07 15:10:26 +02:00
Christophe Romain 0567d528c6 Let ext_mod be aware of p1_utils includes 2017-04-07 12:51:43 +02:00
Christophe Romain 36e3f4bc2a Generate ejabberd lib dir when not available in code server (#1665)
This is the case if running ejabberd from development directory
when code:lib_dir(ejabberd) returns {error, nad_name}.
2017-04-07 12:09:43 +02:00
Christophe Romain 2a6c50832e Improve S2S examples (#1583) 2017-04-07 11:12:27 +02:00
Christophe Romain d759875db8 Add more examples on config template (#1583) 2017-04-07 11:02:11 +02:00
Christophe Romain 1510ee0b3c Merge pull request #1660 from michal800106/master
Fix order of starting supervisors.
2017-04-07 10:04:38 +02:00
Evgeniy Khramtsov 3729acc5b0 Improve logging of Redis errors 2017-04-07 09:10:33 +03:00
Holger Weiss 9fa5f37f74 mod_client_state: Remove some empty lines 2017-04-06 23:00:53 +02:00
Holger Weiss 0ddd2e0ebf mod_client_state: Queue stanzas of each full JID
Keep the latest stanzas of each given full JID, rather than dropping
them when stanzas from a different resource are received.  This change
makes sure the recipient receives the latest status of all clients of
each contact.  It also ensures the recipient will see the current list
of occupants of joined MUC rooms.
2017-04-06 22:19:00 +02:00
Holger Weiss 7827faae4b mod_client_state: Don't keep track of queue size
Use maps:size/1 rather than keeping track of the size ourselves.
2017-04-06 21:01:26 +02:00
Evgeniy Khramtsov 245fe04289 Improve type specs and return values 2017-04-06 20:56:46 +03:00
Evgeniy Khramtsov 6876a37e61 Add Redis pool support
Fixes #1624
2017-04-06 17:56:37 +03:00
Christophe Romain 00c613b351 Set default prefix to /usr/local 2017-04-06 15:35:02 +02:00
michal 81fe380de2 Fix order of starting supervisors.
ExtMod should be loaded before GenModSupervisor because ext_mod adds proper paths to ebin from modules (ejabberd-contrib).
Without this change you have to add -pa parameter with path to module's ebin.
2017-04-06 08:50:23 +02:00
Holger Weiss 179e8934cf ejabberd_sm: Fix routing of headline messages
As per RFC 6121, silently drop headline messages sent to the bare JID of
an offline user or to the full JID of an unavailable resource.
2017-04-05 21:03:13 +02:00
Holger Weiss 8bfb6fdd4e ejabberd_sm: Fix routing of groupchat messages
As per RFC 6121, don't (re)route groupchat messages sent to a bare JID
or to an unavailable resource.
2017-04-05 20:41:10 +02:00
Holger Weiss 89f81c89da ejabberd_sm: Fix typo in debug message 2017-04-05 20:23:28 +02:00
Evgeniy Khramtsov ad948d33c0 Add description to feature-not-implemented error 2017-04-05 15:19:00 +03:00
Evgeniy Khramtsov 6fa55e7c38 Set 'read_concurrency' for some ETS tables 2017-04-05 15:10:18 +03:00
Evgeniy Khramtsov 2febbe5ffb Don't misuse monotonic_time/0 2017-04-05 10:42:42 +03:00
Christophe Romain 578ecad93c Disable mix tests 2017-04-04 17:02:15 +02:00
Evgeniy Khramtsov f5b0cd1793 Don't log warning on successful ping reply 2017-04-04 17:14:24 +03:00
Evgeniy Khramtsov 3a0b4ad8da Merge branch 'master' of github.com:processone/ejabberd 2017-04-04 09:53:45 +03:00
Evgeniy Khramtsov 408f9b515e Fix c2s connection close on demand
Fixes #1652
2017-04-04 09:52:42 +03:00
Alexey Shchepin f45dc46856 Forget prepared SQL queries on database connect (#1325) 2017-04-03 16:42:41 +03:00
Christophe Romain b75780b9cd Always init pubsub_index when using mnesia 2017-04-03 12:13:20 +02:00
Alexey Shchepin 19614678e9 Change mnesia dir detection 2017-04-03 12:57:47 +03:00
Christophe Romain 55ea097bce Remove obsolete mnesia migration calls
Now that plugins directly use ejabberd_mnesia and can include their own
transform handler, we don't need pubsub_migrate anymore.

People upgrading from 2.1.1x version must upgrade to 17.01 first.
pubsub_migrate module remains to support any manual process requiring it
2017-04-03 11:37:07 +02:00
Evgeniy Khramtsov 9d9037856c Improve redis related code 2017-04-02 11:56:09 +03:00
Evgeniy Khramtsov 5087e9c2df Use ejabberd_sql:abort/1 instead of exit/1 2017-03-31 19:10:07 +03:00
Evgeniy Khramtsov 178a0a3e1b Merge branch 'master' of github.com:processone/ejabberd 2017-03-31 19:08:16 +03:00
Evgeniy Khramtsov 05ef009552 Add Redis as mod_proxy65 RAM backend 2017-03-31 19:07:56 +03:00
Alexey Shchepin 316da00345 Add ejabberd_sql:abort/1 and ejabberd_sql:restart/1 2017-03-31 17:37:24 +03:00
Evgeniy Khramtsov f449df161a Add SQL as mod_proxy65 RAM backend 2017-03-31 08:16:28 +03:00
Evgeniy Khramtsov 3e4ed83cb3 Raise bad_node instead of node_down for consistency reason 2017-03-30 17:51:37 +03:00
Evgeniy Khramtsov f5f353d90a Do not duplicate enc_pid/dec_pid functions 2017-03-30 17:44:43 +03:00
Christophe Romain bfde473c3b Add missing jlib->aux convertion 2017-03-30 14:28:55 +02:00
Christophe Romain c93bf732db Refactor pubsub's get_last_items 2017-03-30 14:26:30 +02:00
Evgeniy Khramtsov 7bcbea2108 Deprecate jlib.erl in favor of aux.erl
Since the main goal of jlib.erl is lost, all auxiliary functions
are now moved to aux.erl, and the whole jlib.erl is now deprecated.
2017-03-30 14:17:13 +03:00
Christophe Romain 997ac58329 Merge pull request #1646 from weiss/custom-headers
Add custom_headers option for ejabberd_http listeners
2017-03-30 12:47:42 +02:00
Evgeniy Khramtsov 085b61eea5 Add Redis as mod_carboncopy RAM backend 2017-03-30 11:45:09 +03:00
Evgeniy Khramtsov 31fd83b2ae Add SQL as mod_carboncopy RAM backend 2017-03-30 10:31:51 +03:00
Badlop 4b4c039fde oauth_list_tokens and oauth_revoke_token work only in Mnesia (#1644) 2017-03-29 12:41:27 +02:00
Evgeniy Khramtsov 0b3cf26406 Fix a typo 2017-03-29 13:20:15 +03:00
Evgeniy Khramtsov 12e01a5119 Add SQL as mod_muc RAM backend 2017-03-29 12:58:01 +03:00
Evgeniy Khramtsov ba6c88cb90 Add Redis as mod_bosh RAM backend 2017-03-28 21:12:26 +03:00
Evgeniy Khramtsov e5815553cb Add SQL as mod_bosh RAM backend 2017-03-28 20:33:57 +03:00
Evgeniy Khramtsov cba6e1b3ab Add Redis as router RAM backend 2017-03-28 19:34:04 +03:00
Christophe Romain 0f864d9466 Mix needs include path to p1_utils 2017-03-28 16:08:10 +02:00
Evgeniy Khramtsov 117f31125d Add SQL as router RAM backend 2017-03-28 16:31:37 +03:00
Holger Weiss 510fde58d8 mod_http_upload: Don't add "Server" header line
Administrators can add the "Server" header line using the new listener
option "custom_headers", if desired.
2017-03-28 00:03:17 +02:00
Holger Weiss 191fc1b4e8 ejabberd_http: Expand @VERSION@ in custom headers
Let ejabberd_http expand the @VERSION@ keyword to the ejabberd version
if specified in the "custom_headers" listener option.

Closes #1414.
2017-03-27 23:52:49 +02:00
Holger Weiss 41de5e78d0 ejabberd_http: Add "custom_headers" option
If the new listener option "custom_headers" is specified, include those
headers with the HTTP(S) response.

Closes #517.
2017-03-27 23:19:11 +02:00
Christophe Romain 5b6d042de2 Fix PEP issues (#1636) 2017-03-27 16:24:24 +02:00
Evgeniy Khramtsov e30d41e5f0 Merge branch 'new_queue'
Conflicts:
	rebar.config
	src/mod_muc_admin.erl
2017-03-24 13:27:56 +03:00
Evgeniy Khramtsov e1f01f0c8a Avoid PID collisions
Fixes #1470
2017-03-24 11:03:23 +03:00
Christophe Romain e56c6545fa Add inets in included_application for mix 2017-03-23 12:20:02 +01:00
Paweł Chmielowski cb0627e6b2 Expand ejabberd.yml.example by enabling mod_http_api with couple commands 2017-03-22 14:30:12 +01:00
Christophe Romain 6c0419db2b Update mix dependencies 2017-03-22 11:59:39 +01:00
Christophe Romain 232cb3dd45 Update dependencies 2017-03-22 10:06:21 +01:00
Christophe Romain 430fc8eb62 Update docker files from latest Rafael's changes 2017-03-21 18:59:12 +01:00
Holger Weiss e469b6ffb4 prosody2ejabberd: Fix offline message record type
mod_offline now expects a #message{} rather than an #xmlel{} record.
2017-03-21 18:35:07 +01:00
Holger Weiss a1068df602 prosody2ejabberd: Fix message attribute removal
Actually remove the 'stamp' and 'stamp_legacy' attributes from imported
offline messages as intended.
2017-03-21 18:23:55 +01:00
Paweł Chmielowski f819272b88 Fix crash in mod_muc_admin, we operate on integers here not lists 2017-03-21 15:36:42 +01:00
Alexey Shchepin 9fb188afbc Don't block contacts with subscription=to in mod_block_strangers (#1609) 2017-03-21 15:42:38 +03:00
Christophe Romain 70050b52ad Use item creation date in rsm order (#1516) 2017-03-21 12:45:41 +01:00
Evgeny Khramtsov 44484fa4ae Merge pull request #1626 from weiss/fix-scram-import
prosody2ejabberd: Fix SCRAM hash conversion
2017-03-21 15:44:29 +04:00
Christophe Romain 69b52196bd Replace mod_http_bind by mod_bosh in config example 2017-03-21 11:15:01 +01:00
Evgeniy Khramtsov f7cb7ef014 Remove misleading sentence about s2s dialback 2017-03-20 21:48:31 +03:00
Paweł Chmielowski b9cd5ca07f Resolve vars.config relative to to rebar.config.script
This fixes problem with missing deps in make rel - issue #1615
2017-03-20 18:28:49 +01:00
Christophe Romain 6017785e10 Fix compilation with mix (#1588) 2017-03-20 16:58:48 +01:00
Christophe Romain 186fda098c Update mix deps 2017-03-20 16:26:16 +01:00
Christophe Romain b6e1858ce6 Update xmpp and fast_tls versions 2017-03-20 15:33:55 +01:00
Evgeniy Khramtsov 7ab4f32c1a Revert "Bump OTP version to 19.3 in Travis config"
This reverts commit 7113f2b8ba.
2017-03-20 14:08:58 +03:00
Evgeniy Khramtsov 7113f2b8ba Bump OTP version to 19.3 in Travis config 2017-03-20 13:49:23 +03:00
Evgeniy Khramtsov c526c02d92 Remove webtool from erlang.plt creation 2017-03-20 13:48:17 +03:00
Evgeniy Khramtsov f3ecba0445 Use new xdata compiler API 2017-03-20 09:57:11 +03:00
Evgeniy Khramtsov 06f42bc749 Better log s2s auth failures when TLS is not available 2017-03-18 13:59:24 +03:00
Evgeniy Khramtsov 72da5bd062 Log startup time 2017-03-18 10:24:42 +03:00
Evgeny Khramtsov e56a76299c Merge pull request #1617 from edwardchow33/patch-1
Fix wrong parameter values in mod_muc_admin
2017-03-18 02:40:14 +04:00
Edward Chow c5af421cee Fixed wrong parameter values in mod_muc_admin
Corrected wrong parameter values passing to register_online_room(Room, Host, Pid) of mod_muc
2017-03-18 03:07:23 +08:00
Evgeniy Khramtsov 91245141e9 Set translation callback on startup 2017-03-17 21:35:02 +03:00
Paweł Chmielowski 2d67ff2249 Teach mod_http_fileserver ability to send 304 Not Modified 2017-03-17 11:58:40 +01:00
Holger Weiss 0ef6973457 prosody2ejabberd: Fix SCRAM hash conversion
Closes #1549.
2017-03-16 23:15:08 +01:00
Badlop 1aeaa794e1 Encode in base64 when getting scram data with import_prosody (#1549) 2017-03-15 11:42:26 +01:00
Evgeniy Khramtsov b932afb0cd Use correct pid when registering local route
This fixes #1600
2017-03-15 10:27:22 +03:00
Alexey Shchepin 9a142eb807 Update cyrsasl_oauth to internal API changes 2017-03-14 17:25:09 +03:00
Alexey Shchepin 069d28b1ed Get rid of p1_sha calls 2017-03-14 02:31:51 +03:00
Paweł Chmielowski 301b1b7a7a Fix handling of xmlrpc request without authentication structure
This is problem from issue #1602
2017-03-13 16:41:52 +01:00
Badlop 113ed66f49 In module_install copy also deps/ebin and priv files (ejabberd-contrib#200) 2017-03-13 11:26:58 +01:00
Evgeny Khramtsov a90c337297 Merge pull request #1603 from strugee/patch-1
Note how to apply s2s Access Rights in the example
2017-03-12 18:34:14 +04:00
Evgeniy Khramtsov 071c1dcb64 Return 'closed' instead of 'einval' on closed sockets 2017-03-12 08:55:54 +03:00
Alex Jordan c4ed1c2764 Note how to apply s2s Access Rights in the example 2017-03-10 23:53:01 -05:00
Evgeniy Khramtsov 4b1bdb563e Improve overloaded S2S queue processing 2017-03-10 20:21:04 +03:00
Paweł Chmielowski 0822108fc8 Teach web admin about ip acl rules 2017-03-10 14:39:47 +01:00
Evgeniy Khramtsov 02064ae12a Add support for file-based queues
It's now possible to use files as internal packet queues.
The following options are introduced:

* queue_type: the option can be set to `ram` (default) or `file`.
  The option can be set per virtual host.
* queue_dir: path to the directory where queues will be allocated.
  The default is 'queue' directory inside Mnesia directory.
  This is a global option and cannot be set per virtual host.
2017-03-10 15:12:43 +03:00
Paweł Chmielowski 782caaa678 Improve formatting of erlang terms shown in web admin 2017-03-10 10:33:16 +01:00
Badlop ee849338dd Include shared groups also when contact is is personal roster (#1585) 2017-03-09 19:21:45 +01:00
Badlop 7e2380ab0c Remove mod_pubsub from ejd2sql export, as it isn't implemented (#1584) 2017-03-08 16:23:01 +01:00
Badlop b0a950b6dd Fix handling ejabberd_sql:sql_transaction result (#1584) 2017-03-08 16:22:13 +01:00
Evgeniy Khramtsov dd11ed82d7 Report more TLS errors 2017-03-08 08:27:54 +03:00
Evgeniy Khramtsov bdc278399d Fix typo and spec 2017-03-07 22:21:44 +03:00
Evgeniy Khramtsov b71c4c0e52 Remove forgotten compile_all 2017-03-07 21:40:39 +03:00
Evgeniy Khramtsov d0a185f2d9 Report some TLS errors 2017-03-07 18:46:02 +03:00
Evgeniy Khramtsov 0aa22e5149 Don't call deprecated jid functions from the test suite 2017-03-07 18:11:28 +03:00
Evgeniy Khramtsov 8b29af629b Best Practices for Use of SASL EXTERNAL with Certificates (XEP-0178) support
It is now possible for client connections to login using PKIX certificates.
This is disabled by default, to enable it:

- either set 'tls_verify: true' and 'cafile: /path/to/CAfile'
  in the corresponding listener's section
- or set equivalent per-vhost options 'c2s_tls_verify' and 'c2s_cafile'
2017-03-07 14:20:50 +03:00
Evgeniy Khramtsov e5aac80cb4 Better handle errors in ejabberd_receiver calls 2017-03-02 16:02:44 +03:00
Evgeniy Khramtsov 4e014b4c5c Fix previous commit 2017-03-02 15:34:26 +03:00
Evgeniy Khramtsov cebdb87387 Revert "Remove relict mod_service_log"
This reverts commit 0d4e1abbd1.
However, stanzas are now encapsulated into forwarded element
(as per XEP-0297) instead of <route/> nonza.
2017-03-02 15:30:34 +03:00
Evgeniy Khramtsov 8e41bdc25e Improve reporting of unavailable SASL mechanisms 2017-03-01 15:23:22 +03:00
Evgeniy Khramtsov 28f4131d50 Resolve all addresses from SRV lookup 2017-03-01 14:37:35 +03:00
Evgeniy Khramtsov f6e2840947 External components must always provide 'to' attribute 2017-03-01 00:17:27 +03:00
Evgeniy Khramtsov c3ef56702a Add s2s work-around for gmail.com 2017-02-28 20:15:05 +03:00
Evgeniy Khramtsov 489385d565 Make sure all hooks are called with proper host in ejabberd_c2s 2017-02-28 16:47:31 +03:00
Paweł Chmielowski ce3317da7a Fix bug in api_permission parsing 2017-02-28 13:36:34 +01:00
Jerome Sautret d6a9ef5bc1 Propagate the TRANSACTION_TIMEOUT to pgsql driver (EJAB-1266) 2017-02-28 12:19:07 +01:00
Evgeniy Khramtsov ac74b7dca1 Don't crash on malformed IP addresses 2017-02-28 13:11:49 +03:00
Evgeniy Khramtsov d81b07bd5f Improve logging of outbound s2s auth failures 2017-02-28 12:13:35 +03:00
Evgeniy Khramtsov 95a8f58314 Improve logging of dialback failures 2017-02-28 10:13:09 +03:00
Evgeniy Khramtsov f3594ec881 Resend stream header before calling handle_auth_success/2 callback 2017-02-28 10:12:11 +03:00
Paweł Chmielowski 7a186e242d Fix compilation on R17 2017-02-27 20:38:59 +01:00
Paweł Chmielowski b2e16ffb12 Fix parsing of acl/access rules inside oauth sections of api_permissions
This should fix problem reported in #1568
2017-02-27 20:23:37 +01:00
Evgeniy Khramtsov ac025ee6f2 Clarify new modules usage in the example config 2017-02-27 17:20:04 +03:00
Paweł Chmielowski b1b3aba439 Fix elixir tests 2017-02-27 13:05:08 +01:00
Evgeniy Khramtsov 719b4d1183 Don't perform useless resourceprep 2017-02-27 13:58:57 +03:00
Paweł Chmielowski a098d1ec62 Update tests to ejabberd_commands changes 2017-02-27 10:45:39 +01:00
Paweł Chmielowski ac548f2e95 Update tests to cyrsasl modifications 2017-02-27 10:45:15 +01:00
Paweł Chmielowski 6808865068 Return ok from start/2 2017-02-27 10:05:35 +01:00
Evgeniy Khramtsov 7a9fa52e91 Change loglevel on configuration reload 2017-02-27 11:11:29 +03:00
Evgeniy Khramtsov d523357ba8 Invalidate access permissions on configuration reload 2017-02-27 09:55:54 +03:00
Evgeniy Khramtsov 933351ab4c Fix log message format 2017-02-26 16:27:26 +03:00
Evgeniy Khramtsov fadcc85553 Put more stuff under supervision 2017-02-26 15:10:59 +03:00
Evgeniy Khramtsov 7decd58aaa Don't fail on elements decoding 2017-02-26 11:53:41 +03:00
Evgeniy Khramtsov c1439ddd5b Get rid of jid:to_string/1 and jid:from_string/1 2017-02-26 10:07:12 +03:00
Evgeniy Khramtsov 603ec9cb19 Don't pass empty resource to jid:make() 2017-02-25 10:01:01 +03:00
Evgeniy Khramtsov 485aae8134 Don't pass 'from' and 'to' along with stanza in hooks' arguments 2017-02-24 21:25:25 +03:00
Evgeniy Khramtsov 039ac46963 Don't polute log with known content types 2017-02-24 20:57:24 +03:00
Evgeniy Khramtsov 4892b01eb4 Get rid of unused variable warning 2017-02-24 17:48:17 +03:00
Evgeniy Khramtsov 03e2b0f0bf Remove previous options when the config gets reloaded 2017-02-24 17:03:11 +03:00
Evgeniy Khramtsov 0124d292b5 Add gen_mod:is_loaded_elsewhere/2 2017-02-24 16:31:39 +03:00
Evgeniy Khramtsov b8fbac72ac Restart listeners on configuration reload 2017-02-24 15:18:10 +03:00
Paweł Chmielowski e8c0e21f71 We don't like now() 2017-02-24 12:08:57 +01:00
Paweł Chmielowski a85a953e8e Adapt get_last tests to new output 2017-02-24 12:08:57 +01:00
Paweł Chmielowski c950fc05f0 Update tests for changes in acl start code 2017-02-24 12:08:57 +01:00
Evgeniy Khramtsov 0db99ccb4b Improve config reloading support by ejabberd_auth 2017-02-24 14:06:47 +03:00
Paweł Chmielowski 6aab450c16 Make sure that addr_re is always initialized when creating http state 2017-02-24 11:30:36 +01:00
Evgeniy Khramtsov c15d230a57 Return ejabberd_sm:stop/0 back 2017-02-24 12:39:44 +03:00
Paweł Chmielowski f310d7bb12 Make host header parser work correctly with ipv6 literal addresses 2017-02-24 10:25:26 +01:00
Evgeniy Khramtsov 67d6ca9f10 Improve startup procedure 2017-02-24 12:05:47 +03:00
Evgeniy Khramtsov 5b112c86bf Fix a case clause and run c2s_filter_send on send_error/3 2017-02-24 07:57:57 +03:00
Badlop 57181c0a76 get_last now always returns tuple with UTC XEP-0082 and status (#1565) 2017-02-23 23:27:57 +01:00
Badlop 6314a96b05 Protect users from delete_old_users command using a fixed access rule (#1462) 2017-02-23 19:38:17 +01:00
Badlop 4294ba6b52 Separate list of strings with \n for srg_get_info in mod_http_api (#1500) 2017-02-23 19:23:24 +01:00
Holger Weiss 519f3db6b6 Specify "ExecReload" command in systemd unit
Now that "ejabberdctl reload_config" works the way most admins would
expect, expose the command via systemd.
2017-02-23 18:16:56 +01:00
Christophe Romain e7901f9d70 Prepare mix for 17.03 2017-02-23 18:14:29 +01:00
Christophe Romain 1030f041e3 Update dependencies 2017-02-23 18:13:10 +01:00
Holger Weiss c76253cb0a tools/hook_deps.sh: Search for escript in PATH 2017-02-23 17:38:56 +01:00
Evgeny Khramtsov 33e82de475 Merge pull request #1499 from weiss/offline-stanza-id
Include stanza ID with archived offline messages
2017-02-23 20:36:05 +04:00
Holger Weiss b475df2250 Include stanza ID with archived offline messages
Fixes #1480.
2017-02-23 16:55:35 +01:00
Christophe Romain 720741b725 Avoid orphan_item leak on affiliation/subscription removal (#1563) 2017-02-23 16:43:22 +01:00
Jerome Sautret bc9f178b6d Fix pubsub MySQL schema 2017-02-23 16:04:29 +01:00
Evgeniy Khramtsov 6cdead166b Start/stop auth modules when host is added/deleted 2017-02-23 16:19:22 +03:00
Evgeniy Khramtsov 0542c65a07 Stop all s2s connections via supervisor calls 2017-02-23 16:18:29 +03:00
Paweł Chmielowski f4081a363b Fix elixir tests 2017-02-23 09:53:20 +01:00
Evgeniy Khramtsov a3ea6e7723 Improve reload_config admin command 2017-02-23 11:14:49 +03:00
Evgeniy Khramtsov 7d68112265 Start/stop virtual hosts when reloading configuration file 2017-02-23 10:12:19 +03:00
Evgeniy Khramtsov ed34b04e9b Remove unused macro 2017-02-22 20:48:51 +03:00
Evgeniy Khramtsov 96a690f607 Merge branch 'master' of github.com:processone/ejabberd 2017-02-22 19:47:00 +03:00
Evgeniy Khramtsov 3c4057ff55 Reload modules when reloading configuration file 2017-02-22 19:46:47 +03:00
Evgeniy Khramtsov ff67860cdb Make sure all hooks are called with proper host 2017-02-22 19:45:12 +03:00
Christophe Romain 87b5e2500b Fix match of itemid on get_cached_item, fixes 14e771d8 2017-02-22 17:44:47 +01:00
Christophe Romain 56df6e7ba8 Add missing NOT NULL restrictions 2017-02-22 15:47:36 +01:00
Christophe Romain c0b346e0b8 Move archive tables into lite.sql for better comparison with other schemas 2017-02-22 15:44:03 +01:00
Evgeniy Khramtsov 635dfa2eae Re-enable "replaced" tests 2017-02-21 12:53:08 +03:00
Evgeniy Khramtsov 6ffd5ffd0c Test stream management queue overload 2017-02-21 12:38:03 +03:00
Evgeniy Khramtsov e11bcf9c43 Improve stream management tests 2017-02-21 09:19:51 +03:00
Evgeniy Khramtsov adbd174959 Rename mod_sm -> mod_stream_mgmt 2017-02-21 09:18:58 +03:00
Evgeniy Khramtsov 1c34f89c19 Merge branch 'master' of github.com:processone/ejabberd 2017-02-21 08:46:28 +03:00
Evgeniy Khramtsov bbfd089b7e Don't count resent stanzas
Thanks to Holger Weiß for an advise
2017-02-21 08:44:39 +03:00
Holger Weiss 1e679e6f84 Travis CI: Update MySQL APT repository key
The old key expired on February 16, 2017.
2017-02-20 21:17:34 +01:00
Holger Weiss 61cdee97fc ejabberd_c2s: Don't drop 'user_send_packet' result
When handling a <session/> IQ, use the stanza returned by the
'user_send_packet' hook.

Thanks to Evgeniy for spotting this.
2017-02-20 13:07:34 +01:00
Badlop 7d767fac7f Support scrammed passwords in ejabberdctl import_prosody (#1549) 2017-02-20 12:47:56 +01:00
Evgeniy Khramtsov 9426c67302 Fix s2s_dns_timeout issues 2017-02-20 10:42:16 +03:00
Evgeny Khramtsov a664d6389e Merge pull request #1555 from weiss/count-session-iq
Let ejabberd_c2s handle <session/> IQ
2017-02-20 10:21:15 +04:00
Holger Weiss 7c159e3881 Let ejabberd_c2s handle <session/> IQ
This fixes the counting of incoming stanzas for stream management.
2017-02-19 22:43:10 +01:00
Evgeniy Khramtsov 70bfc5b4a8 Get rid of non-breaking space 2017-02-18 12:13:48 +03:00
Evgeniy Khramtsov 940ca9311d Fix some dialyzer warnings 2017-02-18 09:36:27 +03:00
Evgeny Khramtsov b2de1d7438 Merge pull request #1553 from lemenkov/config_functions_deprecation
Mark local/global config functions as deprecated
2017-02-17 20:40:04 +04:00
Peter Lemenkov 1a2dd3680f Mark local/global config functions as deprecated
See discussion in PR #1548.

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2017-02-17 19:20:44 +03:00
Christophe Romain 68cc1e775c Fix compilation when included as Elixir dependency (#1526) 2017-02-17 16:26:39 +01:00
Badlop a1e8d3c3dc Commands documentation lack arguments when policy=user (#1514) 2017-02-17 12:37:42 +01:00
Evgeny Khramtsov ae25fa994c Merge pull request #1548 from lemenkov/use_get_option
Use ejabberd_config:get_option/2 instead of ejabberd_config:get_local_option/2
2017-02-16 23:34:50 +04:00
Peter Lemenkov 009a5007ff Use ejabberd_config:add_option/2 instead of ejabberd_config:add_local_option/2
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2017-02-16 20:47:47 +03:00
Peter Lemenkov cb30f7733d Use ejabberd_config:get_option/2 instead of ejabberd_config:get_local_option/2
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2017-02-16 20:41:57 +03:00
Paweł Chmielowski eec63dbefe Correct access_matches spec 2017-02-16 15:38:44 +01:00
Evgeniy Khramtsov 218eeae797 Fix some dialyzer warnings 2017-02-16 14:18:36 +03:00
Evgeniy Khramtsov 8b2d308498 Change routing API
Now 'From' and 'To' arguments must be omitted in functions
and structures related to routing.
The commit deprecates the following functions:
     ejabberd_router:route/3 in favor of ejabberd_router:route/1
     ejabberd_router:route_error/4 in favor of ejabberd_router:route_error/2
     ejabberd_local:route_iq/4 in favor of ejabberd_local:route_iq/2
     ejabberd_local:route_iq/5 in favor of ejabberd_local:route_iq/3
The format of {route, From, To, Packet} is changed in favor of {route, Packet}
2017-02-16 11:10:24 +03:00
Evgeniy Khramtsov 26a5811744 Merge branch 'master' of github.com:processone/ejabberd 2017-02-16 00:23:00 +03:00
Evgeniy Khramtsov 0d4e1abbd1 Remove relict mod_service_log 2017-02-16 00:22:48 +03:00
Paweł Chmielowski 5b019ab48c Disable undefined_function_calls xref_check
It looks like it will calling undefined function still will be catched
by xref_queries
2017-02-15 14:12:07 +01:00
Evgeniy Khramtsov f2b5153a8c Report password change in the log 2017-02-14 17:10:16 +03:00
Evgeniy Khramtsov 6fd89f5fe0 Attach IP metadata to every stanza received from stream 2017-02-14 17:09:25 +03:00
Paweł Chmielowski 0b304731c5 Use newer p1_utils 2017-02-14 15:06:00 +01:00
Paweł Chmielowski 63da351038 Fix handling of config.ctc files 2017-02-14 14:39:24 +01:00
Paweł Chmielowski cad02bb1b0 Add more check to make xref 2017-02-14 14:39:24 +01:00
Evgeniy Khramtsov f61c933a7a Only use GEN_SERVER macro where appropriate 2017-02-14 15:39:57 +03:00
Evgeniy Khramtsov 28f66ddd7c Attach modules to gen_mod's supervisor 2017-02-14 12:39:26 +03:00
Evgeny Khramtsov a1e45ab56c Merge pull request #1539 from lemenkov/use_crypto_sha
RFE: Use crypto:hash/2 function
2017-02-14 11:38:05 +04:00
Evgeniy Khramtsov f664e39374 Improve modules start/stop procedures 2017-02-14 10:25:08 +03:00
Peter Lemenkov e7733ce7d9 Use crypto:hash/2 function
Use crypto:hash/2 function instead of ones from p1_sha.

This function exists since commit
erlang/otp@208f9ad382 and also implemented
as NIF, so I believe it's safe to use it.

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2017-02-13 18:42:50 +03:00
Evgeniy Khramtsov e1ba499bd6 Check result of gen_mod:start/2 callback (#1534) 2017-02-13 11:11:41 +03:00
Evgeniy Khramtsov fd885d0818 Apply SASLprep before storing/converting passwords
Fixes #996 and #1295
2017-02-12 10:06:30 +03:00
Evgeniy Khramtsov 67c9de6461 Use p1_server behaviour in xmpp_stream layer 2017-02-08 17:16:18 +03:00
Paweł Chmielowski ca0dd09944 Accept "add_commands: admin" in commands section not only "add_commands: - admin"
This fixes issue reported in #1518, and restores compatibility with
what older version were accepting and what is documented.
2017-02-06 21:40:37 +01:00
Paweł Chmielowski b703b4f022 Don't shadow binding in match 2017-02-06 11:38:51 +01:00
Evgeniy Khramtsov f30c9d49f7 Add TLS support for external components 2017-02-06 13:30:58 +03:00
Paweł Chmielowski af5457ba09 Make sure that api_permissions always have "console commands" section
If user didn't override it in config file, default version which allows
executing all commands will be added
2017-02-03 15:22:35 +01:00
Badlop a31154c035 Set subscribers nicks when recreating room (thanks to Girdhar Sojitra)(#1495) 2017-01-31 19:18:39 +01:00
Badlop b2a2e0f135 Support non-JID lines in command create_rooms_file 2017-01-31 17:50:04 +01:00
Christophe Romain 85eb8f022c Depend on fast_xml-1.1.20 2017-01-31 11:02:23 +01:00
Christophe Romain 589bc73838 Don't warn if custom schema is not available 2017-01-31 09:53:52 +01:00
Evgeny Khramtsov 649d3b753b Merge pull request #1502 from lemenkov/ignore_output_val
No need to explicitly return ok here
2017-01-30 18:15:25 +04:00
Peter Lemenkov c377708da1 No need to explicitly return ok here
No need to explicitly return ok here. Return value will be ignored
anyway.

Signed-off-by: Peter Lemenkov <lemenkov@redhat.com>
2017-01-30 14:52:04 +01:00
Paweł Chmielowski 326e8da06d Use newer version of epam 2017-01-29 14:51:03 +01:00
Paweł Chmielowski 44a9ceac0b More changes that are required from p1_pam -> epam 2017-01-29 14:35:22 +01:00
Paweł Chmielowski 5c1168c33f Change name of pam dep from p1_pam to epam
We need to use same name as .app file or rebar complains
2017-01-29 14:26:46 +01:00
Paweł Chmielowski dd458c637e Floating deps should always be executed
This fixes problem with recognizing latest_deps configure option
2017-01-29 12:14:32 +01:00
Paweł Chmielowski 2f3f6f8b71 Improve compilation with rebar3 2017-01-26 16:45:04 +01:00
Evgeniy Khramtsov 11326692f2 Merge branch 'master' of github.com:processone/ejabberd 2017-01-26 10:59:31 +03:00
Evgeniy Khramtsov 9d144bd495 Do not drop default TLS options
Fixes #1484
2017-01-26 10:58:26 +03:00
Paweł Chmielowski a284722fd0 Adapt to coveralls api change 2017-01-24 19:16:50 +01:00
Evgeniy Khramtsov c0a89e328a Change OTP version from 19.1 to 19.2 in travis config 2017-01-24 10:39:40 +03:00
Evgeniy Khramtsov 99fd621aed Speedup features list when a lot of virtual hosts configured 2017-01-24 10:38:29 +03:00
Paweł Chmielowski 5183f7724d Fix tests 2017-01-23 20:43:35 +01:00
Evgeniy Khramtsov 0c57044c59 Make mod_disco handle features of mod_ping 2017-01-23 22:33:46 +03:00
Evgeniy Khramtsov 5e2c105396 Merge branch 'master' of github.com:processone/ejabberd 2017-01-23 21:52:35 +03:00
Evgeniy Khramtsov 0ce3a3665a Make sure only {exit, normal} is not catched when executing a hook 2017-01-23 21:52:25 +03:00
Paweł Chmielowski b0e72ece43 Adapt to new ejabberd_sm changes 2017-01-23 19:34:29 +01:00
Alexey Shchepin 8b5e6e4a13 Compatibility with R17 in mod_block_strangers 2017-01-23 19:04:22 +03:00
Alexey Shchepin 43bfa0efbc Check message subject in mod_block_strangers 2017-01-23 17:10:28 +03:00
Christophe Romain ca298c7c39 Update deps in mix.lock 2017-01-23 14:42:52 +01:00
Evgeniy Khramtsov 48d8498dbb Avoid using maps:get/2 to keep compatibility with OTP 17.5 2017-01-23 16:30:16 +03:00
Evgeniy Khramtsov 19bec62eb5 Fix calling to mod_offline:store_packet 2017-01-23 15:00:46 +03:00
Paweł Chmielowski 5e5a8bbdcf Don't use maps:take it available in R19 only 2017-01-23 12:56:08 +01:00
Paweł Chmielowski 7c2ccb2cb7 Add tool for checking which dependences need update 2017-01-23 12:24:25 +01:00
Evgeniy Khramtsov 435e5e6263 Make test suite working again 2017-01-23 13:51:05 +03:00
Evgeniy Khramtsov e564f9ae31 Make a message is not bounced if it's archived 2017-01-21 13:47:47 +03:00
Evgeniy Khramtsov 68cf45a8b9 Archive message before delivering it to offline storage (#1348) 2017-01-21 11:47:04 +03:00
Evgeniy Khramtsov 94b23482a9 Send <compressed/> in correct order 2017-01-21 10:47:55 +03:00
Evgeny Khramtsov 1e968f5487 Merge pull request #1478 from weiss/multi-host-pubsub-cache
mod_pubsub: Fix last item cache for multiple hosts
2017-01-21 11:17:06 +04:00
Holger Weiss 14e771d871 mod_pubsub: Fix last item cache for multiple hosts
Don't let the last item cache intermix PubSub items of different virtual
domains.
2017-01-21 00:14:56 +01:00
Evgeniy Khramtsov 56ef607904 Add stanza-id to every archived message (#1477) 2017-01-20 23:21:06 +03:00
Evgeniy Khramtsov 17fe272dc5 Update copyright headers in new files 2017-01-20 19:56:19 +03:00
Evgeniy Khramtsov d5d906184f Merge branch 'new_stream'
Conflicts:
	src/cyrsasl.erl
	src/ejabberd_c2s.erl
	src/ejabberd_cluster.erl
	src/ejabberd_frontend_socket.erl
	src/ejabberd_node_groups.erl
	src/ejabberd_router.erl
	src/mod_bosh.erl
	src/mod_ip_blacklist.erl
	src/mod_muc_mnesia.erl
	src/mod_offline.erl
	src/mod_proxy65_sm.erl
2017-01-20 19:35:46 +03:00
Christophe Romain 3b2c2b5c04 Prepare 17.01 for hex.pm 2017-01-20 12:19:55 +01:00
Christophe Romain 39cfee239d Use xmpp 1.1.6 2017-01-20 11:51:56 +01:00
Paweł Chmielowski 1f02567507 Make shim for mod_http_api admin_ip_access more robust 2017-01-20 10:19:09 +01:00
Christophe Romain 4f5d54f062 Try db migration only when mnesia is configured (#1458) 2017-01-20 09:26:13 +01:00
Evgeniy Khramtsov fc2b71a04e Restore muc_invite_hook (#1467) 2017-01-19 18:24:29 +03:00
Evgeniy Khramtsov 87b964a7f6 Make sure 'jabber:client' namespace is added to forwarded messages (#1474) 2017-01-19 18:03:07 +03:00
Evgeniy Khramtsov 4cf83ca3a7 Restore multiple invitations support (#1468) 2017-01-19 17:26:08 +03:00
Evgeniy Khramtsov 3d9997288d Don't forget to convert muc#roomconfig_mam 2017-01-19 16:42:04 +03:00
Evgeniy Khramtsov 527472f18c Support legacy muc#roomconfig values (#1469) 2017-01-19 11:12:27 +03:00
Christophe Romain d2b8569452 Fix typo 2017-01-18 17:11:08 +01:00
Christophe Romain 3482ee5c75 Reset table only if new def change from runtime 2017-01-18 17:02:03 +01:00
Christophe Romain 3029e84faf Improve check of mnesia schema opearations 2017-01-18 16:53:36 +01:00
Evgeniy Khramtsov 044e55b98e Fix reporting dialback failures 2017-01-18 18:26:31 +03:00
Evgeniy Khramtsov 60a09285b7 Don't attempt to resolve _jabber._tcp SRV record 2017-01-18 17:54:42 +03:00
Evgeniy Khramtsov ba47fd4649 Improve <delay/> tag insertion 2017-01-18 14:09:39 +03:00
Evgeniy Khramtsov 2de2d00f14 Cope with malformed values in 'rosterusers' SQL table (#1466) 2017-01-18 11:59:46 +03:00
Evgeniy Khramtsov 7b8c01da12 Better log bytestream termination 2017-01-17 23:06:55 +03:00
Evgeniy Khramtsov 9021ba01ac Use crypto:exor/2 instead of hand-crafted bxor 2017-01-17 22:37:44 +03:00
Evgeniy Khramtsov b8db0a8ed6 Reset XML stream before sending SASL <success/> 2017-01-17 22:06:26 +03:00
Christophe Romain 2a68591181 Remove wrong index setting 2017-01-17 16:23:45 +01:00
Christophe Romain 94ac777f93 Let ejabberd_mnesia handles copy_type 2017-01-17 15:05:14 +01:00
Christophe Romain 0ea6c1dcf6 Fix index processing (#1461) 2017-01-17 14:53:41 +01:00
Christophe Romain 2ce6d49a40 Speedup table setup, no io if EJABBERD_SCHEMA_PATH not set (#1461) 2017-01-17 14:22:12 +01:00
Evgeniy Khramtsov c7476875e6 Avoid stopping mod_offline before supervisor termination (#1464) 2017-01-17 14:31:00 +03:00
Evgeniy Khramtsov 22ee16fd9d Get rid of ejabberd_frontend_socket 2017-01-17 14:00:01 +03:00
Evgeniy Khramtsov c68ac1d5eb Improve error reporting for forbidden servers 2017-01-17 13:38:05 +03:00
Alexey Shchepin a23c76fb82 Drop only messages with <body/> in mod_block_strangers 2017-01-17 01:34:40 +03:00
Alexey Shchepin fd4f5c0996 Stop hook on message drop in mod_block_strangers 2017-01-16 18:45:26 +03:00
Alexey Shchepin b080b8f54d Use user_receive_packet hook in mod_block_strangers 2017-01-16 18:40:30 +03:00
Alexey Shchepin 5a8dea1591 Remove stub in mob_block_strangers 2017-01-16 18:21:36 +03:00
Evgeniy Khramtsov a849b384f8 Merge branch 'new_stream' of github.com:processone/ejabberd into new_stream 2017-01-16 18:15:08 +03:00
Alexey Shchepin fedfe5427c Add mod_block_strangers 2017-01-16 18:14:14 +03:00
Evgeniy Khramtsov 1176e1f096 Add script to check hook dependencies 2017-01-16 17:14:33 +03:00
Evgeniy Khramtsov 22c25e4413 Don't allow raw elements in process_iq/3 2017-01-16 16:40:11 +03:00
Evgeniy Khramtsov 557820707b Implement database backend interface for mod_proxy65 2017-01-16 15:28:11 +03:00
Evgeniy Khramtsov 0078a3b904 Correctly set gen_server's name 2017-01-16 11:43:35 +03:00
Evgeniy Khramtsov 65d352d5de Remove handle_event/1 callback 2017-01-16 11:34:49 +03:00
Evgeniy Khramtsov 64997d9961 Add mod_sm and mod_s2s_dialback to example config 2017-01-16 10:12:46 +03:00
Paweł Chmielowski ce42b6be01 Add example api_permisions: definition to config template
Also expand default config to have rule for admin oauth
2017-01-13 16:53:48 +01:00
Evgeniy Khramtsov 7606be93d5 Decode message before checking for expiration (#1458) 2017-01-13 14:20:25 +03:00
Badlop e2665c5da9 Usable size for Shared rosters members textarea (EJAB-1753) 2017-01-13 12:16:23 +01:00
Evgeniy Khramtsov 32d548d99b Fix configuration commands (#1432) 2017-01-13 13:36:28 +03:00
Evgeniy Khramtsov 25ddb6c69d Add forgotten -include_lib() 2017-01-13 13:28:55 +03:00
Evgeniy Khramtsov 0baaad30b1 Implement database backend interface for MUC, BOSH and auth_anonyous 2017-01-13 12:03:39 +03:00
Evgeniy Khramtsov 31491ebe16 Fix some corner cases while re-reading RFC6120 2017-01-13 11:35:47 +03:00
Evgeniy Khramtsov b10e10efae Ignore unexpected events 2017-01-11 16:50:11 +03:00
Evgeniy Khramtsov 02f96d0f41 Implement database backend interface for ejabberd_router 2017-01-11 16:25:43 +03:00
Evgeniy Khramtsov 2129a33077 Fix attaching ejabberd_s2s_out process to a supervisor 2017-01-11 11:09:56 +03:00
Evgeniy Khramtsov 5cfe57ece5 Add 'supervisor' listening option
If set to 'true' (this is the default), new processes spawned by
ejabberd_listener will be attached to the corresponding supervisor.
No such processes will be attached to a supervisor otherwise.
Setting this to 'false' will improve performance of high loaded
systems where new C2S/S2S processes are spawned very rapidly.
2017-01-11 10:56:04 +03:00
Evgeniy Khramtsov 03667d0c73 Add SSL support for SQL connections
Currently only PostgreSQL is supported.
This requires p1_pgsql-1.1.2 and higher.
2017-01-10 17:40:38 +03:00
Christophe Romain f2acf57412 update deps 2017-01-10 15:11:41 +01:00
Christophe Romain efccee55e3 pubsub_subscription may is not used (migration is optional) 2017-01-10 13:53:23 +01:00
Christophe Romain 6ff81946cf Fix migration of old pubsub database (#1409) 2017-01-10 12:10:11 +01:00
Evgeniy Khramtsov 08d482b064 Allow old-stype mod_vcard_ldap in the config (#1410) 2017-01-10 11:29:01 +03:00
Evgeniy Khramtsov dd5389df23 Don't forget to advertise disco features 2017-01-10 11:25:12 +03:00
Evgeniy Khramtsov e01bece552 Make stream related calls module independent 2017-01-09 22:03:42 +03:00
Badlop 3d0d9cb354 Fix typo in previous commit 2017-01-09 17:54:10 +01:00
Badlop afc7f5aa37 Simplify setting allow_subscription (#1404) 2017-01-09 15:56:25 +01:00
Evgeniy Khramtsov f14a966680 Set from/to in every routed packet 2017-01-09 17:51:08 +03:00
Evgeniy Khramtsov 6c564775c4 Remove unused mod_ip_blacklist module 2017-01-09 17:22:31 +03:00
Evgeniy Khramtsov 1e55e018e5 Adopt remaining code to support new hooks 2017-01-09 17:02:17 +03:00
Badlop 9605e2b2a4 Fix problem with get_vcard command (#1447) 2017-01-06 16:13:57 +01:00
Christophe Romain a910ab8171 Get nodes from ejabberd_cluster instead of mnesia 2017-01-03 17:21:02 +01:00
Christophe Romain 32e5781a6a Cleanup file headers 2017-01-03 15:58:52 +01:00
Badlop f5290a8e44 Specify that process_rosteritems command works only with Mnesia storage 2017-01-03 01:38:56 +01:00
Badlop 5fdd1c39fe Update copyright date automatically (#1442) 2017-01-02 21:42:06 +01:00
Paweł Chmielowski 769975f6d7 Remove mod_http_bind and migration code to mod_bosh 2017-01-02 15:53:25 +01:00
Paweł Chmielowski 1bda40dac7 Fix cyrsasl test after recent changes 2017-01-02 13:36:21 +01:00
Evgeniy Khramtsov 5ef60bf594 Correctly process errors from new cyrsasl API 2017-01-02 15:02:03 +03:00
Evgeniy Khramtsov 666608544b Improve return values in cyrsasl API 2017-01-02 14:55:06 +03:00
Evgeniy Khramtsov 3dd2a614ac Get rid of "jlib.hrl" header in some files 2017-01-02 14:45:52 +03:00
Evgeniy Khramtsov 50682b98d6 Better cope with IPv6 domains 2016-12-31 17:43:40 +03:00
Evgeniy Khramtsov cf87c5664f Reflect cyrsasl API changes in remaining code 2016-12-31 13:48:55 +03:00
Evgeniy Khramtsov 247ca872f6 Improve return values in cyrsasl API 2016-12-31 13:47:35 +03:00
Evgeniy Khramtsov e7fe4dc474 More refactoring on session management 2016-12-30 00:00:36 +03:00
Badlop c6b5dd6c4f Fix case clauses when using compression (#1431)(thanks to Evgeniy Khramtsov) 2016-12-29 15:18:42 +01:00
Evgeniy Khramtsov 309bdfbe28 Add xmpp_stream_out behaviour and rewrite s2s/SM code 2016-12-28 09:47:11 +03:00
Christophe Romain ed679279fd Cleanup file headers 2016-12-27 10:57:50 +01:00
Badlop fad7612cf1 Allow subscriber to create room, then set allow_subscription=true (#1404) 2016-12-26 21:16:17 +01:00
Holger Weiss df92d96d4f Revert "Fix 'nodetree' configuration lookups for PEP"
This reverts commit 7ef8dfb4e0.

The config/3 function copes with the PEP case.
2016-12-25 01:24:40 +01:00
Holger Weiss 7ef8dfb4e0 Fix 'nodetree' configuration lookups for PEP 2016-12-25 00:58:20 +01:00
Evgeniy Khramtsov 7f653cfe76 Rewrite ejabberd_service to use new XMPP stream API 2016-12-11 18:24:51 +03:00
Evgeniy Khramtsov 5cc8e807df Initial version of new XMPP stream behaviour (for review) 2016-12-11 15:03:37 +03:00
Johan Oudinet d364eab74b Merge remote-tracking branch 'upstream/master' 2016-11-23 11:45:13 +01:00
Johan Oudinet 404a7c3381 Remove bashismes from ejabberdctl
To avoid unecessary extra quoting, do not call commands with sh -c ''
and use the -- option from su to supply arguments.

Parse command line parameters is a bit tricky as the previous behavior
allows to mix options to ejabberdctl with unknown options given to
the next script (usually, the ctl). This is solved by relying on the
fact that for loop saves its argument, so we can flush its content
with set -- and re-add unknown options with set -- "$@" "$arg".

Finally, remove unecessary quotes in mnesia options and in the ping
command.
2016-11-21 15:25:58 +01:00
376 changed files with 29772 additions and 22377 deletions
+3 -2
View File
@@ -3,7 +3,7 @@ language: erlang
otp_release:
- 17.5
- 18.3
- 19.1
- 19.2
services:
- riak
@@ -21,7 +21,8 @@ before_install:
- sudo apt-key adv --import .travis/mysql_repo_key.asc
- sudo add-apt-repository 'deb http://repo.mysql.com/apt/ubuntu/ precise mysql-5.6'
- sudo apt-get -qq update
- sudo apt-get -qq -o Dpkg::Options::=--force-confold install mysql-server-5.6
- sudo apt-get -qq -o Dpkg::Options::=--force-confold install mysql-server
- sudo mysql_upgrade
# /END MYSQL 5.6
- pip install --user coveralls-merge
+420 -84
View File
@@ -1,5 +1,5 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.9 (SunOS)
Version: GnuPG v1.4.5 (GNU/Linux)
mQGiBD4+owwRBAC14GIfUfCyEDSIePvEW3SAFUdJBtoQHH/nJKZyQT7h9bPlUWC3
RODjQReyCITRrdwyrKUGku2FmeVGwn2u2WmDMNABLnpprWPkBdCk96+OmSLN9brZ
@@ -10,87 +10,423 @@ K2HtkrPbP72vwsEKMYhhr0eKCbtLGfls9krjJ6sBgACyP/Vb7hiPwxh6rDZ7ITnE
kYpXBACmWpP8NJTkamEnPCia2ZoOHODANwpUkP43I7jsDmgtobZX9qnrAXw+uNDI
QJEXM6FSbi0LLtZciNlYsafwAPEOMDKpMqAK6IyisNtPvaLd8lH0bPAnWqcyefep
rv0sxxqUEMcM3o7wwgfN83POkDasDbs3pjwPhxvhz6//62zQJ7Q2TXlTUUwgUmVs
ZWFzZSBFbmdpbmVlcmluZyA8bXlzcWwtYnVpbGRAb3NzLm9yYWNsZS5jb20+iGkE
ExECACkCGyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAIZAQUCUwHUZgUJGmbLywAK
CRCMcY07UHLh9V+DAKCjS1gGwgVI/eut+5L+l2v3ybl+ZgCcD7ZoA341HtoroV3U
6xRD09fUgeq0O015U1FMIFBhY2thZ2Ugc2lnbmluZyBrZXkgKHd3dy5teXNxbC5j
b20pIDxidWlsZEBteXNxbC5jb20+iG8EMBECAC8FAk53Pa0oHSBidWlsZEBteXNx
bC5jb20gd2lsbCBzdG9wIHdvcmtpbmcgc29vbgAKCRCMcY07UHLh9bU9AJ9xDK0o
xJFL9vTl9OSZC4lX0K9AzwCcCrS9cnJyz79eaRjL0s2r/CcljdyIZQQTEQIAHQUC
R6yUtAUJDTBYqAULBwoDBAMVAwIDFgIBAheAABIJEIxxjTtQcuH1B2VHUEcAAQGu
kgCffz4GUEjzXkOi71VcwgCxASTgbe0An34LPr1j9fCbrXWXO14msIADfb5piEwE
ExECAAwFAj4+o9EFgwlmALsACgkQSVDhKrJykfIk4QCfWbEeKN+3TRspe+5xKj+k
QJSammIAnjUz0xFWPlVx0f8o38qNG1bq0cU9iEwEExECAAwFAj5CggMFgwliIokA
CgkQtvXNTca6JD+WkQCgiGmnoGjMojynp5ppvMXkyUkfnykAoK79E6h8rwkSDZou
iz7nMRisH8uyiEYEEBECAAYFAj+s468ACgkQr8UjSHiDdA/2lgCg21IhIMMABTYd
p/IBiUsP/JQLiEoAnRzMywEtujQz/E9ono7H1DkebDa4iEYEEBECAAYFAj+0Q3cA
CgkQhZavqzBzTmbGwwCdFqD1frViC7WRt8GKoOS7hzNN32kAnirlbwpnT7a6NOsQ
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
AcOphrnJ
=443I
ZWFzZSBFbmdpbmVlcmluZyA8bXlzcWwtYnVpbGRAb3NzLm9yYWNsZS5jb20+iGwE
ExECACwCGyMCHgECF4ACGQEGCwkIBwMCBhUKCQgCAwUWAgMBAAUCWKcFIAUJHirJ
FAAKCRCMcY07UHLh9VcFAJ46pUyVd8BZ2r5CppMC1tmyQ3ceRgCfVPwuVsiS0VER
5WUqtAQDt+DoetCIaQQTEQIAKQIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkB
BQJTAdRmBQkaZsvLAAoJEIxxjTtQcuH1X4MAoKNLWAbCBUj96637kv6Xa/fJuX5m
AJwPtmgDfjUe2iuhXdTrFEPT19SB6ohmBBMRAgAmAhsjBgsJCAcDAgQVAggDBBYC
AwECHgECF4AFAk53PioFCRP7AhUACgkQjHGNO1By4fUmzACeJdfqgc9gWTUhgmcM
AOmG4RjwuxcAoKfM+U8yMOGELi+TRif7MtKEms6piGkEExECACkCGyMGCwkIBwMC
BBUCCAMEFgIDAQIeAQIXgAIZAQUCUZSROgUJFTchqgAKCRCMcY07UHLh9YtAAJ9X
rA/ymlmozPZn+A9ls8/uwMcTsQCfaQMNq1dNkhH2kyByc3Rx9/W2xfqJARwEEAEC
AAYFAlAS6+UACgkQ8aIC+GoXHivrWwf/dtLk/x+NC2VMDlg+vOeM0qgG1IlhXZfi
NsEisvvGaz4m8fSFRGe+1bvvfDoKRhxiGXU48RusjixzvBb6KTMuY6JpOVfz9Dj3
H9spYriHa+i6rYySXZIpOhfLiMnTy7NH2OvYCyNzSS/ciIUACIfH/2NH8zNT5CNF
1uPNRs7HsHzzz7pOlTjtTWiF4cq/Ij6Z6CNrmdj+SiMvjYN9u6sdEKGtoNtpycgD
5HGKR+I7Nd/7v56yhaUe4FpuvsNXig86K9tI6MUFS8CUyy7Hj3kVBZOUWVBM053k
nGdALSygQr50DA3jMGKVl4ZnHje2RVWRmFTr5YWoRTMxUSQPMLpBNIkBHAQQAQIA
BgUCU1B+vQAKCRAohbcD0zcc8dWwCACWXXWDXIcAWRUw+j3ph8dr9u3SItljn3wB
c7clpclKWPuLvTz7lGgzlVB0s8hH4xgkSA+zLzl6u56mpUzskFl7f1I3Ac9GGpM4
0M5vmmR9hwlD1HdZtGfbD+wkjlqgitNLoRcGdRf/+U7x09GhSS7Bf339sunIX6sM
gXSC4L32D3zDjF5icGdb0kj+3lCrRmp853dGyA3ff9yUiBkxcKNawpi7Vz3D2ddU
pOF3BP+8NKPg4P2+srKgkFbd4HidcISQCt3rY4vaTkEkLKg0nNA6U4r0YgOa7wIT
SsxFlntMMzaRg53QtK0+YkH0KuZR3GY8B7pi+tlgycyVR7mIFo7riQEcBBABCAAG
BQJWgVd0AAoJEEZu4b/gk4UKk9MH/Rnt7EccPjSJC5CrB2AU5LY2Dsr+PePI2ubP
WsEdG82qSjjGpbhIH8LSg/PzQoGHiFWMmmZWJktRT+dcgLbs3b2VwCNAwCE8jOHd
UkQhEowgomdNvHiBHKHjP4/lF68KOPiO/2mxYYkmpM7BWf3kB57DJ5CTi3/JLoN7
zF40qIs/p09ePvnwStpglbbtUn7XPO+1/Ee8VHzimABom52PkQIuxNiVUzLVn3bS
Wqrd5ecuqLk6yzjPXd2XhDHWC9Twpl68GePru6EzQtusi0m6S/sHgEXqh/IxrFZV
JlljF75JvosZq5zeulr0i6kOij+Y1p6MFffihITZ1gTmk+CLvK2JASIEEAECAAwF
Ak53QS4FAwASdQAACgkQlxC4m8pXrXwJ8Qf/be/UO9mqfoc2sMyhwMpN4/fdBWwf
LkA12FXQDOQMvwH9HsmEjnfUgYKXschZRi+DuHXe1P7l8G2aQLubhBsQf9ejKvRF
TzuWMQkdIq+6Koulxv6ofkCcv3d1xtO2W7nb5yxcpVBPrRfGFGebJvZa58DymCNg
yGtAU6AOz4veavNmI2+GIDQsY66+tYDvZ+CxwzdYu+HDV9HmrJfc6deM0mnBn7SR
jqzxJPgoTQhihTav6q/R5/2p5NvQ/H84OgS6GjosfGc2duUDzCP/kheMRKfzuyKC
OHQPtJuIj8++gfpHtEU7IDUX1So3c9n0PdpeBvclsDbpRnCNxQWU4mBot4kBIgQQ
AQIADAUCToi2GQUDABJ1AAAKCRCXELibyletfLZAB/9oRqx+NC98UQD/wlxCRytz
vi/MuPnbgQUPLHEap10tvEi33S/H/xDR/tcGofY4cjAvo5skZXXeWq93Av7PACUb
zkg0X0eSr2oL6wy66xfov72AwSuX+iUK68qtKaLqRLitM02y8aNRV/ggKvt7UMvG
mOvs5yLaYlobyvGaFC2ClfkNOt2MlVnQZCmnYBCwOktPGkExiu2yZMifcYGxQcpH
KVFG59KeF2cM2d4xYM8HJqkSGGW306LFVSyeRwG+wbttgLpD5bM/T2b3fF/J35ra
CSMLZearRTq8aygPl+XM7MM2eR946aw6jmOsgNBErbvvIdQj6LudAZj+8imcXV2K
iQEiBBABAgAMBQJOmdnRBQMAEnUAAAoJEJcQuJvKV618AvIIAIEF1ZJ+Ry7WOdKF
5oeQ/ynaYUigzN92fW/9zB8yuQlngkFJGidYMbci1tR1siziIVJFusR3ZonqAPGK
/SUta9Y6KWLhmc7c5UnEHklq/NfdMZ2WVSIykXlctqw0sbb+z1ecEd4G8u9j5ill
MO1B36rQayYAPoeXLX8dY4VyFLVGaQ00rWQBYFZrpw16ATWbWGJP332NSfCk4zZq
6kXEW07q0st3YBgAAGdNQyEeZCa4d4pBRSX6189Kjg6GDnIcaiOF6HO6PLr9fRlL
r5ObCgU+G9gEhfiVwDEV9E+7/Bq2pYZ9whhkBqWQzdpXTNTM24uaEhE01EPO5zeC
O214q6mJASIEEAECAAwFAk6rpgEFAwASdQAACgkQlxC4m8pXrXzAhwf/f9O99z16
3Y5FZVIxexyqXQ/Mct9uKHuXEVnRFYbA49dQLD4S73N+zN7gn9jFeQcBo4w8qVUV
94U/ta/VbLkdtNREyplPM4XY8YE5Wfd9bfyg3q1PbEiVjk995sBF+2+To99YYKst
gXPqjlH0jUfEyDmexOj+hsp8Rc63kvkIx36VBa4ONRYFefGAhKDMigL2YAhc1UkG
tkGTuLmlCGwIV6lviDZD3RJf5375VFnaHv7eXfwQxCwE+BxG3CURrjfxjaxMTmMP
yAG2rhDp5oTUEvqDYNbko5UxYOmrSjvF4FzXwqerElXJUkUzSh0pp7RxHB/1lCxD
s7D1F1hlgFQuNIkBIgQQAQIADAUCTrzZHAUDABJ1AAAKCRCXELibyletfMUpB/4s
07dREULIBnA1D6qr3fHsQJNZqbAuyDlvgGGLWzoyEDs+1JMFFlaa+EeLIo1386GU
2DammDC23p3IB79uQhJeD2Z1TcVg4cA64SfF/CHca5coeRSrdAiudzU/cgLGtXIP
/OaFamXgdMxAhloLFbSHPCZkyb00phVa8+xeIVDrK1HByZsNIXy/SSK8U26S2PVZ
2o14fWvKbJ1Aga8N6DuWY/D8P2mi3RAbiuZgfzkmKL5idH/wSKfnFKdTgJzssdCc
1jZEGVk5rFYcWOrJARHeP/tsnb/UxKBEsNtO7e3N2e/rLVnEykVIO066hz7xZK/V
NBSpx3k3qj4XPK41IHy2iQEiBBABAgAMBQJOzqO8BQMAEnUAAAoJEJcQuJvKV618
2twH/0IzjXLxN45nvIfEjC75a+i9ZSLlqR8lsHL4GpEScFKI0a0lT4IVAIY2RKG+
MAs2eHm0UfKuwGs5jluRZ9RqKrc61sY0XQV9/7znY9Db16ghX04JjknOKs/fPi87
rvKkB/QxJWS8qbb/erRmW+cPNjbRxTFPS5JIwFWHA16ieFEpvdAgKV6nfvJVTq1r
jPDcnIA9CJN2SmUFx9Qx3SRc6ITbam1hjFnY6sCh6AUhxLI2f1mq1xH9PqEy42Um
68prRqTyJ7Iox1g/UDDkeeUcAg7T1viTz7uXpS3Wrq4zzo4yOpaJfLDR3pI5g2Zk
SNGTMo6aySE4OABt8i1Pc1Pm6AmJASIEEAECAAwFAk7yPFYFAwASdQAACgkQlxC4
m8pXrXzXiAf9FrXe0lgcPM+tYOWMLhv5gXJi2VUBaLxpyRXm/kJcmxInKq1GCd3y
D4/FLHNu3ZcCz/uklPAbZXWI0O6ewq0LWsRtklmJjWiedH+hGyaTv95VklojRIBd
8nBaJ6M98rljMBHTFwWvjQFVf4FLRJQZqHlvjcCkq2Dd9BWJpGXvr/gpKkmMJYNK
/ftfZRcChb35NI19WRpOhj9u808OPcqKVvZBcPwFGV5cEBzmAC94J7JcD8+S8Ik8
iUJMQGGL3QcmZOBozovh86hj7KTSEBHlLXl832z89H1hLeuLbnXoGLv3zeUFSxkv
1h35LhZLqIMDQRXLuUzxGHMBpLhPyGWRJ4kBIgQQAQIADAUCTwQJFwUDABJ1AAAK
CRCXELibyletfABvB/9Cy69cjOqLGywITs3Cpg//40jmdhSAVxilJivP6J5bubFH
DJlVTx541Dv5h4hTG2BQuueQ4q1VCpSGW+rHcdhPyvmZGRz1rxdQQGh1Dv0Bod2c
3PJVSYPSrRSwCZJkJHOtVRBdjK4mkZb5aFTza+Tor9kxzj4FcXVd4KAS+hHQHYHc
Ar8tt2eOLzqdEFTULeGiSoNn+PVzvzdfhndphK+8F2jfQ2UKuc01O7k0Yn9xZVx0
OG6fE1gStzLv7C5amWLRd8+xh+MN0G8MgNglpBoExsEMMlPBYSUHa6lxpdMNMuib
rIyVncE9X8QOhImt8K0sNn/EdbuldJNGYbDLt7O4iQEiBBABAgAMBQJPFdTcBQMA
EnUAAAoJEJcQuJvKV6184owH+wZ/uLpezXnSxigeH1sig72QEXMrNd5DVHCJdig3
bo+K5YmmN710/m5z+63XKUEWpd6/knajObgckThzWftNeK1SSFQGPmoYZP9EZnSU
7L+/dSUpExbj842G5LYagrCyMGtlxRywWEmbi72TKS/JOK0jLiOdvVy+PHrZSu0D
TVQ7cJh1BmPsbz7zzxjmcI5l+7B7K7RHZHq45nDLoIabwDacj7BXvBK0Ajqz4QyJ
GQUjXC7q+88I+ptPvOXlE5nI/NbiCJOMI6d/bWN1KwYrC80fZuFaznfQFcPyUaDw
yRaun+K3kEji2wXecq+yMmLUEp01TKsUeOL50HD6hHH07W+JASIEEAECAAwFAk85
bQsFAwASdQAACgkQlxC4m8pXrXwKPQgAlkbUsTr7nkq+haOk0jKpaHWEbRMEGMrB
I3F7E+RDO6V/8y4Jtn04EYDc8GgZMBah+mOgeINq3y8jRMYV5jVtZXv2MWYFUcjM
kVBKeqhi/pGEjmUdmdt3DlPv3Z+fMTMRmAocI981iY/go8PVPg/+nrR6cFK2xxnO
R8TacikJBFeSfkkORg1tDzjjYv1B5ZIEkpplepl5ahJBBq7cpYhTdY6Yk0Sz0J8w
EdffLSaNxrRuWLrRhWzZU7p9bFzfb/7OHc21dJnB7wKv5VvtgE+jiQw9tOKaf5hc
SgRYuF6heu+B25gc5Uu88lo409mZ7oxQ6hDCn7JHvzh0rhmSN+Kid4kBIgQQAQIA
DAUCT0qQrQUDABJ1AAAKCRCXELibyletfC9UB/4o2ggJYM0CLxEpP0GU8UKOh3+/
zm1DN7Qe4kY2iCtF1plKHQaTgt5FlgRCFaiXcVv7WzGz/FnmxonR1leLl+kfRlwy
PPnoI/AWPCy/NO4Cl5KnjsSmsdDUpObwZ4KYsdilZR7ViJu2swdAIgnXBUwrlRJR
7CK4TAKrTeonRgVSrVx8Vt//8/cYj73CLq8oY/KK0iHiQrSwo44uyhdiFIAssjyX
n6/2E+w0zgvPexNSNNROHQ8pjbq+NTY6GwKIGsaej3UTRwQ7psvKXz8y7xdzmOAr
/khGvxB5gjkx02pimjeia8v66aH6rbnojJMAovNUS4EHdHnulv4rovC8Kf9iiQEi
BBABAgAMBQJPVdsaBQMAEnUAAAoJEJcQuJvKV618vVEIALFXPBzcAO1SnQarBLzy
YMVZZumPvSXKnUHAO+6kjApXPJ+qFRdUaSNshZxVKY9Zryblu4ol/fLUTt0CliSD
IxD6L4GXEm4VYYCl4lPO3bVsJnGITLFwQGHM27EmjVoTiD8Ch7kPq2EXr3dMRgzj
pdz+6aHGSUfOdLTPXufDvW83bEWGaRVuTJKw+wIrcuRqQ+ucWJgJGwcE4zeHjZad
Jx1XUm1X+BbI73uiQussyjhhQVVNU7QEdrjyuscaZ/H38wjUwNbylxDPB4I8quC1
knQ0wSHr7gKpM+E9nhiS14poRqU18u78/sJ2MUPXnQA6533IC238/LP8JgqB+BiQ
BTSJASIEEAECAAwFAk9ng3cFAwASdQAACgkQlxC4m8pXrXxQRAf/UZlkkpFJj1om
9hIRz7gS+l7YvTaKSzpo+TBcx3C7aqKJpir6TlMK9cb9HGTHo2Xp1N3FtQL72NvO
6CcJpBURbvSyb4i0hrm/YcbUC4Y3eajWhkRS3iVfGNFbc/rHthViz0r6Y5lhXX16
aVkDv5CIFWaF3BiUK0FnHrZiy4FPacUXCwEjv3uf8MpxV5oEmo8Vs1h4TL3obyUz
qrImFrEMYE/12lkE8iR5KWCaF8eFyl56HL3PPl90JMQBXzhwsFoWCPuwjfM5w6sW
Ll//zynwxtlJ9CRz9c2vK6aJ8DRu3OfBKN1iiEcNEynksDnNXErn5xXKz3p5pYdq
e9BLzUQCDYkBIgQQAQIADAUCT3inRgUDABJ1AAAKCRCXELibyletfGMKCADJ97qk
geBntQ+tZtKSFyXznAugYQmbzJld8U6eGSQnQkM40Vd62UZLdA8MjlWKS8y4A4L2
0cI14zs5tKG9Q72BxQOw5xkxlLASw1/8WeYEbw7ZA+sPG//q9v3kIkru3sv64mMA
enZtxsykexRGyCumxLjzlAcL1drWJGUYE2Kl6uzQS7jb+3PNBloQvz6nb3YRZ+Cg
Ly9D41SIK+fpnV8r4iqhu7r4LmAQ7Q1DF9aoGaYvn2+xLGyWHxJAUet4xkMNOLp6
k9RF1nbNe4I/sqeCB25CZhCTEvHdjSGTD2yJR5jfoWkwO9w8DZG1Q9WrWqki4hSB
l0cmcvO34pC1SJYziQEiBBABAgAMBQJPinQFBQMAEnUAAAoJEJcQuJvKV618CFEI
AJp5BbcV7+JBMRSvkoUcAWDoJSP2ug9zGw5FB8J90PDefKWCKs5Tjayf2TvM5ntq
5DE9SGaXbloIwa74FoZlgqlhMZ4AtY9Br+oyPJ5S844wpAmWMFc6NnEPFaHQkQ+b
dJYpRVNd9lzagJP261P3S+S9T2UeHVdOJBgWIq9Mbs4lnZzWsnZfQ4Lsz0aPqe48
tkU8hw+nflby994qIwNOlk/u+I/lJbNz5zDY91oscXTRl2jV1qBgKYwwCXxyB3j9
fyVpRl+7QnqbTWcCICVFL+uuYpP0HjdoKNqhzEguAUQQLOB9msPTXfa2hG+32ZYg
5pzI5V7GCHq0KO6u5Ctj3TGJASIEEAECAAwFAk+cQEEFAwASdQAACgkQlxC4m8pX
rXzi7AgAx8wJzNdD7UlgdKmrAK//YqH7arSssb33Xf45sVHDpUVA454DXeBrZpi+
zEuo03o5BhAuf38cwfbkV6jN1mC2N0FZfpy4v7RxHKLYr7tr6r+DRn1L1giX5ybx
CgY0fLAxkwscWUKGKABWxkz9b/beEXaO2rMt+7DBUdpAOP5FNRQ8WLRWBcMGQiaT
S4YcNDAiNkrSP8CMLQP+04hQjahxwCgBnksylciqz3Y5/MreybNnTOrdjVDsF0Oe
t0uLOiWXUZV1FfaGIdb/oBQLg+e1B74p5+q3aF8YI97qAZpPa1qiQzWIDX8LX9QX
EFyZ3mvqzGrxkFoocXleNPgWT8fRuokBIgQQAQIADAUCT64N/QUDABJ1AAAKCRCX
ELibyletfDOGCACKfcjQlSxrWlEUrYYZpoBP7DE+YdlIGumt5l6vBmxmt/5OEhqr
+dWwuoiyC5tm9CvJbuZup8anWfFzTTJmPRPsmE4z7Ek+3CNMVM2wIynsLOt1pRFK
4/5RNjRLbwI6EtoCQfpLcZJ//SB56sK4DoFKH28Ok4cplESPnoMqA3QafdSEA/FL
qvZV/iPgtTz7vjQkMgrXAIUM4fvKe3iXkAExGXtmgdXHVFoKmHrxJ2DTSvM7/19z
jGJeu2MhIKHyqEmCk6hLjxyCE5pAH59KlbAQOP1bS28xlRskBApm2wN+LOZWzC62
HhEReQ50inCGuuubK0PqUQnyYc+lUFxrFpcliQEiBBABAgAMBQJPv9lVBQMAEnUA
AAoJEJcQuJvKV618AzgH/iRFFCi4qjvoqji1fi7yNPZVOMMO2H13Ks+AfcjRtHuV
aa30u50ND7TH+XQe6yerTapLh3aAm/sNP99aTxIuwRSlyKEoDs93+XVSgRqPBgbF
/vxv0ykok3p6L9DxFO/w5cL8JrBhMZoJrEkIBFkwN8tWlcXPRFQvcdBYv3M3DTZU
qY+UHnOxHvSzsl+LJ0S9Xcd9C5bvYfabmYJvG5eRS3pj1L/y3a6yw6hvY+JtnQAk
t05TdeHMIgQH/zb8V9wxDzmE0un8LyoC2Jx5TpikQsJSejwK6b3coxVBlngku6+C
qDAimObZLw6H9xYYIK0FoJs7j5bQZEwUO7OLBgjcMOqJASIEEAECAAwFAk/Rpc8F
AwASdQAACgkQlxC4m8pXrXw49Qf/TdNbun2htQ+cRWarszOx8BLEiW/x6PVyUQpZ
nV/0qvhKzlJUjM9hQPcA0AsOjhqtCN6Cy8KXbK/TvPm9D/Nk6HWwD1PomzrJVFk2
ywGFIuTR+lluKSp7mzm5ym0wJs5cPq731Im31RUQU8ndjLrq9YOf5FVL8NqmcOAU
4E8d68BbmVCQC5MMr0901FKwKznShfpy7VYN25/BASj8dhnynBYQErqToOJB6Cnd
JhdTlbfR4SirqAYZZg3XeqGhByytEHE1x7FMWWFYhdNtsnAVhYBbWqAzBs8lF9Jd
Mhaf0VQU/4z10gVrRtXLR/ixrCi+P4cM/fOQkqd6pwqWkaXt6okBIgQQAQIADAUC
T+NxIAUDABJ1AAAKCRCXELibyletfFBBCAC6+0TUJDcNaqOxOG1KViY6KYg9NCL8
pwNK+RKNK/N1V+WGJQH7qDMwRoOn3yogrHax4xIeOWiILrvHK0O6drS1DjsymIhR
Sm2XbE/8pYmEbuJ9vHh3b/FTChmSAO7dDjSKdWD3dvaY8lSsuDDqPdTX8FzOfrXC
M22C/YPg7oUG2A5svE1b+yismP4KmVNWAepEuPZcnEMPFgop3haHg9X2+mj/btDB
Yr6p9kAgIY17nigtNTNjtI0dMLu43aIzedCYHqOlNHiB049jkJs54fMGBjF9qPtc
m0k44xyKd1/JXWMdNUmtwKsChAXJS3YOciMgIx6tqYUTndrP4I6q1rfriQEiBBAB
AgAMBQJP9T1VBQMAEnUAAAoJEJcQuJvKV618J9wIAI1lId9SMbEHF6PKXRe154lE
pap5imMU/lGTj+9ZcXmlf8o2PoMMmb3/E1k+EZUaeSBoOmjS8C2gwd5XFwRrlwAD
RlK/pG5XsL4h5wmN2fj1ororrJXvqH427PLRQK9yzdwG4+9HTBOxjoS8qZT9plyK
AJZzAydAMqyseRHgNo0vMwlgrs4ojo+GcFGQHrF3IaUjvVfUPOmIj7afopFdIZmI
GaSF0TXBzqcZ1chFv/eTBcIuIKRvlaDee5FgV7+nLH2nKOARCLvV/+8uDi2zbr83
Ip5x2tD3XuUZ0ZWxD0AQWcrLdmGb4lkxbGxvCtsaJHaLXWQ2m760RjIUcwVMEBKJ
ASIEEAECAAwFAlAGYWsFAwASdQAACgkQlxC4m8pXrXwyVAgAvuvEl6yuGkniWOlv
uHEusUv/+2GCBg6qV+IEpVtbTCCgiFjYR5GasSp1gpZ5r4BocOlbGdjdJGHTpyK8
xD1i+6qZWUYhNRg2POXUVzcNEl2hhouwPLOifcmTwAKU76TEv3L5STviL3hWgUR2
yEUZ3Ut0IGVV6uPER9jpR3qd6O3PeuFkwf+NaGTye4jioLAy3aYwtZCUXzvYmNLP
90K4y+5yauZteLmNeq26miKC/NQu4snNFClPbGRjHD1ex9KDiAMttOgN4WEq7srT
rYgtT531WY4deHpNgoPlHPuAfC0H+S6YWuMbgfcb6dV+Rrd8Ij6zM3B/PcjmsYUf
OPdPtIkBIgQQAQIADAUCUBgtfQUDABJ1AAAKCRCXELibyletfAm3CACQlw21Lfeg
d8RmIITsfnFG/sfM3MvZcjVfEAtsY3fTK9NiyU0B3yX0PU3ei37qEW+50BzqiStf
5VhNvLfbZR+yPou7o2MAP31mq3Uc6grpTV64BRIkCmRWg40WMjNI1hv7AN/0atgj
ATYQXgnEw7mfFb0XZtMTD6cmrz/A9nTPVgZDxzopOMgCCC1ZK4Vpq9FKdCYUaHpX
3sqnDf+gpVIHkTCMgWLYQOeX5Nl+fgnq6JppaQ3ySZRUDr+uFUs0uvDRvI/cn+ur
ri92wdDnczjFumKvz/cLJAg5TG2Jv1Jx3wecALsVqQ3gL7f7vr1OMaqhI5FEBqdN
29L9cZe/ZmkriQEiBBIBCgAMBQJVoNxyBYMHhh+AAAoJEEoz7NUmyPxLD1EH/2eh
7a4+8A1lPLy2L9xcNt2bifLfFP2pEjcG6ulBoMKpHvuTCgtX6ZPdHpM7uUOje/F1
CCN0IPB533U1NIoWIKndwNUJjughtoRM+caMUdYyc4kQm29Se6hMPDfyswXE5Bwe
PmoOm4xWPVOH/cVN04zyLuxdlQZNQF/nJg6PMsz4w5z+K6NGGm24NEPcc72iv+6R
Uc/ry/7v5cVu4hO5+r104mmNV5yLecQF13cHy2JlngIHXPSlxTZbeJX7qqxE7TQh
5nviSPgdk89oB5jFSx4g1efXiwtLlP7lbDlxHduomyQuH9yqmPZMbkJt9uZDc8Zz
MYsDDwlc7BIe5bGKfjqJAhwEEAECAAYFAlSanFIACgkQdzHqU52lcqLdvg//cAEP
qdN5VTKWEoDFjDS4I6t8+0KzdDWDacVFwKJ8RAo1M2SklDxnIvnzysZd2VHp5Pq7
i4LYCZo5lDkertQ6LwaQxc4X6myKY4LTA652ObFqsSfgh9kW+aJBBAyeahPQ8CDD
+Yl23+MY5wTsj4qt7KffNzy78vLbYnVnvRQ3/CboVix0SRzg0I3Oi7n3B0lihvXy
5goy9ikjzZevejMEfjfeRCgoryy9j5RvHH9PF3fJVtUtHCS4f+kxLmbQJ1XqNDVD
hlFzjz8oUzz/8YXy3im5MY7Zuq4P4wWiI7rkIFMjTYSpz/evxkVlkR74qOngT2pY
VHLyJkqwh56i0aXcjMZiuu2cymUt2LB9IsaMyWBNJjXr2doRGMAfjuR5ZaittmML
yZwix9mWVk7tkwlIxmT/IW6Np0qMhDZcWYqPRpf7+MqY3ZYMK4552b8aDMjhXrnO
OwLsz+UI4bZa1r9dguIWIt2C2b5C1RQ9AsQBPwg7h5P+HhRuFAuDKK+vgV8FRuzR
JeKkFqwB4y0Nv7BzKbFKmP+V+/krRv+/Dyz9Bz/jyAQgw02u1tPupH9BGhlRyluN
yCJFTSNj7G+OLU0/l4XNph5OOC7sy+AMZcsL/gsT/TXCizRcCuApNTPDaenACpbv
g8OoIzmNWhh4LXbAUHCKmY//hEw9PvTZA1xKHgyJAhwEEgECAAYFAlJYsKQACgkQ
oirk60MpxUV2XQ//b2/uvThkkbeOegusDC4AZfjnL/V3mgk4iYy4AC9hum0R9oNl
XDR51P1TEw9mC1btHj+7m7Iq1a5ke5wIC7ENZiilr0yPqeWgL5+LC98dz/L85hqA
wIoGeOfMhrlaVbAZEj4yQTAJDA35vZHVsQmp87il0m+fZX04OBLXBzw86EoAAZ7Q
EoH4qFcT9k1T363tvNnIm3mEvkQ5WjE1R9uchJa1g7hdlNQlVkjFmPZrJK9fl4z5
6Dto89Po4Sge48jDH0pias4HATYHsxW819nz5jZzGcxLnFRRR5iITVZi9qzsHP7N
bUh3qxuWCHS9xziXpOcSZY848xXw63Y5jDJfpzupzu/KHj6CzXYJUEEqp9MluoGb
/BCCEPzdZ0ovyxFutM/BRcc6DvE6sTDF/UES21ROqfuwtJ6qJYWX+lBIgyCJvj4o
RdbzxUleePuzqCzmwrIXtoOKW0Rlj4SCeF9yCwUMBTGW5/nCLmN4dwf1KW2RP2Eg
4ERbuUy7QnwRP5UCl+0ISZJyYUISfg8fmPIdQsetUK9Cj+Q5jpB2GXwELXWnIK6h
K/6jXp+EGEXSqdIE53vAFe7LwfHiP/D5M71D2h62sdIOmUm3lm7xMOnM5tKlBiV+
4jJSUmriCT62zo710+6iLGqmUUYlEll6Ppvo8yuanXkYRCFJpSSP7VP0bBqIZgQT
EQIAJgUCTnc9dgIbIwUJEPPzpwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEIxx
jTtQcuH1Ut4AoIKjhdf70899d+7JFq3LD7zeeyI0AJ9Z+YyE1HZSnzYi73brScil
bIV6sbQ7TXlTUUwgUGFja2FnZSBzaWduaW5nIGtleSAod3d3Lm15c3FsLmNvbSkg
PGJ1aWxkQG15c3FsLmNvbT6IbwQwEQIALwUCTnc9rSgdIGJ1aWxkQG15c3FsLmNv
bSB3aWxsIHN0b3Agd29ya2luZyBzb29uAAoJEIxxjTtQcuH1tT0An3EMrSjEkUv2
9OX05JkLiVfQr0DPAJwKtL1ycnLPv15pGMvSzav8JyWN3IhlBBMRAgAdBQJHrJS0
BQkNMFioBQsHCgMEAxUDAgMWAgECF4AAEgkQjHGNO1By4fUHZUdQRwABAa6SAJ9/
PgZQSPNeQ6LvVVzCALEBJOBt7QCffgs+vWP18JutdZc7XiawgAN9vmmITAQTEQIA
DAUCPj6j0QWDCWYAuwAKCRBJUOEqsnKR8iThAJ9ZsR4o37dNGyl77nEqP6RAlJqa
YgCeNTPTEVY+VXHR/yjfyo0bVurRxT2ITAQTEQIADAUCPkKCAwWDCWIiiQAKCRC2
9c1NxrokP5aRAKCIaaegaMyiPKenmmm8xeTJSR+fKQCgrv0TqHyvCRINmi6LPucx
GKwfy7KIRgQQEQIABgUCP6zjrwAKCRCvxSNIeIN0D/aWAKDbUiEgwwAFNh2n8gGJ
Sw/8lAuISgCdHMzLAS26NDP8T2iejsfUOR5sNriIRgQQEQIABgUCP7RDdwAKCRCF
lq+rMHNOZsbDAJ0WoPV+tWILtZG3wYqg5LuHM03faQCeKuVvCmdPtro06xDzeeTX
VrZ14+GIRgQQEQIABgUCQ1uz6gAKCRCL2C5vMLlLXH90AJ0QsqhdAqTAk3SBnO2w
zuSOwiDIUwCdFExsdDtXf1cL3Q4ilo+OTdrTW2CIRgQTEQIABgUCRPEzJgAKCRD2
ScT0YJNTDApxAKCJtqT9LCHFYfWKNGGBgKjka0zi9wCcCG3MvnvBzDUqDVebudUZ
61Sont+ITAQQEQIADAUCQYHLAQWDBiLZiwAKCRAYWdAfZ3uh7EKNAJwPywk0Nz+Z
Lybw4YNQ7H1UxZycaQCePVhY4P5CHGjeYj9SX2gQCE2SNx+ITAQQEQIADAUCQYHL
NAWDBiLZWAAKCRCBwvfr4hO2kiIjAJ0VU1VQHzF7yYVeg+bh31nng9OOkwCeJI8D
9mx8neg4wspqvgXRA8+t2saITAQQEQIADAUCQYHLYgWDBiLZKgAKCRBrcOzZXcP0
cwmqAJsFjOvkY9c5eA/zyMrOZ1uPB6pd4QCdGyzgbYb/eoPu6FMvVI9PVIeNZReI
TAQQEQIADAUCQdCTJAWDBdQRaAAKCRB9JcoKwSmnwmJVAKCG9a+Q+qjCzDzDtZKx
5NzDW1+W+QCeL68seX8OoiXLQuRlifmPMrV2m9+ITAQQEQIADAUCQitbugWDBXlI
0gAKCRDmG6SJFeu5q/MTAKCTMvlCQtLKlzD0sYdwVLHXJrRUvgCffmdeS6aDpwIn
U0/yvYjg1xlYiuqITAQSEQIADAUCQCpZOgWDB3pLUgAKCRA8oR80lPr4YSZcAJwP
4DncDk4YzvDvnRbXW6SriJn1yQCdEy+d0CqfdhM7HGUs+PZQ9mJKBKqITAQSEQIA
DAUCQD36ugWDB2ap0gAKCRDy11xj45xlnLLfAKC0NzCVqrbTDRw25cUss14RRoUV
PACeLpEc3zSahJUB0NNGTNlpwlTczlCITAQSEQIADAUCQQ4KhAWDBpaaCAAKCRA5
yiv0PWqKX/zdAJ4hNn3AijtcAyMLrLhlZQvib551mwCgw6FEhGLjZ+as0W681luc
wZ6PzW+ITAQSEQIADAUCQoClNAWDBSP/WAAKCRAEDcCFfIOfqOMkAJwPUDhS1eTz
gnXclDKgf353LbjvXgCeLCWyyj/2d0gIk6SqzaPl2UcWrqiITAQTEQIADAUCPk1N
hAWDCVdXCAAKCRAtu3a/rdTJMwUMAKCVPkbk1Up/kyPrlsVKU/Nv3bOTZACfW5za
HX38jDCuxsjIr/084n4kw/uITAQTEQIADAUCQdeAdgWDBc0kFgAKCRBm79vIzYL9
Pj+8AJ9d7rvGJIcHzTCSYVnaStv6jP+AEACeNHa5yltqieRBCCcLcacGqYK81omI
TAQTEQIADAUCQhiBDgWDBYwjfgAKCRB2wQMcojFuoaDuAJ9CLYdysef7IsW42UfW
hI6HjxkzSgCfeEpXS4hEmmGicdpRiJQ/W21aB0GIZQQTEQIAHQULBwoDBAMVAwID
FgIBAheABQJLcC/KBQkQ8/OnABIHZUdQRwABAQkQjHGNO1By4fWw2wCeJilgEarL
8eEyfDdYTyRdqE45HkoAnjFSZY8Zg/iXeErHI0r04BRukNVgiHsEMBECADsFAkJ3
NfU0HQBPb3BzLi4uIHNob3VsZCBoYXZlIGJlZW4gbG9jYWwhIEknbSAqc28qIHN0
dXBpZC4uLgAKCRA5yiv0PWqKX+9HAJ0WjTx/rqgouK4QCrOV/2IOU+jMQQCfYSC8
JgsIIeN8aiyuStTdYrk0VWCIjwQwEQIATwUCRW8Av0gdAFNob3VsZCBoYXZlIGJl
ZW4gYSBsb2NhbCBzaWduYXR1cmUsIG9yIHNvbWV0aGluZyAtIFdURiB3YXMgSSB0
aGlua2luZz8ACgkQOcor9D1qil+g+wCfcFWoo5qUl4XTE9K8tH3Q+xGWeYYAnjii
KxjtOXc0ls+BlqXxbfZ9uqBsiQIiBBABAgAMBQJBgcuFBYMGItkHAAoJEKrj5s5m
oURoqC8QAIISudocbJRhrTAROOPoMsReyp46Jdp3iL1oFDGcPfkZSBwWh8L+cJjh
dycIwwSeZ1D2h9S5Tc4EnoE0khsS6wBpuAuih5s//coRqIIiLKEdhTmNqulkCH5m
imCzc5zXWZDW0hpLr2InGsZMuh2QCwAkB4RTBM+r18cUXMLV4YHKyjIVaDhsiPP/
MKUj6rJNsUDmDq1GiJdOjySjtCFjYADlQYSD7zcd1vpqQLThnZBESvEoCqumEfOP
xemNU6xAB0CL+pUpB40pE6Un6Krr5h6yZxYZ/N5vzt0Y3B5UUMkgYDSpjbulNvaU
TFiOxEU3gJvXc1+h0BsxM7FwBZnuMA8LEA+UdQb76YcyuFBcROhmcEUTiducLu84
E2BZ2NSBdymRQKSinhvXsEWlH6Txm1gtJLynYsvPi4B4JxKbb+awnFPusL8W+gfz
jbygeKdyqzYgKj3M79R3geaY7Q75Kxl1UogiOKcbI5VZvg47OQCWeeERnejqEAdx
EQiwGA/ARhVOP/1l0LQA7jg2P1xTtrBqqC2ufDB+v+jhXaCXxstKSW1lTbv/b0d6
454UaOUV7RisN39pE2zFvJvY7bwfiwbUJVmYLm4rWJAEOJLIDtDRtt2h8JahDObm
3CWkpadjw57S5v1c/mn+xV9yTgVx5YUfC/788L1HNKXfeVDq8zbAiQIiBBMBAgAM
BQJCnwocBYMFBZpwAAoJENjCCglaJFfPIT4P/25zvPp8ixqV85igs3rRqMBtBsj+
5EoEW6DJnlGhoi26yf1nasC2frVasWG7i4JIm0U3WfLZERGDjR/nqlOCEqsP5gS3
43N7r4UpDkBsYh0WxH/ZtST5llFK3zd7XgtxvqKL98l/OSgijH2W2SJ9DGpjtO+T
iegq7igtJzw7Vax9z/LQH2xhRQKZR9yernwMSYaJ72i9SyWbK3k0+e95fGnlR5pF
zlGq320rYHgD7v9yoQ2t1klsAxK6e3b7Z+RiJG6cAU8o8F0kGxjWzF4v8D1op7S+
IoRdB0Bap01ko0KLyt3+g4/33/2UxsW50BtfqcvYNJvU4bZns1YSqAgDOOanBhg8
Ip5XPlDxH6J/3997n5JNj/nk5ojfd8nYfe/5TjflWNiput6tZ7frEki1wl6pTNbv
V9C1eLUJMSXfDZyHtUXmiP9DKNpsucCUeBKWRKLqnsHLkLYydsIeUJ8+ciKc+EWh
FxEY+Ml72cXAaz5BuW9L8KHNzZZfez/ZJabiARQpFfjOwAnmhzJ9r++TEKRLEr96
taUI9/8nVPvT6LnBpcM38Td6dJ639YvuH3ilAqmPPw50YvglIEe4BUYD5r52Seqc
8XQowouGOuBX4vs7zgWFuYA/s9ebfGaIw+uJd/56Xl9ll6q5CghqB/yt1EceFEnF
CAjQc2SeRo6qzx22iEYEEBECAAYFAkSAbycACgkQCywYeUxD5vWDcACfQsVk/XGi
ITFyFVQ3IR/3Wt7zqBMAoNhso/cX8VUfs2BzxPvvGS3y+5Q9iEYEEBECAAYFAkUw
ntcACgkQOI4l6LNBlYkyFgCbBcw5gIii0RTDJsdNiuJDcu/NPqEAniSq9iTaLjgF
HZbaizUU8arsVCB5iEYEEBECAAYFAkWho2sACgkQu9u2hBuwKr6bjwCfa7ZK6O+X
mT08Sysg4DEoZnK4L9UAoLWgHuYg35wbZYx+ZUTh98diGU/miF0EExECAB0FAj4+
owwFCQlmAYAFCwcKAwQDFQMCAxYCAQIXgAAKCRCMcY07UHLh9XGOAJ4pVME15/DG
rUDohtGv2z8a7yv4AgCeKIp0jWUWE525QocBWms7ezxd6syIXQQTEQIAHQUCR6yU
zwUJDTBYqAULBwoDBAMVAwIDFgIBAheAAAoJEIxxjTtQcuH1dCoAoLC6RtsD9K3N
7NOxcp3PYOzH2oqzAKCFHn0jSqxk7E8by3sh+Ay8yVv0BYhdBBMRAgAdBQsHCgME
AxUDAgMWAgECF4AFAkequSEFCQ0ufRUACgkQjHGNO1By4fUdtwCfRNcueXikBMy7
tE2BbfwEyTLBTFAAnifQGbkmcARVS7nqauGhe1ED/vdgiF0EExECAB0FCwcKAwQD
FQMCAxYCAQIXgAUCS3AuZQUJEPPyWQAKCRCMcY07UHLh9aA+AKCHDkOBKBrGb8tO
g9BIub3LFhMvHQCeIOOot1hHHUlsTIXAUrD8+ubIeZaJARwEEgECAAYFAkvCIgMA
CgkQ3PTrHsNvDi8eQgf/dSx0R9Klozz8iK79w00NOsdoJY0Na0NTFmTbqHg30XJo
G62cXYgc3+TJnd+pYhYi5gyBixF/L8k/kPVPzX9W0YfwChZDsfTw0iDVmGxOswiN
jzSo0lhWq86/nEL30Khl9AhCC1XFNRw8WZYq9Z1qUXHHJ2rDARaedvpKHOjzRY0N
dx6R2zNyHDx2mlfCQ9wDchWEuJdAv0uHrQ0HV9+xq7lW/Q3L/V5AuU0tiowyAbBL
PPYrB6x9vt2ZcXS7BOy8SfQ1i8W2QDQ/Toork4YwBiv6WCW/ociy7paAoPOWV/Nf
2S6hDispeecbk7wqpbUj5klDmwrlgB/jmoAXWEnbsYkBIgQQAQIADAUCSSpooAUD
ABJ1AAAKCRCXELibyletfFOMCACpP+OVZ7lH/cNY+373c4FnSI0/S5PXS0ABgdd4
BFWRFWKrWBeXBGc8sZfHOzVEwkzV96iyHbpddeAOAkEA4OVPW1MMFCmlHxi2s9/N
JrSrTPVfQOH5fR9hn7Hbpq/ETw0IoX1FKo7vndMnHZnFEnI+PDXLcdMYQgljYzhT
xER4vYY0UKu8ekSshUy4zOX7XSJxwqPUvps8qs/TvojIF+vDJvgFYHVkgvS+shp8
Oh/exg9vKETBlgU87Jgsqn/SN2LrR/Jhl0aLd0G0iQ+/wHmVYdQUMFaCZwk/BKNa
XPzmGZEUZ3RNbYa19Mo7hcE3js76nh5YMxFvxbTggVu4kdFkiQEiBBABAgAMBQJK
M06IBQMAEnUAAAoJEJcQuJvKV618F4gH/innejIHffGMk8jYix4ZZT7pW6ApyoI+
N9Iy85H4L+8rVQrtcTHyq0VkcN3wPSwtfZszUF/0qP6P8sLJNJ1BtrHxLORYjJPm
gveeyHPzA2oJl6imqWUTiW822fyjY/azwhvZFzxmvbFJ+r5N/Z57+Ia4t9LTSqTN
HzMUYaXKDaAqzZeK7P0E6XUaaeygbjWjBLQ1O0ezozAy+Kk/gXApmDCGFuHSFe7Z
mgtFcbXLM2XFQpMUooETD2R8MUsd+xnQsff/k6pQOLxi+jUEsWSr/iqmvlk6gZ4D
pemBjuhcXYlxJYjUaX9Zmn5s+ofF4GFxRqXoY7l9Z+tCM9AX37lm6S+JASIEEAEC
AAwFAkpEcgoFAwASdQAACgkQlxC4m8pXrXz2mgf/RQkpmMM+5r8znx2TpRAGHi5w
ktvdFxlvPaOBWE28NDwTrpcoMqo9kzAiuvEQjVNihbP21wR3kvnQ84rTAH0mlC2I
uyybggpqwzOUl+Wi0o+vk8ZA0A0dStWRN8uqneCsd1XnqDe1rvqC4/9yY223tLmA
kPvz54ka2vX9GdJ3kxMWewhrVQSLCktQpygU0dujGTDqJtnk0WcBhVF9T87lv3W2
eGdPielzHU5trXezmGFj21d56G5ZFK8co7RrTt4qdznt80glh1BTGmhLlzjMPLTe
dcMusm3D1QB9ITogcG94ghSf9tEKmmRJ6OnnWM5Kn9KcL63E5oj2/lY9H54wSYkB
IgQQAQIADAUCSlY+RwUDABJ1AAAKCRCXELibyletfOOQB/0dyJBiBjgf+8d3yNID
pDktLhZYw8crIjPBVdOgX12xaUYBTGcQITRVHSggzffDA5BQXeUuWhpL4QB0uz1c
EPPwSMiWiXlBtwF5q6RVf3PZGJ9fmFuTkPRO7SruZeVDo9WP8HjbQtOLukYf566e
grzAYR9p74UgWftpDtmrqrRTobiuvsFBxosbeRCvEQCrN0n+p5D9hCVB88tUPHnO
WA4mlduAFZDxQWTApKQ92frHiBqy+M1JFezz2OM3fYN+Dqo/Cb7ZwOAA/2dbwS7o
y4sXEHbfWonjskgPQwFYB23tsFUuM4uZwVEbJg+bveglDsDStbDlfgArXSL/0+ak
lFcHiQEiBBABAgAMBQJKaAqEBQMAEnUAAAoJEJcQuJvKV618rH0H/iCciD4U6YZN
JBj0GN7/Xt851t9FWocmcaC+qtuXnkFhplXkxZVOCU4VBMs4GBoqfIvagbBTyfV4
Di+W8Uxr+/1jiu3l/HvoFxwdwNkGG6zNBhWSjdwQpGwPvh5ryV1OfLX/mgQgdDmx
vqz5+kFDUj4m7uLaeuU2j1T0lR4zU0yAsbt7J3hwfqJCXHOc9bm5nvJwMrSm+sdC
TP5HjUlwHr9mTe8xuZvj6sO/w0P4AqIMxjC9W7pT9q0ofG2KSTwt7wFbh05sbG4U
QYOJe4+Soh3+KjAa1c0cvmIh4cKX9qfCWwhhdeNfh1A9VTHhnl5zTv/UjvnQtjhl
H/Fq1eBSKcSJASIEEAECAAwFAkp5LgoFAwASdQAACgkQlxC4m8pXrXwY6wgAg3f8
76L3qDZTYlFAWs3pXBl8GsUr1DEkTlEDZMZKDM3wPmhaWBR1hMA3y6p3aaCUyJIJ
BEneXzgyU9uqCxXpC78d5qc3xs/Jd/SswzNYuvuzLYOw5wN5L31SLmQTQ8KqE0uo
RynBmtDCQ4M2UKifSnv+0+3mPh85LVAS481GNpL+VVfCYtKesWNu40+98Yg6L9NG
WwRTfsQbcdokZo44Jz7Y7f81ObC4r/X1DgPj2+d4AU/plzDcdrbINOyprs+7340e
cnaGO4Lsgd19b1CvcgJgltRquu3kRvd+Ero2RYpDv6GVK8Ea0Lto4+b/Ae8cLXAh
QnaWQCEWmw+AU4Jbz4kBIgQQAQIADAUCSo5fvQUDABJ1AAAKCRCXELibyletfA08
B/9w8yJdc8K+k07U30wR/RUg3Yb2lBDygmy091mVsyB0RGixBDXEPOXBqGKAXiV1
QSMAXM2VKRsuKahY2HFkPbyhZtjbdTa7Pr/bSnPvRhAh9GNWvvRg2Kp3qXDdjv9x
ywEghKVxcEIVXtNRvpbqRoKmHzIExvUQck5DM1VwfREeYIoxgs4035WADhVMdngQ
S2Gt8P2WaU/p8EZhFGg6X8KtOlD68zGboaJe0hj2VDc+Jc+KdjRfE3fW5IToid/o
DkUaIW6tB3WkXb0g6D/2hrEJbX3headChHKSB8eQdOR9bcCJDhhU8csd501qmrhC
ctmvlpeWQZdIQdk6sABPWeeCiQEiBBABAgAMBQJKoBJHBQMAEnUAAAoJEJcQuJvK
V618Ml8H/1D88/g/p9fSVor4Wu5WlMbg8zEAik3BIxQruEFWda6nART6M9E7e+P1
++UHZsWYs6l9ROpWxRLG1Yy9jLec2Y3nUtb20m65p+IVeKR2a9PHW35WZDV9dOYP
GZabKkO1clLeWLVgp9LRjZ+AeRG+ljHqsULXro1dwewLTB/gg9I2vgNv6dKxyKak
nM/GrqZLATAq2KoaE/u/6lzRFZIzZnLtjZh8X7+nS+V8v9IiY4ntrpkrbvFk30U6
WJp79oBIWwnW/84RbxutRoEwSar/TLwVRkcZyRXeJTapbnLGnQ/lDO1o1d7+Vbjd
q/Sg/cKHHf7NthCwkQNsCnHL0f51gZCJASIEEAECAAwFAkqoEAAFAwASdQAACgkQ
lxC4m8pXrXwE/Af/XD4R/A5R6Ir/nCvKwCTKJmalajssuAcLEa2pMnFZYO/8rzLO
+Gp8p0qFH9C4LFwA0NvR5q6X/swuROf4zxljSvNcdlQVaAfJ2ZDEgJ5GXzsPplrv
SAI9jS3LL7fSWDZgKuUe0a4qx7A0NgyGMUYGhP+QlRFa8vWEBI9fANd/0mMqAeBV
qQyOH0X1FiW1Ca2Jn4NKfuMy9GEvRddVIbB1LvoNVtXPNzeeKMyNb9Jdx1MFWssy
COBP2DayJKTmjvqPEc/YOjOowoN5sJ/jn4mVSTvvlTooLiReSs6GSCAjMVxN7eYS
/Oyq6Iu1JDcJvmB8N2WixAZtAVgF8OA7CWXKVYkBIgQQAQIADAUCSrnHiQUDABJ1
AAAKCRCXELibyletfPChB/9uECti1dZeNuFsd0/RuGyRUVlrrhJE6WCcOrLO9par
rPbewbKBmjSzB0MygJXGvcC06mPNuquJ7/WpxKsFmfg4vJBPlADFKtgRUy9BLzjC
eotWchPHFBVW9ftPbaQViSUu7d89NLjDDM5xrh80puDIApxoQLDoIrh3T1kpZx56
jSWv0gelFUMbXAzmqkJSyL4Xdh1aqzgUbREd7Xf2ICzuh0sV6V7c/AwWtjWEGEsA
HZaiQDywZwbC18GwrMLiAzGWb/AScFDQRCZKJDjL+Ql8YT6z+ZMVr8gb7CIU5PKY
dhiIf2UVTQwLAoW7lNRCQQAqcGjK3IMIz7SO/yk4HmVUiQEiBBABAgAMBQJK3gjG
BQMAEnUAAAoJEJcQuJvKV618jkEH+wb0Zv9z7xQgpLMowVuBFQVu8/z7P5ASumyB
PUO3+0JVxSHBhlCKQK7n11m1fhuGt2fCxXhSU6LzXj36rsKRY53lGZ9QhvqFUtQH
3Xb2IQLIJC4UKjG2jSSCdcuA/x98bwp2v7O03rn7ndCS16CwXnRV3geQoNipRKMS
DajKPpZv1RiZm8pMKqEb8WSw352xWoOcxuffjlsOEwvJ85SEGCAZ9tmIlkZOc7Ai
QONDvii9b8AYhQ60RIQC0HP2ASSmK0V92VeFPxHmAygdDQgZNVtbVxgnnt7oTNEu
VRXNY+z4OfBArp7R+cTsvijDRZY4kML1n22hUybwoxUEvjqZV2+JASIEEAECAAwF
AkrvOlQFAwASdQAACgkQlxC4m8pXrXxrPAgArXiNgZirNuBhfNCXlkzkCHLx5wnV
e4SmTpbWzTwWw7+qk7d4l9hlWtdImISORINzo7f4ShSUzJX2GciNaXhaHRo7+y5O
Zbu82jQb09aQQj/nibKYuqxqUrobTEm+DuYz3JUQZm2PsPcHLS8mX9cxvrJUncPG
nXEV0DRaq71SGWDprtkvBbp6i38aY3sIhYgz8wM5m1szKDtjywmBYcFehIdozt9z
hm7wZshzRWQX1+Rf/pIsnk+OzBIa34crSemTnacbV/B7278z2XAyziPNFuqz0xu+
iltOmYmayfNWAmumuw9NcuwWMlth6Mc2HLrpo0ZBheJ6iuDMPsHnwqdB/4kBIgQQ
AQIADAUCSwBd2gUDABJ1AAAKCRCXELibyletfP6tB/4m1w0BtlkJgtS6E+B/ns14
z4A4PGors+n+MYm05qzvi+EnDF/sytCmVcKeimrtvDcfoDtKAFFvJjcYXfnJdGWm
Pu0SJMRL5KKCirAKwZmU/saxOgoB5QLNw+DHPteJ3w9GmWlGxIqG1r15WC5duzBC
y3FsnjJYG3jaLnHOO9yXXb5h0kUTORfUKdvAr1gxF2KoatZWqGoaPPnHoqb88rjt
zk8I7gDqoXnzh8wLxa0ZYvfTC/McxdWTrwXLft+krmMQ18iIZEne2hvVLNJVuluU
oiWLeHA8iNCQ4W4WTdLc1mCnCjGTMX/MN41uLH0C9Ka4R6wEaqj4lPDk1B/1TV+Q
iQEiBBABAgAMBQJLEYGrBQMAEnUAAAoJEJcQuJvKV618naIH/2t9aH5mBTKBN6fU
qhrf79vIsjtI/QNS5qisBISZMX3/1/0Gu6WnxkPSfdCUJMWCjMcnVj7KU2wxTHHG
VpAStd9r2afUNxRyqZwzwyytktuZok0XngAEDYDDBS3ssu2R4uWLCsC2ysXEqO/5
tI5YrTWJZrfeIphTaYP5hxrMujvqy3kEwKKbiMz91cDeiLS+YCBcalj5n/1dMYf7
8U8C6ieurxAg/L8h6x25VM4Ilx4MmG2T8QGtkkUXd+Fd/KYWmf0LE5LLPknf0Hhw
oVslPXeinp4FsHK/5wzviv4YZpzuTqs9NlKcMsa4IuuPOB0FDf0pn+OFQbEg9QwY
2gCozK+JASIEEAECAAwFAksjTdQFAwASdQAACgkQlxC4m8pXrXwlogf/XBGbXRVX
LMaRN4SczOjwT3/tUCriTkb3v+zKjRG90zFhYAccjn7w+7jKQicjq6quQG1EH2X4
/Su6ps1lDLqGHHhiJW3ZhxQScLZmhdAYsh2qG4GP/UW3QjXG7c61t+H3olvWg2cr
wqCxxFZAgkAAkr9xcHWFZJEQeXoob6cCZObaUnHSANdmC6s5lUxXYa2bmL7Q3UB4
4KCzDvAfbPZKJOw9k0qb3lc11zx+vGdyZFbm4R0+3LPp/vT0b3GlSbbF9lU1GOXh
VaphrgFFa76dmjfHCkPplXAkK1VSIU/aPGAefduTFMdlSZpdMtJ5AULjGcszBDlR
pLlPxvqVa0ZpgIkBIgQQAQIADAUCSycmkgUDABJ1AAAKCRCXELibyletfHlNCACp
1YespiHfQt2alcscE5zgfETEHHic8Ai6pNkU9HT4TeWcFHEDe5QqfYcpjLrQvBXS
kSvxEittbyRdv+e+j5Z+HyHjiG8nAQBL6qy9eHqQE4+d7gYs6DTk7sG9ZMYphREb
ltzD+F4hVCQdLT8LNr0eVFN7ehqECScDaCG8/Qyti+l/0M902/Yn+mz0ilOiUdWJ
9x6LPaIINtb1gsYDEylLjwGIZmI0r5Kh9wYoV4vnNezFbxO1uRiW0B7iaPjIEsbt
OOKp7wx2aX+DM3N9F3BtaIY8XnzcnomNm83SNsgmgrZljpQltUnNqIhNM8DupQ+I
WOV5gtl6pTC7CgeVTVyRiQEiBBABAgAMBQJLOGXuBQMAEnUAAAoJEJcQuJvKV618
ll4IAKJ9mm4jb0c8fe9+uDI8eCJRbzNbVXm8zWzpA8GUtQAakwxoKv332QP1Wa1P
odni/e3EMhsSREOZJJv79YqGxGRBTE9Kb/VjM34nas4XSnXKW28XWhKyIw+XwQAi
nY2swFHh+83Htr/mwTdJfS2aEYl2zboBvd/JZCdhOGU2GH737S/3uEczoKkfVQ/w
OTM8X1xWwlYWqx23k/DsGcuDs9lA2g7Mx7DSqBtVjaTkn9h0zATzXLDkmP4SAUVj
cZ83WDpFre5WnizZjdXlBMM5OCexp5WpmzyHLTnaBFK4jEmnsk5C2Rnoyp8Ivz6g
Ecg1tRbEXijRw++d2TFYlJwLKtiJASIEEAECAAwFAktKMicFAwASdQAACgkQlxC4
m8pXrXxqHQgAuYY5scKrh0m/GS9EYnyC9494lOlO6iytU0CpE6oBC31M3hfX/Dbj
UbcS5szZNU+2CPYo4ujQLZ7suN7+tTjG6pZFfMevajT9+jsL+NPMF8RLdLOVYmbl
TmSQGNO+XGEYaKYH5oZIeIW5AKCgi2ozkdFlBBLAx7Kqo/FyybhkURFEcvEyVmgf
3KLV7IIiX/fYLfoCMCJ/Lcm9/llSFB1n8Nvg66Xd533DKoHjueD3jyaNAVlo2mq/
sIAv++kntvOiB3GDK5pfwHZ78WWiCpsWZpE5gzAnzJ1Y0WEigRo0PVLu3cLO0jLG
23d+H/CbfZ8rkajHJeCDQF7YVmP0t0nYpYkBIgQQAQIADAUCS1v+ZgUDABJ1AAAK
CRCXELibyletfNS/CACqt2TkB86mjqM+cJ74+dWBvJ2aFuURuxzm95i9Q/W/hU08
2iMbC3+0k2oD8CrTOe61P+3oRyLjv/UEDUNzLncNe2YsA9JeV+4hvPwH5Vp3Om13
089fCKZUbqslXNKkHiWYU+zAaZJXEuGRmRz0HbQIeAMOWF4oa226uo1e4ws1Jhc+
F3E/ApCRyFBqBUdL05hapQLditYpsBjIdiBGpjzidMLE2wX2W4ZpAdN0U6BIyIqR
mTPjbSkvzS9kSWFmfhQgnBDKEYJpVZgE1sN52rYC1sDeGeiuKxlzjVov9MMhYMWa
Zo3R5o3F2iIM/BK6FbC252lf/Mhu3ICuXujNBZNYiQEiBBABAgAMBQJLbSH4BQMA
EnUAAAoJEJcQuJvKV618kd0IAJLLwDH6gvgAlBFklQJXqQxUdcSOOVMAWtlHgWOy
ozjgomZZBkRL8dtCDr9YBMcj5czcQ3qpmLJdppXhKB+kJV2iUXfDMSFXwJ4wLfIs
8FNnXw8H5U01oBkGH/Ku6ngL9Vwt+MjYHtCWkw9QueUKZnDudX9qIzLAIt+mwSTu
A6+fY4VWIg40AA0v3exaQM55YR/UhlKunpGG9o8Qkq77dMEbTMpOmBoLbOMRB3Dd
MAvVU6G2l6Pcb7KobVCuOBnb6batXARV/G8sw+nzfJ16fr/KobZT2A6m+Jrqk4dl
F14ljLbz16O5JGUPAryN2G2ddBdSAy7dtFSVhWWiWC9n88q5Ag0EPj6jHRAIAO/h
iX8WzHWOMLJT54x/axeDdqn1rBDf5cWmaCWHN2ujNNlgpx5emoU9v7QStsNUCOGB
bXkeO4Ar7YG+jtSR33zqNh3y5kQ0YkY3dQ0wh6nsl+wh4XIIY/3TUZVtmdJeUBRH
JlfVNFYad2hX1guFI37Ny1PoZAFsxO82g+XB/Se8r/+sbmVcONdcdIeFKrE3FjLt
IjNQcxC6l9Q2Oy8KDxG/zvUZG3+H5i3tdRMyGgmuD6gEV0GXOHYUopzLeit1+Aa0
bCk36Mwbu+BeOw/CJW3+b0mB27hOaf9aCA855IP6fJFvtxcblq8nHIqhU3Dc9tec
sl9/S1xZ5S8ylG/xeRsAAwUH/i8KqmvAhq0X7DgCcYputwh37cuZlHOa1Ep07JRm
BCDgkdQXkGrsj2Wzw7Aw/TGdWWkmn2pxb8BRui5cfcZFO7c6vryi6FpJuLucX975
+eVY50ndWkPXkJ1HF4i+HJwRqE2zliN/RHMs4LJcwXQvvjD43EE3AO6eiVFbD+qA
AdxUFoOeLblKNBHPG7DPG9xL+Ni5rkE+TXShxsB7F0z7ZdJJZOG0JODmox7IstQT
GoaU9u41oyZTIiXPiFidJoIZCh7fdurP8pn3X+R5HUNXMr7M+ba8lSNxce/F3kmH
0L7rsKqdh9d/aVxhJINJ+inVDnrXWVoXu9GBjT8Nco1iU9SIVAQYEQIADAUCTnc9
7QUJE/sBuAASB2VHUEcAAQEJEIxxjTtQcuH1FJsAmwWK9vmwRJ/y9gTnJ8PWf0BV
roUTAKClYAhZuX2nUNwH4vlEJQHDqYa5yQ==
=HfUN
-----END PGP PUBLIC KEY BLOCK-----
+99 -11
View File
@@ -1,25 +1,113 @@
FROM debian:jessie
FROM debian:jessie-slim
MAINTAINER Rafael Römhild <rafael@roemhild.de>
ENV XMPP_DOMAIN=localhost \
ENV EJABBERD_BRANCH=17.04 \
EJABBERD_USER=ejabberd \
EJABBERD_HTTPS=true \
EJABBERD_STARTTLS=true \
EJABBERD_S2S_SSL=true \
EJABBERD_HOME=/opt/ejabberd \
PATH=/opt/ejabberd/bin:/usr/sbin:/usr/bin:/sbin:/bin \
EJABBERD_DEBUG_MODE=false \
HOME=$EJABBERD_HOME \
PATH=$EJABBERD_HOME/bin:/usr/sbin:/usr/bin:/sbin:/bin \
DEBIAN_FRONTEND=noninteractive \
XMPP_DOMAIN=localhost \
# Set default locale for the environment
LC_ALL=C.UTF-8 \
LANG=en_US.UTF-8 \
LANGUAGE=en_US.UTF-8
# bootstrap
COPY . /tmp/ejabberd
RUN /tmp/ejabberd/docker/bootstrap.sh
# Add ejabberd user and group
RUN groupadd -r $EJABBERD_USER \
&& useradd -r -m \
-g $EJABBERD_USER \
-d $EJABBERD_HOME \
$EJABBERD_USER
# Install packages and perform cleanup
RUN set -x \
&& buildDeps=' \
git-core \
build-essential \
automake \
libssl-dev \
zlib1g-dev \
libexpat-dev \
libyaml-dev \
libsqlite3-dev \
erlang-src erlang-dev \
' \
&& requiredAptPackages=' \
locales \
ldnsutils \
python2.7 \
python-jinja2 \
ca-certificates \
libyaml-0-2 \
erlang-base erlang-snmp erlang-ssl erlang-ssh erlang-webtool \
erlang-tools erlang-xmerl erlang-corba erlang-diameter erlang-eldap \
erlang-eunit erlang-ic erlang-odbc erlang-os-mon \
erlang-parsetools erlang-percept erlang-typer erlang-inets \
python-mysqldb \
imagemagick \
' \
&& apt-key adv \
--keyserver keys.gnupg.net \
--recv-keys 434975BD900CCBE4F7EE1B1ED208507CA14F4FCA \
&& apt-get update \
&& apt-get install -y $buildDeps $requiredAptPackages --no-install-recommends \
&& dpkg-reconfigure locales && \
locale-gen C.UTF-8 \
&& /usr/sbin/update-locale LANG=C.UTF-8 \
&& echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen \
&& locale-gen \
&& cd /tmp \
&& git clone https://github.com/processone/ejabberd.git \
--branch $EJABBERD_BRANCH --single-branch --depth=1 \
&& cd ejabberd \
&& chmod +x ./autogen.sh \
&& ./autogen.sh \
&& ./configure --enable-user=$EJABBERD_USER \
--prefix=/ \
--enable-all \
--disable-tools \
--disable-pam \
&& make debug=$EJABBERD_DEBUG_MODE \
&& make install \
&& mkdir $EJABBERD_HOME/ssl \
&& mkdir $EJABBERD_HOME/conf \
&& mkdir $EJABBERD_HOME/backup \
&& mkdir $EJABBERD_HOME/upload \
&& mkdir $EJABBERD_HOME/database \
&& mkdir $EJABBERD_HOME/module_source \
&& cd $EJABBERD_HOME \
&& rm -rf /tmp/ejabberd \
&& rm -rf /etc/ejabberd \
&& ln -sf $EJABBERD_HOME/conf /etc/ejabberd \
&& chown -R $EJABBERD_USER: $EJABBERD_HOME \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get purge -y --auto-remove $buildDeps
# Wrapper for setting config on disk from environment
# allows setting things like XMPP domain at runtime
ADD ./docker/run.sh /sbin/run
# Add run scripts
ADD ./docker/scripts $EJABBERD_HOME/scripts
ADD https://raw.githubusercontent.com/rankenstein/ejabberd-auth-mysql/master/auth_mysql.py $EJABBERD_HOME/scripts/lib/auth_mysql.py
RUN chmod a+rx $EJABBERD_HOME/scripts/lib/auth_mysql.py
# Add config templates
ADD ./docker/conf /opt/ejabberd/conf
# Continue as user
USER ejabberd
USER $EJABBERD_USER
# Set workdir to ejabberd root
WORKDIR /opt/ejabberd
VOLUME ["/opt/ejabberd/conf", "/opt/ejabberd/database", "/opt/ejabberd/ssl", "/opt/ejabberd/backup", "/opt/ejabberd/upload", "/opt/ejabberd/modules"]
WORKDIR $EJABBERD_HOME
VOLUME ["$EJABBERD_HOME/database", "$EJABBERD_HOME/ssl", "$EJABBERD_HOME/backup", "$EJABBERD_HOME/upload"]
EXPOSE 4560 5222 5269 5280 5443
ENTRYPOINT ["/opt/ejabberd/docker/start.sh"]
CMD ["start"]
ENTRYPOINT ["run"]
+4 -4
View File
@@ -125,11 +125,11 @@ ifeq ($(MAKECMDGOALS),copy-files-sub)
DEPS:=$(sort $(shell $(REBAR) list-deps|$(SED) -e '/^=/d;s/ .*//'))
DEPS_FILES=$(call FILES_WILDCARD,$(foreach DEP,$(DEPS),deps/$(DEP)/ebin/*.beam deps/$(DEP)/ebin/*.app deps/$(DEP)/priv/* deps/$(DEP)/priv/lib/* deps/$(DEP)/priv/bin/* deps/$(DEP)/include/*.hrl deps/$(DEP)/lib/*/ebin/*.beam deps/$(DEP)/lib/*/ebin/*.app))
DEPS_FILES=$(call FILES_WILDCARD,$(foreach DEP,$(DEPS),deps/$(DEP)/ebin/*.beam deps/$(DEP)/ebin/*.app deps/$(DEP)/priv/* deps/$(DEP)/priv/lib/* deps/$(DEP)/priv/bin/* deps/$(DEP)/include/*.hrl deps/$(DEP)/COPY* deps/$(DEP)/LICENSE* deps/$(DEP)/lib/*/ebin/*.beam deps/$(DEP)/lib/*/ebin/*.app))
DEPS_FILES_FILTERED=$(filter-out %/epam deps/elixir/ebin/elixir.app,$(DEPS_FILES))
DEPS_DIRS=$(sort deps/ $(foreach DEP,$(DEPS),deps/$(DEP)/) $(dir $(DEPS_FILES)))
MAIN_FILES=$(filter-out %/configure.beam,$(call FILES_WILDCARD,ebin/*.beam ebin/*.app priv/msgs/*.msg priv/lib/* include/*.hrl))
MAIN_FILES=$(filter-out %/configure.beam,$(call FILES_WILDCARD,ebin/*.beam ebin/*.app priv/msgs/*.msg priv/lib/* include/*.hrl COPYING))
MAIN_DIRS=$(sort $(dir $(MAIN_FILES)) priv/bin priv/sql)
define DEP_VERSION_template
@@ -148,7 +148,7 @@ $(foreach file,$(DEPS_FILES_FILTERED) $(MAIN_FILES),$(eval $(call COPY_template,
$(sort $(call TO_DEST,$(MAIN_DIRS) $(DEPS_DIRS))):
$(INSTALL) -d $@
$(call TO_DEST,deps/p1_pam/priv/bin/epam): $(LIBDIR)/%: deps/p1_pam/priv/bin/epam $(call TO_DEST,deps/p1_pam/priv/bin/)
$(call TO_DEST,deps/epam/priv/bin/epam): $(LIBDIR)/%: deps/epam/priv/bin/epam $(call TO_DEST,deps/epam/priv/bin/)
$(INSTALL) -m 750 $(O_USER) $< $@
$(call TO_DEST,priv/sql/lite.sql): sql/lite.sql $(call TO_DEST,priv/sql)
@@ -295,7 +295,7 @@ dialyzer/erlang.plt:
@mkdir -p dialyzer
@dialyzer --build_plt --output_plt dialyzer/erlang.plt \
-o dialyzer/erlang.log --apps kernel stdlib sasl crypto \
public_key ssl mnesia inets odbc tools compiler erts webtool \
public_key ssl mnesia inets odbc tools compiler erts \
runtime_tools asn1 observer xmerl et gs wx syntax_tools; \
status=$$? ; if [ $$status -ne 2 ]; then exit $$status; else exit 0; fi
+1 -1
View File
@@ -108,7 +108,7 @@ To compile ejabberd you need:
- GCC.
- Libexpat 1.95 or higher.
- Libyaml 0.1.4 or higher.
- Erlang/OTP 17.1 or higher.
- Erlang/OTP 17.5 or higher.
- OpenSSL 1.0.0 or higher, for STARTTLS, SASL and SSL encryption.
- Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
+31 -4
View File
@@ -66,7 +66,7 @@ if test "x$MAKE" = "x"; then
fi
# Change default prefix
AC_PREFIX_DEFAULT(/)
AC_PREFIX_DEFAULT(/usr/local)
AC_ARG_ENABLE(hipe,
[AC_HELP_STRING([--enable-hipe], [compile natively with HiPE, not recommended (default: no)])],
@@ -101,10 +101,10 @@ AC_ARG_ENABLE(mssql,
esac],[db_type=generic])
AC_ARG_ENABLE(all,
[AC_HELP_STRING([--enable-all], [same as --enable-odbc --enable-mysql --enable-pgsql --enable-sqlite --enable-pam --enable-zlib --enable-riak --enable-redis --enable-elixir --enable-iconv --enable-debug --enable-tools (useful for Dialyzer checks, default: no)])],
[AC_HELP_STRING([--enable-all], [same as --enable-odbc --enable-mysql --enable-pgsql --enable-sqlite --enable-pam --enable-zlib --enable-riak --enable-redis --enable-elixir --enable-iconv --enable-stun --enable-sip --enable-debug --enable-tools (useful for Dialyzer checks, default: no)])],
[case "${enableval}" in
yes) odbc=true mysql=true pgsql=true sqlite=true pam=true zlib=true riak=true redis=true elixir=true iconv=true debug=true tools=true ;;
no) odbc=false mysql=false pgsql=false sqlite=false pam=false zlib=false riak=false redis=false elixir=false iconv=false debug=false tools=false ;;
yes) odbc=true mysql=true pgsql=true sqlite=true pam=true zlib=true riak=true redis=true elixir=true iconv=true stun=true sip=true debug=true tools=true ;;
no) odbc=false mysql=false pgsql=false sqlite=false pam=false zlib=false riak=false redis=false elixir=false iconv=false stun=false sip=false debug=false tools=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-all) ;;
esac],[])
@@ -212,6 +212,30 @@ AC_ARG_ENABLE(latest_deps,
*) AC_MSG_ERROR(bad value ${enableval} for --enable-latest-deps) ;;
esac],[if test "x$latest_deps" = "x"; then latest_deps=false; fi])
AC_ARG_ENABLE(system_deps,
[AC_HELP_STRING([--enable-system-deps], [makes rebar use localy installed dependences instead of downloading them (default: no)])],
[case "${enableval}" in
yes) system_deps=true ;;
no) system_deps=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-system-deps) ;;
esac],[if test "x$system_deps" = "x"; then system_deps=false; fi])
AC_ARG_ENABLE(stun,
[AC_HELP_STRING([--enable-stun], [enable STUN/TURN support (default: no)])],
[case "${enableval}" in
yes) stun=true ;;
no) stun=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-stun) ;;
esac],[if test "x$stun" = "x"; then stun=false; fi])
AC_ARG_ENABLE(sip,
[AC_HELP_STRING([--enable-sip], [enable SIP support (default: no)])],
[case "${enableval}" in
yes) sip=true ;;
no) sip=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-sip) ;;
esac],[if test "x$sip" = "x"; then sip=false; fi])
AC_CONFIG_FILES([Makefile
vars.config
src/ejabberd.app.src])
@@ -253,9 +277,12 @@ AC_SUBST(riak)
AC_SUBST(redis)
AC_SUBST(elixir)
AC_SUBST(iconv)
AC_SUBST(stun)
AC_SUBST(sip)
AC_SUBST(debug)
AC_SUBST(tools)
AC_SUBST(latest_deps)
AC_SUBST(system_deps)
AC_SUBST(CFLAGS)
AC_SUBST(CPPFLAGS)
AC_SUBST(LDFLAGS)
+1 -1
View File
@@ -68,7 +68,7 @@ or use a data container
```bash
docker create --name ejabberd-data rroemhild/ejabberd-data
docker run -d --name ejabberd --volumes-from processone-data rroemhild/ejabberd
docker run -d --name ejabberd --volumes-from ejabberd-data rroemhild/ejabberd
```
## SSL Certificates
-75
View File
@@ -1,75 +0,0 @@
#!/bin/sh
set -ex
export DEBIAN_FRONTEND="noninteractive"
readonly buildDeps='
git-core
build-essential
automake
libssl-dev
zlib1g-dev
libexpat-dev
libyaml-dev
libsqlite3-dev
erlang-src erlang-dev'
readonly requiredAptPackages='
locales
ldnsutils
python2.7
python-jinja2
ca-certificates
libyaml-0-2
erlang-base erlang-snmp erlang-ssl erlang-ssh erlang-webtool
erlang-tools erlang-xmerl erlang-corba erlang-diameter erlang-eldap
erlang-eunit erlang-ic erlang-odbc erlang-os-mon
erlang-parsetools erlang-percept erlang-typer
python-mysqldb
imagemagick'
apt-key adv \
--keyserver keys.gnupg.net \
--recv-keys 434975BD900CCBE4F7EE1B1ED208507CA14F4FCA
apt-get update
apt-get install -y $buildDeps $requiredAptPackages --no-install-recommends
dpkg-reconfigure locales && locale-gen C.UTF-8
/usr/sbin/update-locale LANG=C.UTF-8
echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen
locale-gen
# add ejabberd user
useradd --home $EJABBERD_HOME -M --system ejabberd
mkdir $EJABBERD_HOME
cd /tmp/ejabberd
chmod +x ./autogen.sh
./autogen.sh
./configure --enable-user=ejabberd \
--enable-all \
--disable-tools \
--disable-pam
make debug=$EJABBERD_DEBUG_MODE
make install
cd $EJABBERD_HOME
mkdir -p logs ssl backup upload module_source modules/conf
mv /tmp/ejabberd/docker $EJABBERD_HOME
# Move config to homedir
mv /etc/ejabberd conf
ln -s $EJABBERD_HOME/conf /etc/ejabberd
# rename original configs
mv conf/ejabberd.yml conf/ejabberd.yml.orig
mv conf/ejabberdctl.cfg conf/ejabberdctl.cfg.orig
# clean up
rm -rf /tmp/ejabberd
rm -rf /var/lib/apt/lists/*
apt-get purge -y --auto-remove $buildDeps
# change owner for ejabberd home
chown -R ejabberd $EJABBERD_HOME
+10 -7
View File
@@ -300,7 +300,7 @@ modules:
mod_caps: {}
mod_carboncopy: {}
mod_client_state:
drop_chat_states: true
queue_chat_states: true
queue_presence: false
mod_configure: {} # requires mod_adhoc
mod_disco: {}
@@ -311,6 +311,8 @@ modules:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
mod_last: {}
mod_mam:
default: always
mod_muc:
host: "conference.@HOST@"
access: muc
@@ -404,12 +406,13 @@ host_config:
{%- if env['EJABBERD_CONFIGURE_ODBC'] == "true" %}
### ====================
### ODBC DATABASE CONFIG
odbc_type: {{ env['EJABBERD_ODBC_TYPE'] }}
odbc_server: {{ env['EJABBERD_ODBC_SERVER'] }}
odbc_database: {{ env['EJABBERD_ODBC_DATABASE'] }}
odbc_username: {{ env['EJABBERD_ODBC_USERNAME'] }}
odbc_password: {{ env['EJABBERD_ODBC_PASSWORD'] }}
odbc_pool_size: {{ env['EJABBERD_ODBC_POOL_SIZE'] }}
sql_type: {{ env['EJABBERD_ODBC_TYPE'] }}
sql_server: "{{ env['EJABBERD_ODBC_SERVER'] }}"
sql_database: "{{ env['EJABBERD_ODBC_DATABASE'] }}"
sql_username: "{{ env['EJABBERD_ODBC_USERNAME'] }}"
sql_password: "{{ env['EJABBERD_ODBC_PASSWORD'] }}"
default_db: sql
{% endif %}
{%- if env['EJABBERD_DEFAULT_DB'] is defined %}
+21 -33
View File
@@ -10,7 +10,7 @@
#
# Default: true
#
POLL={{ env['POLL'] or 'true' }}
#POLL=true
#.
#' SMP: SMP support ([enable|auto|disable])
@@ -24,7 +24,7 @@ POLL={{ env['POLL'] or 'true' }}
#
# Default: auto
#
SMP={{ env['SMP'] or 'auto' }}
#SMP=auto
#.
#' ERL_MAX_PORTS: Maximum number of simultaneously open Erlang ports
@@ -36,7 +36,7 @@ SMP={{ env['SMP'] or 'auto' }}
# Default: 32000
# Maximum: 268435456
#
ERL_MAX_PORTS={{ env['ERL_MAX_PORTS'] or '32000' }}
#ERL_MAX_PORTS=32000
#.
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
@@ -48,9 +48,7 @@ ERL_MAX_PORTS={{ env['ERL_MAX_PORTS'] or '32000' }}
# Default: not defined
# Example: 4200-4210
#
{%- if env['FIREWALL_WINDOW'] %}
FIREWALL_WINDOW={{ env['FIREWALL_WINDOW'] }}
{%- endif %}
#FIREWALL_WINDOW=
#.
#' INET_DIST_INTERFACE: IP address where this Erlang node listens other nodes
@@ -58,11 +56,9 @@ FIREWALL_WINDOW={{ env['FIREWALL_WINDOW'] }}
# This communication is used by ejabberdctl command line tool,
# and in a cluster of several ejabberd nodes.
#
# Default: 0.0.0.0
# Default: 127.0.0.1
#
{%- if env['INET_DIST_INTERFACE'] %}
INET_DIST_INTERFACE={{ env['INET_DIST_INTERFACE'] }}
{%- endif %}
#INET_DIST_INTERFACE=127.0.0.1
#.
#' ERL_EPMD_ADDRESS: IP addresses where epmd listens for connections
@@ -78,9 +74,7 @@ INET_DIST_INTERFACE={{ env['INET_DIST_INTERFACE'] }}
#
# Default: 0.0.0.0
#
{%- if env['ERL_EPMD_ADDRESS'] %}
ERL_EPMD_ADDRESS={{ env['ERL_EPMD_ADDRESS'] }}
{%- endif %}
#ERL_EPMD_ADDRESS=127.0.0.1
#.
#' ERL_PROCESSES: Maximum number of Erlang processes
@@ -94,7 +88,7 @@ ERL_EPMD_ADDRESS={{ env['ERL_EPMD_ADDRESS'] }}
# Default: 250000
# Maximum: 268435456
#
ERL_PROCESSES={{ env['ERL_PROCESSES'] or '250000' }}
#ERL_PROCESSES=250000
#.
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
@@ -107,7 +101,7 @@ ERL_PROCESSES={{ env['ERL_PROCESSES'] or '250000' }}
#
# Default: 1400
#
ERL_MAX_ETS_TABLES={{ env['ERL_MAX_ETS_TABLES'] or '1400' }}
#ERL_MAX_ETS_TABLES=1400
#.
#' ERL_OPTIONS: Additional Erlang options
@@ -122,7 +116,7 @@ ERL_MAX_ETS_TABLES={{ env['ERL_MAX_ETS_TABLES'] or '1400' }}
#
# Default: ""
#
ERL_OPTIONS="{{ env['ERL_OPTIONS'] or '-noshell' }}"
ERL_OPTIONS="{{ env['ERL_OPTIONS'] or "-noshell" }}"
#.
#' ERLANG_NODE: Erlang node name
@@ -140,7 +134,7 @@ ERL_OPTIONS="{{ env['ERL_OPTIONS'] or '-noshell' }}"
#
# Default: ejabberd@localhost
#
ERLANG_NODE={{ env['ERLANG_NODE'] or 'ejabberd@localhost' }}
ERLANG_NODE={{ env['ERLANG_NODE'] or "ejabberd@localhost" }}
#.
#' EJABBERD_PID_PATH: ejabberd PID file
@@ -163,7 +157,7 @@ ERLANG_NODE={{ env['ERLANG_NODE'] or 'ejabberd@localhost' }}
#
# Default: $ETC_DIR/ejabberd.yml
#
EJABBERD_CONFIG_PATH={{ env['EJABBERD_CONFIG_PATH'] or '/opt/ejabberd/conf/ejabberd.yml' }}
#EJABBERD_CONFIG_PATH=/etc/ejabberd/ejabberd.yml
#.
#' CONTRIB_MODULES_PATH: contributed ejabberd modules path
@@ -173,19 +167,7 @@ EJABBERD_CONFIG_PATH={{ env['EJABBERD_CONFIG_PATH'] or '/opt/ejabberd/conf/ejabb
#
# Default: $HOME/.ejabberd-modules
#
CONTRIB_MODULES_PATH={{ env['CONTRIB_MODULES_PATH'] or '/opt/ejabberd/modules' }}
#.
#' CONTRIB_MODULES_CONF_DIR: configuration directory for contributed modules
#
# Specify the full path to the configuration directory for contributed ejabberd
# modules. In order to configure a module named mod_foo, a mod_foo.yml file can
# be created in this directory. This file will then be used instead of the
# default configuration file provided with the module.
#
# Default: $CONTRIB_MODULES_PATH/conf
#
CONTRIB_MODULES_CONF_DIR={{ env['CONTRIB_MODULES_CONF_DIR'] or '/opt/ejabberd/modules/conf' }}
#CONTRIB_MODULES_PATH=/opt/ejabberd-modules
#.
#' EJABBERD_BYPASS_WARNINGS: Bypass LIVE warning
@@ -195,5 +177,11 @@ CONTRIB_MODULES_CONF_DIR={{ env['CONTRIB_MODULES_CONF_DIR'] or '/opt/ejabberd/mo
EJABBERD_BYPASS_WARNINGS=true
#.
#'
# vim: foldmarker=#',#. foldmethod=marker:
#' SPOOL_DIR: Database spool dir
#
# Specify the full path to the database spool dir used in binary installer for
# backwards compatibility.
#
# Docker: rroemhild/ejabberd
#
SPOOL_DIR=$EJABBERD_HOME/database/$ERLANG_NODE
+3
View File
@@ -0,0 +1,3 @@
{lookup,["file","native"]}.
{host,{127,0,0,1}, ["localhost","hostalias"]}.
{file, resolv, "/etc/resolv.conf"}.
-22
View File
@@ -1,22 +0,0 @@
readonly HOSTIP=$(hostname -i)
readonly HOSTNAME=$(hostname -f)
readonly DOMAINNAME=$(hostname -d)
readonly DOCKER_LIB="${EJABBERD_HOME}/docker/lib"
readonly ERLANGCOOKIEFILE="${EJABBERD_HOME}/.erlang.cookie"
readonly EJABBERDCTL="/sbin/ejabberdctl"
readonly CONFIGDIR="${EJABBERD_HOME}/conf"
readonly CONFIGTMPDIR="${EJABBERD_HOME}/docker/conf"
readonly SSLCERTDIR="${EJABBERD_HOME}/ssl"
readonly SSLCERTHOST="${SSLCERTDIR}/host.pem"
readonly LOGDIR="/var/log/ejabberd"
readonly FIRST_START_DONE_FILE="${EJABBERD_HOME}/first-start-done"
readonly CLUSTER_NODE_FILE="${EJABBERD_HOME}/cluster-done"
readonly PYTHON_JINJA2="import os;
import sys;
import jinja2;
sys.stdout.write(
jinja2.Template
(sys.stdin.read()
).render(env=os.environ))"
-72
View File
@@ -1,72 +0,0 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
# Do not exit if users already registered
set +e
randpw() {
< /dev/urandom tr -dc A-Z-a-z-0-9 | head -c ${1:-16};
echo;
}
register_user() {
local user=$1
local domain=$2
local password=$3
${EJABBERDCTL} register ${user} ${domain} ${password}
return $?
}
register_all_users() {
# register users from environment $EJABBERD_USERS with given
# password or random password written to stout. Use whitespace
# to seperate users.
#
# sample:
# - add a user with an given password:
# -e "EJABBERD_USERS=admin@example.com:adminSecret"
# - add a user with a random password:
# -e "EJABBERD_USERS=user@example.com"
# - set password for admin and use random for user1:
# -e "EJABBERD_USERS=admin@example.com:adminSecret user@example.com"
for user in ${EJABBERD_USERS} ; do
local jid=${user%%:*}
local password=${user#*:}
local username=${jid%%@*}
local domain=${jid#*@}
[[ "${password}" == "${jid}" ]] \
&& password=$(randpw)
register_user ${username} ${domain} ${password}
local retval=$?
[[ ${retval} -eq 0 ]] \
&& log "Password for user ${username}@${domain} is ${password}"
done
}
file_exist ${FIRST_START_DONE_FILE} \
&& exit 0
file_exist ${CLUSTER_NODE_FILE} \
&& exit 0
is_set ${EJABBERD_USERS} \
&& register_all_users
exit 0
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
set -e
# Write a first-start-done file
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
if [ ! -e "${FIRST_START_DONE_FILE}" ]; then
touch ${FIRST_START_DONE_FILE}
fi
exit 0
-22
View File
@@ -1,22 +0,0 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
make_dhparam() {
local dhfile=$1
local bits=$2
log "Writing dh file to '${dhfile}'..."
openssl dhparam -out ${dhfile} ${bits}
}
if is_true ${EJABBERD_DHPARAM} ; then
file_exist ${SSLDHPARAM} \
|| make_dhparam ${SSLDHPARAM} 4096
fi
exit 0
-36
View File
@@ -1,36 +0,0 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
make_config() {
local filename=$1
local template="${CONFIGTMPDIR}/${filename}.tpl"
local configfile="${CONFIGDIR}/${filename}"
file_exist $configfile \
&& return 1
if [ ! -e ${configfile} ]; then
log "Generating ${configfile} config file..."
cat $template \
| python -c "${PYTHON_JINJA2}" \
> $configfile
else
echo "File ${configfile} exists."
fi
}
# /opt/ejabberd/conf/ejabberd.yml
make_config "ejabberd.yml"
# /opt/ejabberd/conf/ejabberdctl.cfg
make_config "ejabberdctl.cfg"
exit 0
Executable
+99
View File
@@ -0,0 +1,99 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
# discover hostname
readonly nodename=$(get_nodename)
is_zero ${ERLANG_NODE} \
&& export ERLANG_NODE="ejabberd@localhost"
## backward compatibility
# if ERLANG_NODE is true reset it to "ejabberd" and add
# hostname to the nodename.
# else: export ${ERLANG_NODE} with nodename
if (is_true ${ERLANG_NODE}); then
export ERLANG_NODE="ejabberd@${nodename}"
fi
run_scripts() {
local run_script_dir="${EJABBERD_HOME}/scripts/${1}"
for script in ${run_script_dir}/*.sh ; do
if [ -f ${script} -a -x ${script} ] ; then
${script}
fi
done
}
pre_scripts() {
run_scripts "pre"
}
post_scripts() {
run_scripts "post"
}
stop_scripts() {
run_scripts "stop"
}
ctl() {
local action="$1"
${EJABBERDCTL} ${action} >/dev/null
}
_trap() {
echo "Stopping ejabberd..."
stop_scripts
if ctl stop ; then
local cnt=0
sleep 1
while ctl status || test $? = 1 ; do
cnt=`expr $cnt + 1`
if [ $cnt -ge 60 ] ; then
break
fi
sleep 1
done
fi
}
# Catch signals and shutdown ejabberd
trap _trap SIGTERM SIGINT
## run ejabberd
case "$@" in
start)
pre_scripts
tail -n 0 -F ${LOGDIR}/crash.log \
${LOGDIR}/error.log \
${LOGDIR}/erlang.log &
echo "Starting ejabberd..."
exec ${EJABBERDCTL} "foreground" &
child=$!
${EJABBERDCTL} "started"
post_scripts
wait $child
;;
live)
pre_scripts
echo "Starting ejabberd in 'live' mode..."
exec ${EJABBERDCTL} "live"
;;
shell)
exec "/bin/bash"
;;
*)
exec $@
;;
esac
+53
View File
@@ -0,0 +1,53 @@
readonly HOSTIP=$(hostname -i)
readonly HOSTNAME=$(hostname -f)
readonly DOMAINNAME=$(hostname -d)
readonly ERLANGCOOKIEFILE="${EJABBERD_HOME}/.erlang.cookie"
readonly EJABBERDCTL="/sbin/ejabberdctl"
readonly CONFIGFILE="${EJABBERD_HOME}/conf/ejabberd.yml"
readonly CONFIGTEMPLATE="${EJABBERD_HOME}/conf/ejabberd.yml.tpl"
readonly CTLCONFIGFILE="${EJABBERD_HOME}/conf/ejabberdctl.cfg"
readonly CTLCONFIGTEMPLATE="${EJABBERD_HOME}/conf/ejabberdctl.cfg.tpl"
readonly SSLCERTDIR="${EJABBERD_HOME}/ssl"
readonly SSLCERTHOST="${SSLCERTDIR}/host.pem"
readonly SSLDHPARAM="${SSLCERTDIR}/dh.pem"
readonly LOGDIR="/var/log/ejabberd"
readonly FIRST_START_DONE_FILE="/${EJABBERD_HOME}/first-start-done"
readonly CLUSTER_NODE_FILE="/${EJABBERD_HOME}/cluster-done"
readonly PYTHON_JINJA2="import os;
import sys;
import jinja2;
sys.stdout.write(
jinja2.Template
(sys.stdin.read()
).render(env=os.environ))"
# backward compatibility environment variables
set +e
[[ -n $EJABBERD_ADMIN ]] \
&& export EJABBERD_ADMINS=${EJABBERD_ADMIN}
[[ -n $AUTH_METHOD ]] \
&& export EJABBERD_AUTH_METHOD=${AUTH_METHOD}
[[ -n $SKIP_MODULES_UPDATE ]] \
&& export EJABBERD_SKIP_MODULES_UPDATE=${SKIP_MODULES_UPDATE}
[[ -n $ERL_OPTIONS ]] \
&& export ERLANG_OPTIONS=${ERL_OPTIONS}
[[ -n $SSLCERT_HOST ]] \
&& export EJABBERD_SSLCERT_HOST=${SSLCERT_HOST}
[[ -n $SSLCERT_EXAMPLE_COM ]] \
&& export EJABBERD_SSLCERT_EXAMPLE_COM=${SSLCERT_EXAMPLE_COM}
[[ -n $LOGLEVEL ]] \
&& export EJABBERD_LOGLEVEL=${LOGLEVEL}
[[ -n $EJABBERD_WEB_ADMIN_SSL ]] \
&& export EJABBERD_HTTPS=${EJABBERD_WEB_ADMIN_SSL}
set -e
@@ -29,16 +29,10 @@ is_true() {
}
log() {
local message=$1
echo $message
}
# overwrite this function to get hostname from other sources
# like dns or etcd
get_nodename() {
log ${HOSTNAME}
echo ${HOSTNAME}
}
@@ -48,25 +42,25 @@ join_cluster() {
is_zero ${cluster_node} \
&& exit 0
log "Join cluster..."
echo "Join cluster..."
local erlang_node_name=${ERLANG_NODE%@*}
local erlang_cluster_node="${erlang_node_name}@${cluster_node}"
response=$(${EJABBERDCTL} ping ${erlang_cluster_node})
while [ "$response" != "pong" ]; do
log "Waiting for ${erlang_cluster_node}..."
echo "Waiting for ${erlang_cluster_node}..."
sleep 2
response=$(${EJABBERDCTL} ping ${erlang_cluster_node})
done
log "Join cluster at ${erlang_cluster_node}... "
echo "Join cluster at ${erlang_cluster_node}... "
NO_WARNINGS=true ${EJABBERDCTL} join_cluster $erlang_cluster_node
if [ $? -eq 0 ]; then
touch ${CLUSTER_NODE_FILE}
else
log "cloud not join cluster"
echo "cloud not join cluster"
exit 1
fi
}
@@ -3,14 +3,14 @@ set -e
# Updates the known modules as to be found in https://github.com/processone/ejabberd-contrib
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
run_modules_update_specs() {
log "Updating module specs... "
echo -n 'Updating module specs... '
${EJABBERDCTL} modules_update_specs
}
@@ -3,55 +3,54 @@ set -e
# Installs modules as defined in environment variables
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
install_module_from_source() {
local module_name=$1
local module_source_path=${EJABBERD_HOME}/module_source/${module_name}
local module_install_folder=${EJABBERD_HOME}/.ejabberd-modules/sources/${module_name}
log "Analyzing module ${module_name} for installation"
local module_install_folder=${EJABBERD_HOME}/.ejabberd-modules/sources
echo "Analyzing module ${module_name} for installation"
# Make sure that the module exists in the source folder before attempting a copy
if [ ! -d ${module_source_path} ]; then
log "Error: Module ${module_name} not found in ${EJABBERD_HOME}/module_source"
log "Please use a shared volume to populate your module in ${EJABBERD_HOME}/module_source"
echo "Error: Module ${module_name} not found in ${EJABBERD_HOME}/module_source"
echo "Please use a shared volume to populate your module in ${EJABBERD_HOME}/module_source"
return 1;
fi
# Check to see if the module is already installed
local install_count=$(${EJABBERDCTL} modules_installed | grep -ce "^${module_name}[[:space:]]")
if [ $install_count -gt 0 ]; then
log "Error: Module already installed: ${module_name}"
echo "Error: Module already installed: ${module_name}"
return 1;
fi
# Copy the module into the shared folder
log "Copying module to ejabberd folder ${module_install_folder}"
echo "Copying module to ejabberd folder ${module_install_folder}"
mkdir -p ${module_install_folder}
cp -R ${module_source_path} ${module_install_folder}
# Run the ejabberdctl module_check on the module
log "Running module_check on ${module_name}"
echo "Running module_check on ${module_name}"
${EJABBERDCTL} module_check ${module_name}
if [ $? -ne 0 ]; then
log "Module check failed for ${module_name}"
echo "Module check failed for ${module_name}"
return 1;
fi
log "Module check succeeded for ${module_name}"
echo "Module check succeeded for ${module_name}"
# Install the module
log "Running module_install on ${module_name}"
echo "Running module_install on ${module_name}"
${EJABBERDCTL} module_install ${module_name}
if [ $? -ne 0 ]; then
log "Module installation failed for ${module_name}"
echo "Module installation failed for ${module_name}"
return 1;
fi
log "Module installation succeeded for ${module_name}"
echo "Module installation succeeded for ${module_name}"
return 0;
}
@@ -62,18 +61,18 @@ install_module_from_ejabberd_contrib() {
# Check to see if the module is already installed
local install_count=$(${EJABBERDCTL} modules_installed | grep -ce "^${module_name}[[:space:]]")
if [ $install_count -gt 0 ]; then
log "Error: Module already installed: ejabberd_contrib ${module_name}"
echo "Error: Module already installed: ejabberd_contrib ${module_name}"
return 1;
fi
# Install the module
log "Running module_install on ejabberd_contrib ${module_name}"
echo "Running module_install on ejabberd_contrib ${module_name}"
${EJABBERDCTL} module_install ${module_name}
if [ $? -ne 0 ]; then
log "Module installation failed for ejabberd_contrib ${module_name}"
echo "Module installation failed for ejabberd_contrib ${module_name}"
return 1;
fi
log "Module installation succeeded for ejabberd_contrib ${module_name}"
echo "Module installation succeeded for ejabberd_contrib ${module_name}"
return 0;
}
@@ -86,21 +85,21 @@ enable_custom_auth_module_override() {
required_prefix="ejabberd_auth_"
if [[ "${module_name}" != "${required_prefix}"* ]]; then
log "Error: module_name must begin with ${required_prefix}"
echo "Error: module_name must begin with ${required_prefix}"
exit 1;
fi
log "Checking custom auth module: ${module_name}"
echo "Checking custom auth module: ${module_name}"
# Make sure the auth module is installed
local install_count=$(${EJABBERDCTL} modules_installed | grep -ce "^${module_name}[[:space:]]")
if [ $install_count -eq 0 ]; then
log "Error: custom auth_module not installed: ${module_name}"
echo "Error: custom auth_module not installed: ${module_name}"
return 1;
fi
custom_auth_method=${module_name#$required_prefix}
echo -e "\nauth_method: [${custom_auth_method}]" >> ${CONFIGFILE}
log "Custom auth module ${module_name} configuration complete."
echo "Custom auth module ${module_name} configuration complete."
}
file_exist ${FIRST_START_DONE_FILE} \
@@ -133,7 +132,7 @@ fi
# If any modules were installed, restart the server, if the option is enabled
if [ ${is_restart_needed} -eq 1 ]; then
if is_true ${EJABBERD_RESTART_AFTER_MODULE_INSTALL} ; then
log "Restarting ejabberd after successful module installation(s)"
echo "Restarting ejabberd after successful module installation(s)"
${EJABBERDCTL} restart
child=$!
${EJABBERDCTL} "started"
+118
View File
@@ -0,0 +1,118 @@
#!/bin/bash
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
# Do not exit if users already registered
set +e
randpw() {
< /dev/urandom tr -dc A-Z-a-z-0-9 | head -c ${1:-16};
echo;
}
register_user() {
local user=$1
local domain=$2
local password=$3
${EJABBERDCTL} register ${user} ${domain} ${password}
return $?
}
register_all_users() {
# register users from environment $EJABBERD_USERS with given
# password or random password written to stout. Use whitespace
# to seperate users.
#
# sample:
# - add a user with an given password:
# -e "EJABBERD_USERS=admin@example.com:adminSecret"
# - add a user with a random password:
# -e "EJABBERD_USERS=user@example.com"
# - set password for admin and use random for user1:
# -e "EJABBERD_USERS=admin@example.com:adminSecret user@example.com"
for user in ${EJABBERD_USERS} ; do
local jid=${user%%:*}
local password=${user#*:}
local username=${jid%%@*}
local domain=${jid#*@}
[[ "${password}" == "${jid}" ]] \
&& password=$(randpw)
register_user ${username} ${domain} ${password}
local retval=$?
[[ ${retval} -eq 0 ]] \
&& echo "Password for user ${username}@${domain} is ${password}"
done
}
file_exist ${FIRST_START_DONE_FILE} \
&& exit 0
file_exist ${CLUSTER_NODE_FILE} \
&& exit 0
is_set ${EJABBERD_USERS} \
&& register_all_users
##################################
## Keep for backward compatibility
register_all_ejabberd_admins() {
# add all admins from environment $EJABBERD_ADMINS with the passwords from
# environment $EJABBERD_ADMIN_PASS.
local passwords
local IFS=' '
read -a passwords <<< "${EJABBERD_ADMIN_PWD}"
for admin in ${EJABBERD_ADMINS} ; do
local user=${admin%%@*}
local domain=${admin#*@}
local password=${passwords[0]}
passwords=("${passwords[@]:1}")
register_user ${user} ${domain} ${password}
done
}
register_all_ejabberd_admins_randpw() {
# add all admins from environment $EJABBERD_ADMINS with a random
# password and write the password to stdout.
for admin in ${EJABBERD_ADMINS} ; do
local user=${admin%%@*}
local domain=${admin#*@}
local password=$(randpw)
register_user ${user} ${domain} ${password}
local retval=$?
[[ ${retval} -eq 0 ]] \
&& echo "Password for user ${user}@${domain} is ${password}"
done
}
is_set ${EJABBERD_ADMIN_PWD} \
&& register_all_ejabberd_admins
is_true ${EJABBERD_ADMIN_RANDPWD} \
&& register_all_ejabberd_admins_randpw
exit 0
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
set -e
# Write a first-start-done file
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
if [ ! -e "${FIRST_START_DONE_FILE}" ]; then
touch ${FIRST_START_DONE_FILE}
fi
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
readonly whoami=$(whoami)
change_ejabberd_run_user() {
echo "Change ejabberd install user to root..."
sed -i "s/INSTALLUSER=${EJABBERD_USER}/INSTALLUSER=${whoami}/" ${EJABBERDCTL}
}
[[ "${whoami}" == "root" ]] \
&& change_ejabberd_run_user
exit 0
@@ -1,10 +1,10 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
# Instead of having to mount a direction, specify the ssl certs
# via environment variables:
@@ -12,9 +12,9 @@ source "${EJABBERD_HOME}/docker/lib/functions.sh"
# For example: `EJABBERD_SSLCERT_EXAMPLE_COM`.
write_file_from_env() {
log "Writing $1 to $2"
echo "Writing $1 to $2"
mkdir -p "$(dirname $2)"
log "${!1}" > $2
echo "${!1}" > $2
}
# Write the host certificate
@@ -30,5 +30,4 @@ for xmpp_domain in ${XMPP_DOMAIN} ; do
fi
done
exit 0
@@ -1,10 +1,10 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
make_snakeoil_certificate() {
@@ -20,7 +20,7 @@ make_snakeoil_certificate() {
-keyout /tmp/selfsigned.key \
-out /tmp/selfsigned.crt
log "Writing ssl cert and private key to '${certfile}'..."
echo "Writing ssl cert and private key to '${certfile}'..."
cat /tmp/selfsigned.crt /tmp/selfsigned.key > ${certfile}
rm /tmp/selfsigned.crt /tmp/selfsigned.key
}
@@ -43,7 +43,8 @@ make_host_snakeoil_certificate() {
fi
fi
log "Generating snakeoil ssl cert for ${domain}..."
echo -n "Missing ssl cert for your host. "
echo "Generating snakeoil ssl cert for ${domain}..."
make_snakeoil_certificate ${domain} ${SSLCERTHOST}
}
@@ -53,17 +54,33 @@ make_domain_snakeoil_certificate() {
local domain=$1
local certfile=$2
log "Generating snakeoil ssl cert for ${domain}..."
echo -n "Missing ssl cert for your xmpp domain. "
echo "Generating snakeoil ssl cert for ${domain}..."
make_snakeoil_certificate ${domain} ${certfile}
}
## backward compatibility
# link old xmpp_domain.pem file to the first <domainname>.pem in XMPP_DOMAIN
readonly SSLCERTDOMAIN="${SSLCERTDIR}/xmpp_domain.pem"
if file_exist ${SSLCERTDOMAIN} ; then
for xmpp_domain in ${XMPP_DOMAIN} ; do
file_exist "${SSLCERTDIR}/${xmpp_domain}.pem" \
|| ln -s ${SSLCERTDOMAIN} "${SSLCERTDIR}/${xmpp_domain}.pem"
break
done
fi
is_true ${EJABBERD_SKIP_MAKE_SSLCERT} \
&& echo "Skip certificate generation" \
&& exit 0
# generate host ssl cert if missing
file_exist ${SSLCERTHOST} \
|| make_host_snakeoil_certificate
# generate xmmp domain ssl certificates if missing
for xmpp_domain in ${XMPP_DOMAIN} ; do
domain_certfile="${SSLCERTDIR}/${xmpp_domain}.pem"
@@ -71,5 +88,4 @@ for xmpp_domain in ${XMPP_DOMAIN} ; do
|| make_domain_snakeoil_certificate ${xmpp_domain} ${domain_certfile}
done
exit 0
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
make_dhparam() {
local dhfile=$1
local bits=$2
echo "Writing dh file to '${dhfile}'..."
openssl dhparam -out ${dhfile} ${bits}
}
is_true ${EJABBERD_SKIP_MAKE_DHPARAM} \
&& echo "Skip DH param generation" \
&& exit 0
if is_true ${EJABBERD_DHPARAM} ; then
file_exist ${SSLDHPARAM} \
|| make_dhparam ${SSLDHPARAM} 4096
fi
exit 0
@@ -1,14 +1,14 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
set_erlang_cookie() {
chmod 600 ${ERLANGCOOKIEFILE}
log "Set erlang cookie to ${ERLANG_COOKIE}..."
echo "Set erlang cookie to ${ERLANG_COOKIE}..."
echo ${ERLANG_COOKIE} > ${ERLANGCOOKIEFILE}
chmod 400 ${ERLANGCOOKIEFILE}
}
@@ -22,5 +22,4 @@ file_exist ${FIRST_START_DONE_FILE} \
is_set ${ERLANG_COOKIE} \
&& set_erlang_cookie
exit 0
+38
View File
@@ -0,0 +1,38 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
make_config() {
if [ ! -e ${CONFIGFILE} ]; then
echo "Generating ejabberd config file..."
cat ${CONFIGTEMPLATE} \
| python -c "${PYTHON_JINJA2}" \
> ${CONFIGFILE}
else
echo "ejabberd config file exists."
fi
if [ ! -e ${CTLCONFIGFILE} ]; then
echo "Generating ejabberdctl config file..."
cat ${CTLCONFIGTEMPLATE} \
| python -c "${PYTHON_JINJA2}" \
> ${CTLCONFIGFILE}
else
echo "ejabberdctl config file exists."
fi
}
file_exist ${FIRST_START_DONE_FILE} \
&& exit 0
# generate config file
make_config
exit 0
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/scripts/lib/base_config.sh"
source "${EJABBERD_HOME}/scripts/lib/config.sh"
source "${EJABBERD_HOME}/scripts/lib/base_functions.sh"
source "${EJABBERD_HOME}/scripts/lib/functions.sh"
leave_cluster() {
echo "Leave cluster... "
rm ${CLUSTER_NODE_FILE}
NO_WARNINGS=true ${EJABBERDCTL} leave_cluster
}
file_exist ${CLUSTER_NODE_FILE} \
&& leave_cluster
exit 0
-69
View File
@@ -1,69 +0,0 @@
#!/bin/bash
set -e
# Environment
export EJABBERD_HTTPS=${EJABBERD_HTTPS:-'true'}
export EJABBERD_STARTTLS=${EJABBERD_STARTTLS:-'true'}
export EJABBERD_S2S_SSL=${EJABBERD_S2S_SSL:-'true'}
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
# discover hostname
readonly nodename=$(get_nodename)
# set erlang node to node name from get_nodename
if [[ "$ERLANG_NODE" == "nodename" ]]; then
export ERLANG_NODE="ejabberd@${nodename}"
fi
run_scripts() {
local run_script=$1
local run_script_dir="${EJABBERD_HOME}/docker/${run_script}"
log "Run ${run_script} scripts..."
for script in ${run_script_dir}/*.sh ; do
if [ -f ${script} -a -x ${script} ] ; then
${script}
fi
done
}
_trap() {
run_scripts "stop"
log "Stopping ejabberd..."
$EJABBERDCTL stop
$EJABBERDCTL stopped
exit 0
}
# Catch signals and shutdown ejabberd
trap _trap SIGTERM SIGINT
# print logfiles to stdout
tail -F ${LOGDIR}/crash.log \
${LOGDIR}/error.log \
${LOGDIR}/erlang.log \
${LOGDIR}/ejabberd.log &
# start ejabberd
run_scripts "pre"
log "Starting ejabberd..."
$EJABBERDCTL start
$EJABBERDCTL started
log "Ejabberd started."
run_scripts "post"
# run forever
while true; do sleep 1; done
log "Ejabberd stopped."
exit 0
-21
View File
@@ -1,21 +0,0 @@
#!/bin/bash
set -e
source "${EJABBERD_HOME}/docker/lib/base_config.sh"
source "${EJABBERD_HOME}/docker/lib/config.sh"
source "${EJABBERD_HOME}/docker/lib/base_functions.sh"
source "${EJABBERD_HOME}/docker/lib/functions.sh"
leave_cluster() {
log "Leave cluster..."
rm ${CLUSTER_NODE_FILE}
NO_WARNINGS=true ${EJABBERDCTL} leave_cluster
}
file_exist ${CLUSTER_NODE_FILE} \
&& leave_cluster
exit 0
+1
View File
@@ -11,6 +11,7 @@ Restart=on-failure
RestartSec=5
ExecStart=/bin/sh -c '@ctlscriptpath@/ejabberdctl start && @ctlscriptpath@/ejabberdctl started'
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
PrivateDevices=true
ProtectSystem=full
+136 -27
View File
@@ -106,6 +106,17 @@ hosts:
###. ===============
###' LISTENING PORTS
## Define common macros used by listeners
## define_macro:
## 'CERTFILE': "/path/to/xmpp.pem"
## 'CIPHERS': "ECDH:DH:!3DES:!aNULL:!eNULL:!MEDIUM@STRENGTH"
## 'TLSOPTS':
## - "no_sslv3"
## - "no_tlsv1"
## - "cipher_server_preference"
## - "no_compression"
## 'DHFILE': "/path/to/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 2048
##
## listen: The ports ejabberd will listen on, which service each is handled
## by and what options to start it with.
@@ -113,36 +124,53 @@ hosts:
listen:
-
port: 5222
ip: "::"
module: ejabberd_c2s
##
## If TLS is compiled in and you installed a SSL
## certificate, specify the full path to the
## file and uncomment these lines:
##
## certfile: "/path/to/ssl.pem"
## starttls: true
## certfile: 'CERTFILE'
## protocol_options: 'TLSOPTS'
## dhfile: 'DHFILE'
## ciphers: 'CIPHERS'
##
## To enforce TLS encryption for client connections,
## use this instead of the "starttls" option:
##
## starttls_required: true
##
## Custom OpenSSL options
## Stream compression
##
## zlib: true
##
## protocol_options:
## - "no_sslv3"
## - "no_tlsv1"
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
-
port: 5280
ip: "::"
module: ejabberd_http
request_handlers:
"/ws": ejabberd_http_ws
"/bosh": mod_bosh
"/api": mod_http_api
## "/pub/archive": mod_http_fileserver
web_admin: true
## register: true
captcha: true
##
## ejabberd_service: Interact with external components (transports, ...)
##
## -
## port: 8888
## ip: "::"
## module: ejabberd_service
## access: all
## shaper_rule: fast
@@ -175,39 +203,47 @@ listen:
##
## -
## port: 4560
## ip: "::"
## module: ejabberd_xmlrpc
## access_commands: {}
-
port: 5280
module: ejabberd_http
request_handlers:
"/websocket": ejabberd_http_ws
## "/pub/archive": mod_http_fileserver
web_admin: true
http_bind: true
## register: true
captcha: true
##
## To enable secure http upload
##
## -
## port: 5444
## ip: "::"
## module: ejabberd_http
## request_handlers:
## "": mod_http_upload
## tls: true
## certfile: 'CERTFILE'
## protocol_options: 'TLSOPTS'
## dhfile: 'DHFILE'
## ciphers: 'CIPHERS'
## Disabling digest-md5 SASL authentication. digest-md5 requires plain-text
## password storage (see auth_password_format option).
## disable_sasl_mechanisms: "digest-md5"
###. ==================
###' S2S GLOBAL OPTIONS
##
## s2s_use_starttls: Enable STARTTLS + Dialback for S2S connections.
## s2s_use_starttls: Enable STARTTLS for S2S connections.
## Allowed values are: false optional required required_trusted
## You must specify a certificate file.
##
## s2s_use_starttls: optional
## s2s_use_starttls: required
##
## s2s_certfile: Specify a certificate file.
##
## s2s_certfile: "/path/to/ssl.pem"
## s2s_certfile: 'CERTFILE'
## Custom OpenSSL options
##
## s2s_protocol_options:
## - "no_sslv3"
## - "no_tlsv1"
## s2s_protocol_options: 'TLSOPTS'
##
## domain_certfile: Specify a different certificate for each served hostname.
@@ -229,12 +265,12 @@ listen:
## Outgoing S2S options
##
## Preferred address families (which to try first) and connect timeout
## in milliseconds.
## in seconds.
##
## outgoing_s2s_families:
## - ipv4
## - ipv6
## outgoing_s2s_timeout: 10000
## outgoing_s2s_timeout: 190
###. ==============
###' AUTHENTICATION
@@ -451,6 +487,8 @@ acl:
loopback:
ip:
- "127.0.0.0/8"
- "::1/128"
- "::FFFF:127.0.0.1/128"
##
## Bad XMPP servers
@@ -517,6 +555,7 @@ access_rules:
trusted_network:
- allow: loopback
## Do not establish S2S connections with bad servers
## If you enable this you also have to uncomment "s2s_access: s2s"
## s2s:
## - deny:
## - ip: "XXX.XXX.XXX.XXX/32"
@@ -524,6 +563,53 @@ access_rules:
## - ip: "XXX.XXX.XXX.XXX/32"
## - allow
## ===============
## API PERMISSIONS
## ===============
##
## This section allows you to define who and using what method
## can execute commands offered by ejabberd.
##
## By default "console commands" section allow executing all commands
## issued using ejabberdctl command, and "admin access" section allows
## users in admin acl that connect from 127.0.0.1 to execute all
## commands except start and stop with any available access method
## (ejabberdctl, http-api, xmlrpc depending what is enabled on server).
##
## If you remove "console commands" there will be one added by
## default allowing executing all commands, but if you just change
## permissions in it, version from config file will be used instead
## of default one.
##
api_permissions:
"console commands":
from:
- ejabberd_ctl
who: all
what: "*"
"admin access":
who:
- access:
- allow:
- acl: loopback
- acl: admin
- oauth:
- scope: "ejabberd:admin"
- access:
- allow:
- acl: loopback
- acl: admin
what:
- "*"
- "!stop"
- "!start"
"public commands":
who:
- ip: "127.0.0.1/8"
what:
- "status"
- "connected_users_number"
## 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
@@ -581,7 +667,7 @@ language: "en"
##
modules:
mod_adhoc: {}
## mod_admin_extra: {}
mod_admin_extra: {}
mod_announce: # recommends mod_adhoc
access: announce
mod_blocking: {} # requires mod_privacy
@@ -589,15 +675,25 @@ modules:
mod_carboncopy: {}
mod_client_state: {}
mod_configure: {} # requires mod_adhoc
##mod_delegation: {} # for xep0356
## mod_delegation: {} # for xep0356
mod_disco: {}
## mod_echo: {}
mod_echo: {}
mod_irc: {}
mod_http_bind: {}
mod_bosh: {}
## mod_http_fileserver:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
## mod_http_upload:
## # docroot: "@HOME@/upload"
## put_url: "https://@HOST@:5444"
## thumbnail: false # otherwise needs the identify command from ImageMagick installed
## mod_http_upload_quota:
## max_days: 30
mod_last: {}
## XEP-0313: Message Archive Management
## You might want to setup a SQL backend for MAM because the mnesia database is
## limited to 2GB which might be exceeded on large servers
## mod_mam: {} # for xep0313, mnesia is limited to 2GB, better use an SQL backend
mod_muc:
## host: "conference.@HOST@"
access:
@@ -606,6 +702,7 @@ modules:
- allow: admin
access_create: muc_create
access_persistent: muc_create
mod_muc_admin: {}
## mod_muc_log: {}
## mod_multicast: {}
mod_offline:
@@ -668,6 +765,18 @@ modules:
mod_vcard:
search: false
mod_version: {}
mod_stream_mgmt: {}
## Non-SASL Authentication (XEP-0078) is now disabled by default
## because it's obsoleted and is used mostly by abandoned
## client software
## mod_legacy_auth: {}
## The module for S2S dialback (XEP-0220). Please note that you cannot
## rely solely on dialback if you want to federate with other servers,
## because a lot of servers have dialback disabled and instead rely on
## PKIX authentication. Make sure you have proper certificates installed
## and check your accessibility at https://xmpp.net/
mod_s2s_dialback: {}
mod_http_api: {}
##
## Enable modules with custom options in a specific virtual host
+142 -278
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# define default configuration
POLL=true
@@ -10,135 +10,84 @@ FIREWALL_WINDOW=""
ERLANG_NODE=ejabberd@localhost
# define default environment variables
SCRIPT_DIR=`cd ${0%/*} && pwd`
ERL={{erl}}
IEX={{bindir}}/iex
EPMD={{epmd}}
ERL="{{erl}}"
IEX="{{bindir}}/iex"
EPMD="{{epmd}}"
INSTALLUSER={{installuser}}
ERL_LIBS={{libdir}}
# check the proper system user is used if defined
if [ "$INSTALLUSER" != "" ] ; then
EXEC_CMD="false"
for GID in `id -G`; do
if [ $GID -eq 0 ] ; then
INSTALLUSER_HOME=$(getent passwd "$INSTALLUSER" | cut -d: -f6)
if [ -n "$INSTALLUSER_HOME" ] && [ ! -d "$INSTALLUSER_HOME" ] ; then
mkdir -p "$INSTALLUSER_HOME"
chown "$INSTALLUSER" "$INSTALLUSER_HOME"
fi
EXEC_CMD="su $INSTALLUSER -c"
fi
done
if [ `id -g` -eq `id -g $INSTALLUSER` ] ; then
EXEC_CMD="bash -c"
fi
if [ "$EXEC_CMD" = "false" ] ; then
echo "This command can only be run by root or the user $INSTALLUSER" >&2
exit 4
EXEC_CMD="false"
if [ -n "$INSTALLUSER" ] ; then
if [ $(id -g) -eq $(id -g $INSTALLUSER || echo -1) ] ; then
EXEC_CMD="as_current_user"
else
id -Gn | grep -q wheel && EXEC_CMD="as_install_user"
fi
else
EXEC_CMD="bash -c"
EXEC_CMD="as_current_user"
fi
if [ "$EXEC_CMD" = "false" ] ; then
echo "ERROR: This command can only be run by root or the user $INSTALLUSER" >&2
exit 7
fi
# parse command line parameters
declare -a ARGS=()
while [ $# -ne 0 ] ; do
PARAM="$1"
shift
case $PARAM in
--) break ;;
--no-timeout) EJABBERD_NO_TIMEOUT="--no-timeout" ;;
--node) ERLANG_NODE_ARG=$1 ; shift ;;
--config-dir) ETC_DIR="$1" ; shift ;;
--config) EJABBERD_CONFIG_PATH="$1" ; shift ;;
--ctl-config) EJABBERDCTL_CONFIG_PATH="$1" ; shift ;;
--logs) LOGS_DIR="$1" ; shift ;;
--spool) SPOOL_DIR="$1" ; shift ;;
*) ARGS=("${ARGS[@]}" "$PARAM") ;;
for arg; do
case $1 in
-n|--node) ERLANG_NODE_ARG=$2; shift;;
-s|--spool) SPOOL_DIR=$2; shift;;
-l|--logs) LOGS_DIR=$2; shift;;
-f|--config) EJABBERD_CONFIG_PATH=$2; shift;;
-c|--ctl-config) EJABBERDCTL_CONFIG_PATH=$2; shift;;
-d|--config-dir) ETC_DIR=$2; shift;;
-t|--no-timeout) NO_TIMEOUT="--no-timeout";;
--) :;;
*) break;;
esac
shift
done
# Define ejabberd variable if they have not been defined from the command line
if [ "$ETC_DIR" = "" ] ; then
ETC_DIR={{sysconfdir}}/ejabberd
fi
if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then
EJABBERDCTL_CONFIG_PATH=$ETC_DIR/ejabberdctl.cfg
fi
if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then
. "$EJABBERDCTL_CONFIG_PATH"
fi
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
EJABBERD_CONFIG_PATH=$ETC_DIR/ejabberd.yml
fi
if [ "$LOGS_DIR" = "" ] ; then
LOGS_DIR={{localstatedir}}/log/ejabberd
fi
if [ "$SPOOL_DIR" = "" ] ; then
SPOOL_DIR={{localstatedir}}/lib/ejabberd
fi
if [ "$EJABBERD_DOC_PATH" = "" ] ; then
EJABBERD_DOC_PATH={{docdir}}
fi
if [ "$ERLANG_NODE_ARG" != "" ] ; then
ERLANG_NODE=$ERLANG_NODE_ARG
fi
if [ "{{release}}" != "true" -a "$EJABBERD_BIN_PATH" = "" ] ; then
EJABBERD_BIN_PATH={{libdir}}/ejabberd/priv/bin
fi
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
DATETIME=`date "+%Y%m%d-%H%M%S"`
ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump
ERL_INETRC=$ETC_DIR/inetrc
# define ejabberd variables if not already defined from the command line
: ${ETC_DIR:={{sysconfdir}}/ejabberd}
: ${LOGS_DIR:={{localstatedir}}/log/ejabberd}
: ${SPOOL_DIR:={{localstatedir}}/lib/ejabberd}
: ${EJABBERD_CONFIG_PATH:="$ETC_DIR"/ejabberd.yml}
: ${EJABBERDCTL_CONFIG_PATH:="$ETC_DIR"/ejabberdctl.cfg}
[ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
[ "$ERLANG_NODE_ARG" != "" ] && ERLANG_NODE=$ERLANG_NODE_ARG
[ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] && S="-s"
: ${EJABBERD_DOC_PATH:={{docdir}}}
: ${EJABBERD_LOG_PATH:="$LOGS_DIR"/ejabberd.log}
# define mnesia options
MNESIA_OPTS="-mnesia dir \"\\\"$SPOOL_DIR\\\"\" $MNESIA_OPTIONS"
# define erl parameters
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
KERNEL_OPTS=""
if [ "$FIREWALL_WINDOW" != "" ] ; then
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
ERLANG_OPTS="$ERLANG_OPTS -kernel " \
"inet_dist_listen_min ${FIREWALL_WINDOW%-*} " \
"inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
fi
if [ "$INET_DIST_INTERFACE" != "" ] ; then
INET_DIST_INTERFACE2="$(echo $INET_DIST_INTERFACE | sed 's/\./,/g')"
if [ "$INET_DIST_INTERFACE" != "$INET_DIST_INTERFACE2" ] ; then
INET_DIST_INTERFACE2="{$INET_DIST_INTERFACE2}"
INET_DIST_INTERFACE2=$("$ERL" -noshell -eval 'case inet:parse_address("'$INET_DIST_INTERFACE'") of {ok,IP} -> io:format("~p",[IP]); _ -> ok end.' -s erlang halt)
if [ "$INET_DIST_INTERFACE2" != "" ] ; then
ERLANG_OPTS="$ERLANG_OPTS -kernel inet_dist_use_interface \"$INET_DIST_INTERFACE2\""
fi
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${INET_DIST_INTERFACE2}\""
fi
if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then
NAME="-sname"
else
NAME="-name"
fi
IEXNAME="-$NAME"
ERL_LIBS={{libdir}}
ERL_CRASH_DUMP="$LOGS_DIR"/erl_crash_$(date "+%Y%m%d-%H%M%S").dump
ERL_INETRC="$ETC_DIR"/inetrc
# define ejabberd environment parameters
if [ "$EJABBERD_CONFIG_PATH" != "${EJABBERD_CONFIG_PATH%.yml}" ] ; then
rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH)
rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH)
count=$(sed '/^[ ]*log_rotate_count/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH)
date=$(sed '/^[ ]*log_rotate_date/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH)
else
rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
count=$(sed '/^[ ]*log_rotate_count/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
date=$(sed '/^[ ]*log_rotate_date/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
fi
[ -z "$rate" ] || EJABBERD_OPTS="log_rate_limit $rate"
[ -z "$rotate" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_size $rotate"
[ -z "$count" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_count $count"
[ -z "$date" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_date '$date'"
[ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd ${EJABBERD_OPTS}"
[ -d "$SPOOL_DIR" ] || $EXEC_CMD "mkdir -p $SPOOL_DIR"
cd "$SPOOL_DIR"
# define ejabberd parameters
EJABBERD_OPTS="$EJABBERD_OPTS\
$(sed '/^log_rate_limit/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
$(sed '/^log_rotate_size/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
$(sed '/^log_rotate_count/!d;s/:[ \t]*\([0-9]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")\
$(sed '/^log_rotate_date/!d;s/:[ \t]*\(.[^ ]*\).*/ \1/;s/^/ /' "$EJABBERD_CONFIG_PATH")"
[ -n "$EJABBERD_OPTS" ] && EJABBERD_OPTS="-ejabberd $EJABBERD_OPTS"
EJABBERD_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS $EJABBERD_OPTS -s ejabberd"
# export global variables
export EJABBERD_CONFIG_PATH
export EJABBERD_LOG_PATH
export EJABBERD_BIN_PATH
export EJABBERD_DOC_PATH
export EJABBERD_PID_PATH
export ERL_CRASH_DUMP
@@ -150,116 +99,26 @@ export CONTRIB_MODULES_PATH
export CONTRIB_MODULES_CONF_DIR
export ERL_LIBS
shell_escape_str()
# run command either directly or via su $INSTALLUSER
exec_cmd()
{
if test $# -eq 0; then
printf '"" '
else
shell_escape "$@"
fi
}
shell_escape()
{
local RES=()
for i in "$@"; do
if test -z "$i"; then
printf '"" '
else
printf '%q ' "$i"
fi
done
}
# start server
start()
{
check_start
CMD="`shell_escape \"$ERL\" \"$NAME\" \"$ERLANG_NODE\"` \
-noinput -detached \
$MNESIA_OPTS \
$KERNEL_OPTS \
$EJABBERD_OPTS \
-s ejabberd \
$ERLANG_OPTS \
`shell_escape \"${ARGS[@]}\" \"$@\"`"
$EXEC_CMD "$CMD"
}
# attach to server
debug()
{
debugwarning
NID=$(uid debug)
CMD="`shell_escape \"$ERL\" \"$NAME\" \"$NID\"` \
-remsh $ERLANG_NODE \
-hidden \
$KERNEL_OPTS \
$ERLANG_OPTS \
`shell_escape \"${ARGS[@]}\" \"$@\"`"
$EXEC_CMD "$CMD"
}
# attach to server using Elixir
iexdebug()
{
debugwarning
# Elixir shell is hidden as default
NID=$(uid debug)
CMD="`shell_escape \"$IEX\" \"$IEXNAME\" \"$NID\"` \
-remsh $ERLANG_NODE \
--erl `shell_escape \"$KERNEL_OPTS\"` \
--erl `shell_escape \"$ERLANG_OPTS\"` \
--erl `shell_escape \"${ARGS[@]}\"` \
--erl `shell_escape_str \"$@\"`"
$EXEC_CMD "ERL_PATH=\"$ERL\" $CMD"
}
# start interactive server
live()
{
livewarning
CMD="`shell_escape \"$ERL\" \"$NAME\" \"${ERLANG_NODE}\"` \
$MNESIA_OPTS \
$KERNEL_OPTS \
$EJABBERD_OPTS \
-s ejabberd \
$ERLANG_OPTS \
`shell_escape \"${ARGS[@]}\" \"$@\"`"
$EXEC_CMD "$CMD"
}
# start interactive server with Elixir
iexlive()
{
livewarning
echo $@
CMD="`shell_escape \"$IEX\" \"$IEXNAME\" \"${ERLANG_NODE}\"` \
--erl \"-mnesia dir \\\"$SPOOL_DIR\\\"\" \
--erl \"`shell_escape \"$KERNEL_OPTS\"`\" \
--erl \"`shell_escape \"$EJABBERD_OPTS\"`\" \
--app ejabberd \
--erl `shell_escape \"$ERLANG_OPTS\"` \
--erl `shell_escape \"${ARGS[@]}\"` \
--erl `shell_escape_str \"$@\"`"
$EXEC_CMD "ERL_PATH=\"$ERL\" $CMD"
}
# start server in the foreground
foreground()
{
check_start
CMD="`shell_escape \"$ERL\" \"$NAME\" \"$ERLANG_NODE\"` \
-noinput \
$MNESIA_OPTS \
$KERNEL_OPTS \
$EJABBERD_OPTS \
-s ejabberd \
$ERLANG_OPTS \
`shell_escape \"${ARGS[@]}\" \"$@\"`"
$EXEC_CMD "$CMD"
case $EXEC_CMD in
as_install_user) su -c '"$0" $@"' "$INSTALLUSER" -- "$@" ;;
as_current_user) "$@" ;;
esac
}
exec_erl()
{
NODE=$1; shift
exec_cmd "$ERL" ${S:--}name $NODE $ERLANG_OPTS "$@"
}
exec_iex()
{
NODE=$1; shift
exec_cmd "$IEX" ${S:---}name $NODE --erl "$ERLANG_OPTS" "$@"
}
# usage
debugwarning()
{
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
@@ -286,7 +145,6 @@ debugwarning()
livewarning()
{
check_start
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
echo "--------------------------------------------------------------------"
echo ""
@@ -308,32 +166,6 @@ livewarning()
fi
}
etop()
{
NID=$(uid top)
$EXEC_CMD "$ERL \
$NAME $NID \
-hidden -s etop -s erlang halt -output text -node $ERLANG_NODE"
}
ping()
{
[ -z "$1" ] && PEER=${ERLANG_NODE} || PEER=$1
if [ "$PEER" = "${PEER%.*}" ] ; then
PING_NAME="-sname"
PING_NODE=$(hostname -s)
else
PING_NAME="-name"
PING_NODE=$(hostname)
fi
NID=$(uid ping ${PING_NODE})
$EXEC_CMD "$ERL \
$PING_NAME $NID \
-hidden $KERNEL_OPTS $ERLANG_OPTS \
-eval 'io:format(\"~p~n\",[net_adm:ping('\"'\"'$PEER'\"'\"')])' \
-s erlang halt -output text -noinput"
}
help()
{
echo ""
@@ -355,28 +187,11 @@ help()
echo ""
}
# common control function
ctl()
{
NID=$(uid ctl)
CMD="`shell_escape \"$ERL\" \"$NAME\" \"$NID\"` \
-noinput -hidden $KERNEL_OPTS -s ejabberd_ctl \
-extra `shell_escape \"$ERLANG_NODE\"` $EJABBERD_NO_TIMEOUT \
`shell_escape \"$@\"`"
$EXEC_CMD "$CMD"
result=$?
case $result in
2) help;;
3) help;;
*) :;;
esac
return $result
}
# dynamic node name helper
uid()
{
uuid=$(uuidgen 2>/dev/null)
[ -z "$uuid" -a -f /proc/sys/kernel/random/uuid ] && uuid=$(</proc/sys/kernel/random/uuid)
[ -z "$uuid" -a -f /proc/sys/kernel/random/uuid ] && uuid=$(cat /proc/sys/kernel/random/uuid)
[ -z "$uuid" ] && uuid=$(printf "%X" $RANDOM$(date +%M%S)$$)
uuid=${uuid%%-*}
[ $# -eq 0 ] && echo ${uuid}-${ERLANG_NODE}
@@ -391,6 +206,7 @@ stop_epmd()
}
# make sure node not already running and node name unregistered
# if all ok, ensure runtime directory exists and make it current directory
check_start()
{
"$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && {
@@ -407,11 +223,17 @@ check_start()
"$EPMD" -kill >/dev/null
}
}
} || {
[ -d "$SPOOL_DIR" ] || exec_cmd mkdir -p "$SPOOL_DIR"
cd "$SPOOL_DIR" || {
echo "ERROR: ejabberd can not access directory $SPOOL_DIR"
exit 6
}
}
}
# allow sync calls
wait_for_status()
wait_status()
{
# args: status try delay
# return: 0 OK, 1 KO
@@ -420,27 +242,69 @@ wait_for_status()
while [ $status -ne $1 ] ; do
sleep $3
timeout=`expr $timeout - 1`
[ $timeout -eq 0 ] && {
if [ $timeout -eq 0 ] ; then
status=$1
} || {
ctl status > /dev/null
else
exec_erl $(uid ctl) -hidden -noinput -s ejabberd_ctl \
-extra $ERLANG_NODE $NO_TIMEOUT status > /dev/null
status=$?
}
fi
done
[ $timeout -eq 0 ] && return 1 || return 0
[ $timeout -gt 0 ]
}
# main handler
case "${ARGS[0]}" in
'start') start;;
'debug') debug;;
'iexdebug') iexdebug;;
'live') live;;
'iexlive') iexlive;;
'foreground') foreground;;
'ping'*) ping ${ARGS[1]};;
'etop') etop;;
'started') wait_for_status 0 30 2;; # wait 30x2s before timeout
'stopped') wait_for_status 3 30 2 && stop_epmd;; # wait 30x2s before timeout
*) ctl "${ARGS[@]}";;
# main
case $1 in
start)
check_start
exec_erl $ERLANG_NODE $EJABBERD_OPTS -noinput -detached
;;
foreground)
check_start
exec_erl $ERLANG_NODE $EJABBERD_OPTS -noinput
;;
live)
livewarning
check_start
exec_erl $ERLANG_NODE $EJABBERD_OPTS
;;
debug)
debugwarning
exec_erl $(uid debug) -hidden -remsh $ERLANG_NODE
;;
etop)
exec_erl $(uid top) -hidden -node $ERLANG_NODE -s etop \
-s erlang halt -output text
;;
iexdebug)
debugwarning
exec_iex $(uid debug) --remsh "$ERLANG_NODE"
;;
iexlive)
livewarning
exec_iex $ERLANG_NODE --erl "$EJABBERD_OPTS" --app ejabberd
;;
ping)
PEER=${2:-$ERLANG_NODE}
[ "$PEER" = "${PEER%.*}" ] && PS="-s"
exec_cmd "$ERL" ${PS:--}name $(uid ping $(hostname $PS)) $ERLANG_OPTS \
-noinput -hidden -eval 'io:format("~p~n",[net_adm:ping('"$PEER"')])' \
-s erlang halt -output text
;;
started)
wait_status 0 30 2 # wait 30x2s before timeout
;;
stopped)
wait_status 3 30 2 && stop_epmd # wait 30x2s before timeout
;;
*)
exec_erl $(uid ctl) -hidden -noinput -s ejabberd_ctl \
-extra $ERLANG_NODE $NO_TIMEOUT "$@"
result=$?
case $result in
2|3) help;;
*) :;;
esac
exit $result
;;
esac
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -48,4 +48,4 @@
-define(HEADER(CType),
[CType, ?AC_ALLOW_ORIGIN, ?AC_ALLOW_HEADERS]).
-define(PROCNAME, ejabberd_mod_bosh).
-define(BOSH_CACHE, bosh_cache).
+4 -6
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -33,15 +33,13 @@
-define(SQL_DIR, filename:join(["priv", "sql"])).
-define(CONFIG_PATH, <<"ejabberd.cfg">>).
-define(CONFIG_PATH, <<"ejabberd.yml">>).
-define(LOG_PATH, <<"ejabberd.log">>).
-define(LOG_PATH, "ejabberd.log").
-define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>).
-define(COPYRIGHT, "Copyright (c) 2002-2016 ProcessOne").
-define(S2STIMEOUT, timer:minutes(10)).
-define(COPYRIGHT, "Copyright (c) 2002-2017 ProcessOne").
%%-define(DBGFSM, true).
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -22,5 +22,5 @@
token = <<"">> :: binary() | '_',
us = {<<"">>, <<"">>} :: {binary(), binary()} | '_',
scope = [] :: [binary()] | '_',
expire :: integer() | '$1'
expire :: integer() | '$1' | '_'
}).
+8
View File
@@ -0,0 +1,8 @@
-define(ROUTES_CACHE, routes_cache).
-type local_hint() :: integer() | {apply, atom(), atom()}.
-record(route, {domain :: binary() | '_',
server_host :: binary() | '_',
pid :: undefined | pid(),
local_hint :: local_hint() | undefined | '_'}).
+24 -1
View File
@@ -1,13 +1,36 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-ifndef(EJABBERD_SM_HRL).
-define(EJABBERD_SM_HRL, true).
-define(SM_CACHE, sm_cache).
-record(session, {sid, usr, us, priority, info = []}).
-record(session_counter, {vhost, count}).
-type sid() :: {erlang:timestamp(), pid()}.
-type ip() :: {inet:ip_address(), inet:port_number()} | undefined.
-type info() :: [{conn, atom()} | {ip, ip()} | {node, atom()}
| {oor, boolean()} | {auth_module, atom()}
| {num_stanzas_in, non_neg_integer()}].
| {num_stanzas_in, non_neg_integer()}
| offline].
-type prio() :: undefined | integer().
-endif.
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+2 -2
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,7 +27,7 @@
-record(eldap_search,
{scope = wholeSubtree :: scope(),
base = <<"">> :: binary(),
filter :: eldap:filter(),
filter :: eldap:filter() | undefined,
limit = 0 :: non_neg_integer(),
attributes = [] :: [binary()],
types_only = false :: boolean(),
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+9 -9
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -471,15 +471,15 @@
-type(iq() :: iq_request() | iq_reply()).
-record(rsm_in, {max :: integer() | error,
direction :: before | aft,
id :: binary(),
index :: integer() | error}).
-record(rsm_in, {max :: integer() | error | undefined,
direction :: before | aft | undefined,
id :: binary() | undefined,
index :: integer() | error | undefined}).
-record(rsm_out, {count :: integer(),
index :: integer(),
first :: binary(),
last :: binary()}).
-record(rsm_out, {count :: integer() | undefined,
index :: integer() | undefined,
first :: binary() | undefined,
last :: binary() | undefined}).
-type(rsm_in() :: #rsm_in{}).
+2 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -17,6 +17,7 @@
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-define(PRINT(Format, Args), io:format(Format, Args)).
-compile([{parse_transform, lager_transform}]).
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(motd, {server = <<"">> :: binary(),
packet = #xmlel{} :: xmlel()}).
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(caps_features,
{node_pair = {<<"">>, <<"">>} :: {binary(), binary()},
features = [] :: [binary()] | pos_integer()
+25 -2
View File
@@ -1,4 +1,27 @@
-type matchspec_atom() :: '_' | '$1' | '$2' | '$3'.
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-type matchspec_atom() :: '_' | '$1' | '$2' | '$3' | '$4'.
-record(carboncopy, {us :: {binary(), binary()} | matchspec_atom(),
resource :: binary() | matchspec_atom(),
version :: binary() | matchspec_atom()}).
version :: binary() | matchspec_atom(),
node = node() :: node() | matchspec_atom()}).
-define(CARBONCOPY_CACHE, carboncopy_cache).
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-type conn_param() :: {binary(), binary(), inet:port_number(), binary()} |
{binary(), binary(), inet:port_number()} |
{binary(), binary()} |
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(last_activity, {us = {<<"">>, <<"">>} :: {binary(), binary()},
timestamp = 0 :: non_neg_integer(),
status = <<"">> :: binary()}).
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(archive_msg,
{us = {<<"">>, <<"">>} :: {binary(), binary()} | '$2',
id = <<>> :: binary() | '_',
+10 -7
View File
@@ -1,7 +1,6 @@
%%%----------------------------------------------------------------------
%%% File : mod_muc.hrl
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -23,11 +22,15 @@
{'_', binary()},
opts = [] :: list() | '_'}).
-record(muc_online_room,
{name_host = {<<"">>, <<"">>} :: {binary(), binary()} | '$1' |
{'_', binary()} | '_',
pid = self() :: pid() | '$2' | '_' | '$1'}).
-record(muc_registered,
{us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()}, binary()} | '$1',
nick = <<"">> :: binary()}).
-record(muc_online_room,
{name_host :: {binary(), binary()} | '$1' | {'_', binary()} | '_',
pid :: pid() | '$2' | '_' | '$1'}).
-record(muc_online_users, {us :: {binary(), binary()},
resource :: binary() | '_',
room :: binary() | '_' | '$1',
host :: binary() | '_' | '$2'}).
+9 -17
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -28,9 +28,8 @@
-record(lqueue,
{
queue :: ?TQUEUE,
len :: integer(),
max :: integer()
queue :: p1_queue:queue(),
max = 0 :: integer()
}).
-type lqueue() :: #lqueue{}.
@@ -80,7 +79,7 @@
role :: role(),
%%is_subscriber = false :: boolean(),
%%subscriptions = [] :: [binary()],
last_presence :: xmlel()
last_presence :: presence() | undefined
}).
-record(subscriber, {jid :: jid(),
@@ -91,10 +90,10 @@
{
message_time = 0 :: integer(),
presence_time = 0 :: integer(),
message_shaper :: shaper:shaper(),
presence_shaper :: shaper:shaper(),
message :: xmlel(),
presence :: {binary(), xmlel()}
message_shaper = none :: shaper:shaper(),
presence_shaper = none :: shaper:shaper(),
message :: message() | undefined,
presence :: {binary(), presence()} | undefined
}).
-record(state,
@@ -118,12 +117,5 @@
just_created = false :: boolean(),
activity = treap:empty() :: treap:treap(),
room_shaper = none :: shaper:shaper(),
room_queue = queue:new() :: ?TQUEUE
room_queue :: p1_queue:queue() | undefined
}).
-record(muc_online_users, {us = {<<>>, <<>>} :: {binary(), binary()},
resource = <<>> :: binary() | '_',
room = <<>> :: binary() | '_' | '$1',
host = <<>> :: binary() | '_' | '$2'}).
-type muc_online_users() :: #muc_online_users{}.
+23 -3
View File
@@ -1,10 +1,30 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(offline_msg,
{us = {<<"">>, <<"">>} :: {binary(), binary()},
timestamp = p1_time_compat:timestamp() :: erlang:timestamp() | '_',
expire = p1_time_compat:timestamp() :: erlang:timestamp() | never | '_',
timestamp :: erlang:timestamp() | '_' | undefined,
expire :: erlang:timestamp() | never | undefined | '_',
from = #jid{} :: jid() | '_',
to = #jid{} :: jid() | '_',
packet = #xmlel{} :: xmlel() | '_'}).
packet = #xmlel{} :: xmlel() | message() | '_'}).
-record(state,
{host = <<"">> :: binary(),
+1 -9
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -38,11 +38,3 @@
-type listitem_type() :: none | jid | group | subscription.
-type listitem_value() :: none | both | from | to | jid:ljid() | binary().
-type listitem_action() :: allow | deny.
-record(userlist, {name = none :: none | binary(),
list = [] :: [listitem()],
needdb = false :: boolean()}).
-type userlist() :: #userlist{}.
-export_type([userlist/0]).
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(private_storage,
{usns = {<<"">>, <<"">>, <<"">>} :: {binary(), binary(), binary() |
'$1' | '_'},
+1 -1
View File
@@ -2,7 +2,7 @@
%%% RFC 1928 constants.
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -1,6 +1,6 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(sr_group, {group_host = {<<"">>, <<"">>} :: {'$1' | binary(), '$2' | binary()},
opts = [] :: list() | '_' | '$2'}).
+20
View File
@@ -1,3 +1,23 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(vcard_search,
{us, user, luser, fn, lfn, family, lfamily, given,
lgiven, middle, lmiddle, nickname, lnickname, bday,
+20
View File
@@ -1,2 +1,22 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-record(vcard_xupdate, {us = {<<>>, <<>>} :: {binary(), binary()},
hash = <<>> :: binary()}).
+17 -27
View File
@@ -1,27 +1,22 @@
%%% ====================================================================
%%% ``The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
%%% compliance with the License. You should have received a copy of the
%%% Erlang Public License along with this software. If not, it can be
%%% retrieved via the world wide web at http://www.erlang.org/.
%%%
%%%----------------------------------------------------------------------
%%%
%%% Software distributed under the License is distributed on an "AS IS"
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%%% the License for the specific language governing rights and limitations
%%% under the License.
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% The Initial Developer of the Original Code is ProcessOne.
%%% Portions created by ProcessOne are Copyright 2006-2016, ProcessOne
%%% All Rights Reserved.''
%%% This software is copyright 2006-2016, ProcessOne.
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% copyright 2006-2016 ProcessOne
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%% This file contains pubsub types definition.
%%% ====================================================================
%%%----------------------------------------------------------------------
-include("ejabberd.hrl").
@@ -109,13 +104,6 @@
).
%% @type affiliation() = 'none' | 'owner' | 'publisher' | 'publish-only' | 'member' | 'outcast'.
-type(subscription() :: 'none'
| 'pending'
| 'unconfigured'
| 'subscribed'
).
%% @type subscription() = 'none' | 'pending' | 'unconfigured' | 'subscribed'.
-type(accessModel() :: 'open'
| 'presence'
| 'roster'
@@ -150,6 +138,7 @@
-record(pubsub_state,
{
stateid ,% :: {jlib:ljid(), mod_pubsub:nodeIdx()},
nodeidx ,% :: mod_pubsub:nodeIdx(),
items = [] ,% :: [mod_pubsub:itemId(),...],
affiliation = 'none',% :: mod_pubsub:affiliation(),
subscriptions = [] % :: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
@@ -158,6 +147,7 @@
-record(pubsub_item,
{
itemid ,% :: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
nodeidx ,% :: mod_pubsub:nodeIdx(),
creation = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
modification = {unknown, unknown},% :: {erlang:timestamp(), jlib:ljid()},
payload = [] % :: mod_pubsub:payload()
@@ -171,7 +161,7 @@
-record(pubsub_last_item,
{
nodeid ,% :: mod_pubsub:nodeIdx(),
nodeid ,% :: {binary(), mod_pubsub:nodeIdx()},
itemid ,% :: mod_pubsub:itemId(),
creation ,% :: {erlang:timestamp(), jlib:ljid()},
payload % :: mod_pubsub:payload()
+23 -19
View File
@@ -3,18 +3,18 @@ defmodule Ejabberd.Mixfile do
def project do
[app: :ejabberd,
version: "16.12.0",
description: description,
elixir: "~> 1.3",
version: "17.6.0",
description: description(),
elixir: "~> 1.4",
elixirc_paths: ["lib"],
compile_path: ".",
compilers: [:asn1] ++ Mix.compilers,
erlc_options: erlc_options,
erlc_options: erlc_options(),
erlc_paths: ["asn1", "src"],
# Elixir tests are starting the part of ejabberd they need
aliases: [test: "test --no-start"],
package: package,
deps: deps]
package: package(),
deps: deps()]
end
def description do
@@ -26,38 +26,42 @@ defmodule Ejabberd.Mixfile do
def application do
[mod: {:ejabberd_app, []},
applications: [:ssl],
included_applications: [:lager, :mnesia, :p1_utils, :cache_tab,
included_applications: [:lager, :mnesia, :inets, :p1_utils, :cache_tab,
:fast_tls, :stringprep, :fast_xml, :xmpp,
:stun, :fast_yaml, :esip, :jiffy, :p1_oauth2]
++ cond_apps]
++ cond_apps()]
end
defp erlc_options do
# Use our own includes + includes from all dependencies
includes = ["include"] ++ deps_include(["fast_xml", "xmpp"])
includes = ["include"] ++ deps_include(["fast_xml", "xmpp", "p1_utils"])
[:debug_info, {:d, :ELIXIR_ENABLED}] ++ Enum.map(includes, fn(path) -> {:i, path} end)
end
defp deps do
[{:lager, "~> 3.2"},
[{:lager, "~> 3.4.0"},
{:p1_utils, "~> 1.0"},
{:fast_xml, "~> 1.1"},
{:xmpp, "~> 1.1"},
{:cache_tab, "~> 1.0"},
{:stringprep, "~> 1.0"},
{:fast_yaml, "~> 1.0"},
{:fast_tls, "~> 1.0"},
{:fast_xml, "~> 1.1"},
{:xmpp, "~> 1.1"},
{:stun, "~> 1.0"},
{:esip, "~> 1.0"},
{:jiffy, "~> 0.14.7"},
{:p1_oauth2, "~> 0.6.1"},
{:distillery, "~> 1.0"},
{:ex_doc, ">= 0.0.0", only: :dev}]
++ cond_deps
++ cond_deps()
end
defp deps_include(deps) do
Enum.map(deps, fn dep -> "deps/#{dep}/include" end)
base = case Mix.Project.deps_paths()[:ejabberd] do
nil -> "deps"
_ -> ".."
end
Enum.map(deps, fn dep -> base<>"/#{dep}/include" end)
end
defp cond_deps do
@@ -68,7 +72,7 @@ defmodule Ejabberd.Mixfile do
{config(:redis), {:eredis, "~> 1.0"}},
{config(:zlib), {:ezlib, "~> 1.0"}},
{config(:iconv), {:iconv, "~> 1.0"}},
{config(:pam), {:p1_pam, "~> 1.0"}},
{config(:pam), {:epam, "~> 1.0"}},
{config(:tools), {:luerl, github: "rvirding/luerl", tag: "v0.2"}},
{config(:tools), {:meck, "~> 0.8.4"}},
{config(:tools), {:moka, github: "processone/moka", tag: "1.0.5c"}}], do:
@@ -85,7 +89,7 @@ defmodule Ejabberd.Mixfile do
app
end
def package do
defp package do
[# These are the default files included in the package
files: ["lib", "src", "priv", "mix.exs", "include", "README.md", "COPYING"],
maintainers: ["ProcessOne"],
@@ -96,7 +100,7 @@ defmodule Ejabberd.Mixfile do
"ProcessOne" => "http://www.process-one.net/"}]
end
def vars do
defp vars do
case :file.consult("vars.config") do
{:ok,config} -> config
_ -> [zlib: true, iconv: true]
@@ -104,7 +108,7 @@ defmodule Ejabberd.Mixfile do
end
defp config(key) do
case vars[key] do
case vars()[key] do
nil -> false
value -> value
end
@@ -138,7 +142,7 @@ defmodule Mix.Tasks.Compile.Asn1 do
end)
end
def manifests, do: [manifest]
def manifests, do: [manifest()]
defp manifest, do: Path.join(Mix.Project.manifest_path, @manifest)
def clean, do: Erlang.clean(manifest())
+17 -18
View File
@@ -1,19 +1,18 @@
%{"cache_tab": {:hex, :cache_tab, "1.0.5", "022da45aa10c2ccfdc804e69af36e3be1717c7579f3578767a29bd8ceb3b3c92", [:rebar3], [{:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"distillery": {:hex, :distillery, "1.0.0", "a866a72bf2a3a5f078f5a249017ed951acda88a760d200512f91f585d74db1ec", [:mix], []},
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []},
"esip": {:hex, :esip, "1.0.9", "256259792c07d2f888d56e89031b0d064ff795c395fdca11ee3aab912c56d9de", [:rebar3], [{:fast_tls, "1.0.8", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}, {:stun, "1.0.8", [hex: :stun, optional: false]}]},
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"ezlib": {:hex, :ezlib, "1.0.1", "add8b2770a1a70c174aaea082b4a8668c0c7fdb03ee6cc81c6c68d3a6c3d767d", [:rebar3], []},
"fast_tls": {:hex, :fast_tls, "1.0.8", "697dc84ab958aed36924d8d9df9a463103ddc92f53283bbd930c9015f05ecf0a", [:rebar3], [{:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"fast_xml": {:hex, :fast_xml, "1.1.18", "5cad4f35fa50070d38ef7cbb64975c6a8750e92b976f49e5bb88819f47451e69", [:rebar3], [{:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"fast_yaml": {:hex, :fast_yaml, "1.0.7", "c1fc7995c8422bb4dc2a3502f6432054d6c16fde86f259f50080bb1d09fc5e50", [:rebar3], [{:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"goldrush": {:hex, :goldrush, "0.1.8", "2024ba375ceea47e27ea70e14d2c483b2d8610101b4e852ef7f89163cdb6e649", [:rebar3], []},
"iconv": {:hex, :iconv, "1.0.3", "f5c159f7e0ad2a3b55c6b5528ce71d7926f206df2f9bf83201a77cf1bc91c6f0", [:rebar3], [{:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"jiffy": {:hex, :jiffy, "0.14.7", "9f33b893edd6041ceae03bc1e50b412e858cc80b46f3d7535a7a9940a79a1c37", [:make, :rebar], []},
"lager": {:hex, :lager, "3.2.1", "eef4e18b39e4195d37606d9088ea05bf1b745986cf8ec84f01d332456fe88d17", [:rebar3], [{:goldrush, "0.1.8", [hex: :goldrush, optional: false]}]},
"p1_mysql": {:hex, :p1_mysql, "1.0.1", "d2be1cfc71bb4f1391090b62b74c3f5cb8e7a45b0076b8cb290cd6b2856c581b", [:rebar3], []},
%{"cache_tab": {:hex, :cache_tab, "1.0.8", "eac8923f0f20c35e630317790c4d4c2629c5bc792753fa48eb5391bd39c80245", [:rebar3], [{:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"distillery": {:hex, :distillery, "1.4.0", "d633cd322c8efa0428082b00b7f902daf8caa166d45f9022bbc19a896d2e1e56", [:mix], []},
"earmark": {:hex, :earmark, "1.2.2", "f718159d6b65068e8daeef709ccddae5f7fdc770707d82e7d126f584cd925b74", [:mix], []},
"esip": {:hex, :esip, "1.0.12", "e0505afe74bb362b0ea486e2a64b3c1934b1eb541a7b3e990b23045e4bdc07d4", [:rebar3], [{:fast_tls, "1.0.12", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}, {:stun, "1.0.11", [hex: :stun, optional: false]}]},
"ex_doc": {:hex, :ex_doc, "0.16.1", "b4b8a23602b4ce0e9a5a960a81260d1f7b29635b9652c67e95b0c2f7ccee5e81", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, optional: false]}]},
"ezlib": {:hex, :ezlib, "1.0.2", "22004ecf553a7d831404394d5642712e2aede90522e22bd6ccc089ca410ee098", [:rebar3], []},
"fast_tls": {:hex, :fast_tls, "1.0.12", "861b591f23103142782c5b72de8898673a37acd78646c50dbda978e1e1c5b463", [:rebar3], [{:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"fast_xml": {:hex, :fast_xml, "1.1.23", "1e7b311d3353806ee832d7630fef57713987cea40a7020669cf057d537de4721", [:rebar3], [{:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"fast_yaml": {:hex, :fast_yaml, "1.0.10", "ce5d52b77cb21968c8b73aa29b39f56a4ffd7e1e11f853d5597e7277858f155e", [:rebar3], [{:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], []},
"iconv": {:hex, :iconv, "1.0.5", "ae871aa11c854695db37e48fd5e5583b02e106126fbdf21bb53448f5a47c092b", [:rebar3], [{:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"jiffy": {:hex, :jiffy, "0.14.11", "919a87d491c5a6b5e3bbc27fafedc3a0761ca0b4c405394f121f582fd4e3f0e5", [:rebar3], []},
"lager": {:hex, :lager, "3.4.2", "150b9a17b23ae6d3265cc10dc360747621cf217b7a22b8cddf03b2909dbf7aa5", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, optional: false]}]},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.1", "4e021250cc198c538b097393671a41e7cebf463c248980320e038fe0316eb56b", [:rebar3], []},
"p1_utils": {:hex, :p1_utils, "1.0.6", "ef0951ddf38e92b7e479af4b8dc950df76af8c1030432ef68b7fd7ad17c436fe", [:rebar3], []},
"stringprep": {:hex, :stringprep, "1.0.7", "f709c7ee3697ae9d2becbbbba1dcea47e0f583e313b4eb7d0ced2163c595ee12", [:rebar3], [{:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"stun": {:hex, :stun, "1.0.8", "cfe6df914b12227ca0920e5e3d5b1203331c6662d0948859357c84d2c87a0411", [:rebar3], [{:fast_tls, "1.0.8", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.6", [hex: :p1_utils, optional: false]}]},
"xmpp": {:hex, :xmpp, "1.1.4", "fa9c890a779c57699d870e2e0966e4b6a66e92de19d0263a54df26f1be6ae046", [:rebar3], [{:fast_xml, "1.1.18", [hex: :fast_xml, optional: false]}, {:stringprep, "1.0.7", [hex: :stringprep, optional: false]}]}}
"p1_utils": {:hex, :p1_utils, "1.0.9", "c33c230efbeb4dcc02911161e3cb1a93231a92df15e3fc97de655a9271a26d9f", [:rebar3], []},
"stringprep": {:hex, :stringprep, "1.0.9", "9182ba39931cd1db528b8883cad0d63530abe2bf21835d26cec2f9af8bc00be0", [:rebar3], [{:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"stun": {:hex, :stun, "1.0.11", "386cb3e3543e17a6351028a43e047c2172225d035c826a72fcb67672da9874e5", [:rebar3], [{:fast_tls, "1.0.12", [hex: :fast_tls, optional: false]}, {:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}]},
"xmpp": {:hex, :xmpp, "1.1.11", "8c49964d0d48b81080d2c5700fcf6cc19950ae9dc60a71bd3ff3d4620336d052", [:rebar3], [{:fast_xml, "1.1.23", [hex: :fast_xml, optional: false]}, {:p1_utils, "1.0.9", [hex: :p1_utils, optional: false]}, {:stringprep, "1.0.9", [hex: :stringprep, optional: false]}]}}
+126
View File
@@ -0,0 +1,126 @@
-module(override_deps_versions).
-export([preprocess/2, 'pre_update-deps'/2, new_replace/1, new_replace/0]).
preprocess(Config, _Dirs) ->
update_deps(Config).
update_deps(Config) ->
LocalDeps = rebar_config:get_local(Config, deps, []),
TopDeps = case rebar_config:get_xconf(Config, top_deps, []) of
[] -> LocalDeps;
Val -> Val
end,
Config2 = rebar_config:set_xconf(Config, top_deps, TopDeps),
NewDeps = lists:map(fun({Name, _, _} = Dep) ->
case lists:keyfind(Name, 1, TopDeps) of
false -> Dep;
TopDep -> TopDep
end
end, LocalDeps),
%io:format("LD ~p~n", [LocalDeps]),
%io:format("TD ~p~n", [TopDeps]),
Config3 = rebar_config:set(Config2, deps, NewDeps),
{ok, Config3, []}.
'pre_update-deps'(Config, _Dirs) ->
{ok, Config2, _} = update_deps(Config),
case code:is_loaded(old_rebar_config) of
false ->
{_, Beam, _} = code:get_object_code(rebar_config),
NBeam = rename(Beam, old_rebar_config),
code:load_binary(old_rebar_config, "blank", NBeam),
replace_mod(Beam);
_ ->
ok
end,
{ok, Config2}.
new_replace() ->
old_rebar_config:new().
new_replace(Config) ->
NC = old_rebar_config:new(Config),
{ok, Conf, _} = update_deps(NC),
Conf.
replace_mod(Beam) ->
{ok, {_, [{exports, Exports}]}} = beam_lib:chunks(Beam, [exports]),
Funcs = lists:filtermap(
fun({module_info, _}) ->
false;
({Name, Arity}) ->
Args = args(Arity),
Call = case Name of
new ->
[erl_syntax:application(
erl_syntax:abstract(override_deps_versions),
erl_syntax:abstract(new_replace),
Args)];
_ ->
[erl_syntax:application(
erl_syntax:abstract(old_rebar_config),
erl_syntax:abstract(Name),
Args)]
end,
{true, erl_syntax:function(erl_syntax:abstract(Name),
[erl_syntax:clause(Args, none,
Call)])}
end, Exports),
Forms0 = ([erl_syntax:attribute(erl_syntax:abstract(module),
[erl_syntax:abstract(rebar_config)])]
++ Funcs),
Forms = [erl_syntax:revert(Form) || Form <- Forms0],
%io:format("--------------------------------------------------~n"
% "~s~n",
% [[erl_pp:form(Form) || Form <- Forms]]),
{ok, Mod, Bin} = compile:forms(Forms, [report, export_all]),
code:purge(rebar_config),
{module, Mod} = code:load_binary(rebar_config, "mock", Bin).
args(0) ->
[];
args(N) ->
[arg(N) | args(N-1)].
arg(N) ->
erl_syntax:variable(list_to_atom("A"++integer_to_list(N))).
rename(BeamBin0, Name) ->
BeamBin = replace_in_atab(BeamBin0, Name),
update_form_size(BeamBin).
%% Replace the first atom of the atom table with the new name
replace_in_atab(<<"Atom", CnkSz0:32, Cnk:CnkSz0/binary, Rest/binary>>, Name) ->
replace_first_atom(<<"Atom">>, Cnk, CnkSz0, Rest, latin1, Name);
replace_in_atab(<<"AtU8", CnkSz0:32, Cnk:CnkSz0/binary, Rest/binary>>, Name) ->
replace_first_atom(<<"AtU8">>, Cnk, CnkSz0, Rest, unicode, Name);
replace_in_atab(<<C, Rest/binary>>, Name) ->
<<C, (replace_in_atab(Rest, Name))/binary>>.
replace_first_atom(CnkName, Cnk, CnkSz0, Rest, Encoding, Name) ->
<<NumAtoms:32, NameSz0:8, _Name0:NameSz0/binary, CnkRest/binary>> = Cnk,
NumPad0 = num_pad_bytes(CnkSz0),
<<_:NumPad0/unit:8, NextCnks/binary>> = Rest,
NameBin = atom_to_binary(Name, Encoding),
NameSz = byte_size(NameBin),
CnkSz = CnkSz0 + NameSz - NameSz0,
NumPad = num_pad_bytes(CnkSz),
<<CnkName/binary, CnkSz:32, NumAtoms:32, NameSz:8, NameBin:NameSz/binary,
CnkRest/binary, 0:NumPad/unit:8, NextCnks/binary>>.
%% Calculate the number of padding bytes that have to be added for the
%% BinSize to be an even multiple of ?beam_num_bytes_alignment.
num_pad_bytes(BinSize) ->
case 4 - (BinSize rem 4) of
4 -> 0;
N -> N
end.
%% Update the size within the top-level form
update_form_size(<<"FOR1", _OldSz:32, Rest/binary>> = Bin) ->
Sz = size(Bin) - 8,
<<"FOR1", Sz:32, Rest/binary>>.
+55 -35
View File
@@ -1,45 +1,57 @@
%-------------------------------------------------------------------
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2013-2016, Evgeniy Khramtsov
%%% @doc
%%%----------------------------------------------------------------------
%%%
%%% @end
%%% Created : 1 May 2013 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.6"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.5"}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.9"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.7"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.18"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.4"}}},
{stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.9"}}},
{esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.10"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.7"}}},
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager",
{tag, {if_version_above, "17", "3.4.2", "3.2.1"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.9"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.9"}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.13"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.9"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.23"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.13"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.10"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.1"}}},
{luerl, ".*", {git, "https://github.com/rvirding/luerl", {tag, "v0.2"}}},
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.12"}}}},
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.13"}}}},
{if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
{tag, "1.0.2"}}}},
{tag, "1.0.3"}}}},
{if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
{tag, "1.1.1"}}}},
{tag, "1.1.3"}}}},
{if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
{tag, "1.1.5"}}}},
{if_var_true, pam, {p1_pam, ".*", {git, "https://github.com/processone/epam",
{tag, "1.0.0"}}}},
{if_var_true, pam, {epam, ".*", {git, "https://github.com/processone/epam",
{tag, "1.0.3"}}}},
{if_var_true, zlib, {ezlib, ".*", {git, "https://github.com/processone/ezlib",
{tag, "1.0.1"}}}},
{tag, "1.0.2"}}}},
{if_var_true, riak, {riakc, ".*", {git, "https://github.com/basho/riak-erlang-client",
{tag, "2.4.1"}}}},
%% Elixir support, needed to run tests
%% Elixir support, needed to run tests
{if_var_true, elixir, {elixir, ".*", {git, "https://github.com/elixir-lang/elixir",
{tag, {if_version_above, "17", "v1.2.6", "v1.1.1"}}}}},
{tag, {if_version_above, "17", "v1.4.4", "v1.1.1"}}}}},
%% TODO: When modules are fully migrated to new structure and mix, we will not need anymore rebar_elixir_plugin
{if_var_true, elixir, {rebar_elixir_plugin, ".*",
{git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}},
{if_not_rebar3, {if_var_true, elixir, {rebar_elixir_plugin, ".*",
{git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}},
{if_var_true, iconv, {iconv, ".*", {git, "https://github.com/processone/iconv",
{tag, "1.0.3"}}}},
{tag, "1.0.5"}}}},
{if_var_true, tools, {meck, "0.8.*", {git, "https://github.com/eproxus/meck",
{tag, "0.8.4"}}}},
{if_var_true, tools, {moka, ".*", {git, "https://github.com/processone/moka.git",
@@ -53,14 +65,13 @@
stringprep,
fast_xml,
esip,
luerl,
stun,
fast_yaml,
xmpp,
p1_utils,
p1_mysql,
p1_pgsql,
p1_pam,
epam,
ezlib,
iconv]}}.
@@ -70,13 +81,18 @@
{i, "include"},
{i, "deps/fast_xml/include"},
{i, "deps/xmpp/include"},
{i, "deps/p1_utils/include"},
{if_var_false, debug, no_debug_info},
{if_var_true, debug, debug_info},
{if_var_true, sip, {d, 'SIP'}},
{if_var_true, stun, {d, 'STUN'}},
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
{if_var_match, db_type, mssql, {d, 'mssql'}},
{if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},
{if_var_true, erlang_deprecated_types, {d, 'ERL_DEPRECATED_TYPES'}},
{if_version_above, "18", {d, 'STRONG_RAND_BYTES'}},
{if_have_fun, {crypto, strong_rand_bytes, 1}, {d, 'STRONG_RAND_BYTES'}},
{if_have_fun, {gb_sets, iterator_from, 2}, {d, 'GB_SETS_ITERATOR_FROM'}},
{if_have_fun, {public_key, short_name_hash, 1}, {d, 'SHORT_NAME_HASH'}},
{if_var_true, hipe, native},
{src_dirs, [asn1, src,
{if_var_true, tools, tools},
@@ -84,9 +100,12 @@
{deps_erl_opts, [{if_var_true, hipe, native}]}.
{plugins, [deps_erl_opts,
{if_var_true, elixir, rebar_elixir_compiler},
{if_var_true, elixir, rebar_exunit}]}.
{if_rebar3, {plugins, [rebar3_hex, {provider_asn1, "0.2.0"}]}}.
{if_not_rebar3, {plugins, [
deps_erl_opts, override_deps_versions,
{if_var_true, elixir, rebar_elixir_compiler},
{if_var_true, elixir, rebar_exunit}
]}}.
{if_var_true, elixir,
{lib_dirs, ["deps/elixir/lib"]}}.
@@ -119,6 +138,7 @@
{eunit_compile_opts, [{i, "tools"},
{i, "include"},
{i, "deps/p1_utils/include"},
{i, "deps/fast_xml/include"},
{i, "deps/xmpp/include"}]}.
@@ -128,9 +148,9 @@
{post_hook_configure, [{"fast_tls", []},
{"stringprep", []},
{"fast_yaml", []},
{"esip", []},
{if_var_true, sip, {"esip", []}},
{"fast_xml", [{if_var_true, full_xml, "--enable-full-xml"}]},
{if_var_true, pam, {"p1_pam", []}},
{if_var_true, pam, {"epam", []}},
{if_var_true, zlib, {"ezlib", []}},
{if_var_true, iconv, {"iconv", []}}]}.
+280 -162
View File
@@ -1,40 +1,82 @@
%%%-------------------------------------------------------------------
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2013-2016, Evgeniy Khramtsov
%%% @doc
%%%----------------------------------------------------------------------
%%%
%%% @end
%%% Created : 1 May 2013 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%%-------------------------------------------------------------------
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
ModCfg0 = fun(F, Cfg, [Key|Tail], Op, Default) ->
{OldVal,PartCfg} = case lists:keytake(Key, 1, Cfg) of
{value, {_, V1}, V2} -> {V1, V2};
false -> {if Tail == [] -> Default; true -> [] end, Cfg}
end,
case Tail of
[] ->
[{Key, Op(OldVal)} | PartCfg];
_ ->
[{Key, F(F, OldVal, Tail, Op, Default)} | PartCfg]
end
end,
ModCfg = fun(Cfg, Keys, Op, Default) -> ModCfg0(ModCfg0, Cfg, Keys, Op, Default) end,
Vars = case file:consult(filename:join([filename:dirname(SCRIPT),"vars.config"])) of
{ok, Terms} ->
Terms;
_Err ->
[]
end ++ [{cflags, "-g -O2 -Wall"}, {cppflags, "-g -O2 -Wall"},
{ldflags, ""}, {system_deps, false}],
{cflags, CFlags} = lists:keyfind(cflags, 1, Vars),
{cppflags, CPPFlags} = lists:keyfind(cppflags, 1, Vars),
{ldflags, LDFlags} = lists:keyfind(ldflags, 1, Vars),
{system_deps, SystemDeps} = lists:keyfind(system_deps, 1, Vars),
GetCfg0 = fun(F, Cfg, [Key | Tail], Default) ->
Val = case lists:keyfind(Key, 1, Cfg) of
{Key, V1} -> V1;
false -> Default
end,
case Tail of
[] ->
Val;
_ ->
F(F, Val, Tail, Default)
end
end,
ModCfg0 = fun(F, Cfg, [Key | Tail], Op, Default) ->
{OldVal, PartCfg} = case lists:keytake(Key, 1, Cfg) of
{value, {_, V1}, V2} -> {V1, V2};
false -> {if Tail == [] -> Default; true -> [] end, Cfg}
end,
case Tail of
[] ->
[{Key, Op(OldVal)} | PartCfg];
_ ->
[{Key, F(F, OldVal, Tail, Op, Default)} | PartCfg]
end
end,
FilterConfig = fun(F, Cfg, [{Path, true, ModFun, Default} | Tail]) ->
F(F, ModCfg0(ModCfg0, Cfg, Path, ModFun, Default), Tail);
(F, Cfg, [{Path, SourcePath, true, ModFun, Default, SourceDefault} | Tail]) ->
SourceVal = GetCfg0(GetCfg0, Cfg, SourcePath, SourceDefault),
ModFun2 = fun(V) -> ModFun(V, SourceVal) end,
F(F, ModCfg0(ModCfg0, Cfg, Path, ModFun2, Default), Tail);
(F, Cfg, [_ | Tail]) ->
F(F, Cfg, Tail);
(_, Cfg, []) ->
Cfg
end,
IsRebar3 = case application:get_key(rebar, vsn) of
{ok, VSN} ->
[VSN1 | _] = string:tokens(VSN, "-"),
[Maj, Min, Patch] = string:tokens(VSN1, "."),
[Maj, _Min, _Patch] = string:tokens(VSN1, "."),
(list_to_integer(Maj) >= 3);
undefined ->
lists:keymember(mix, 1, application:loaded_applications())
end,
Cfg = case file:consult(filename:join(filename:dirname(SCRIPT), "vars.config")) of
{ok, Terms} ->
Terms;
_Err ->
[]
end,
SysVer = erlang:system_info(otp_release),
ProcessSingleVar = fun(F, Var, Tail) ->
case F(F, [Var], []) of
@@ -44,10 +86,10 @@ ProcessSingleVar = fun(F, Var, Tail) ->
end,
ProcessVars = fun(_F, [], Acc) ->
lists:reverse(Acc);
(F, [{Type, Ver, Value} | Tail], Acc) when
Type == if_version_above orelse
Type == if_version_below ->
lists:reverse(Acc);
(F, [{Type, Ver, Value} | Tail], Acc) when
Type == if_version_above orelse
Type == if_version_below ->
SysVer = erlang:system_info(otp_release),
Include = if Type == if_version_above ->
SysVer > Ver;
@@ -55,78 +97,136 @@ ProcessVars = fun(_F, [], Acc) ->
SysVer < Ver
end,
if Include ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
F(F, Tail, ProcessSingleVar(F, Value, Acc));
true ->
F(F, Tail, Acc)
F(F, Tail, Acc)
end;
(F, [{Type, Ver, Value, ElseValue} | Tail], Acc) when
Type == if_version_above orelse
Type == if_version_below ->
SysVer = erlang:system_info(otp_release),
(F, [{Type, Ver, Value, ElseValue} | Tail], Acc) when
Type == if_version_above orelse
Type == if_version_below ->
Include = if Type == if_version_above ->
SysVer > Ver;
true ->
SysVer < Ver
end,
if Include ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
F(F, Tail, ProcessSingleVar(F, Value, Acc));
true ->
F(F, Tail, ProcessSingleVar(F, ElseValue, Acc))
F(F, Tail, ProcessSingleVar(F, ElseValue, Acc))
end;
(F, [{Type, Var, Value} | Tail], Acc) when
Type == if_var_true orelse
Type == if_var_false ->
Flag = Type == if_var_true,
case proplists:get_bool(Var, Cfg) of
V when V == Flag ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(F, Tail, Acc)
end;
(F, [{Type, Var, Match, Value} | Tail], Acc) when
Type == if_var_match orelse
Type == if_var_no_match ->
case proplists:get_value(Var, Cfg) of
V when V == Match ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(F, Tail, Acc)
end;
(F, [Other1 | Tail1], Acc) ->
F(F, Tail1, [F(F, Other1, []) | Acc]);
(F, Val, Acc) when is_tuple(Val) ->
list_to_tuple(F(F, tuple_to_list(Val), Acc));
(_F, Other2, _Acc) ->
Other2
end,
(F, [{Type, Var, Value} | Tail], Acc) when
Type == if_var_true orelse
Type == if_var_false ->
Flag = Type == if_var_true,
case proplists:get_bool(Var, Vars) of
V when V == Flag ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(F, Tail, Acc)
end;
(F, [{Type, Value} | Tail], Acc) when
Type == if_rebar3 orelse
Type == if_not_rebar3 ->
Flag = Type == if_rebar3,
case IsRebar3 == Flag of
true ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(F, Tail, Acc)
end;
(F, [{Type, Var, Match, Value} | Tail], Acc) when
Type == if_var_match orelse
Type == if_var_no_match ->
case proplists:get_value(Var, Vars) of
V when V == Match ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(F, Tail, Acc)
end;
(F, [{if_have_fun, MFA, Value} | Tail], Acc) ->
{Mod, Fun, Arity} = MFA,
code:ensure_loaded(Mod),
case erlang:function_exported(Mod, Fun, Arity) of
true ->
F(F, Tail, ProcessSingleVar(F, Value, Acc));
false ->
F(F, Tail, Acc)
end;
(F, [Other1 | Tail1], Acc) ->
F(F, Tail1, [F(F, Other1, []) | Acc]);
(F, Val, Acc) when is_tuple(Val) ->
list_to_tuple(F(F, tuple_to_list(Val), Acc));
(_F, Other2, _Acc) ->
Other2
end,
CFLags = proplists:get_value(cflags, Cfg, ""),
CPPFLags = proplists:get_value(cppflags, Cfg, ""),
LDFLags = proplists:get_value(ldflags, Cfg, ""),
MaybeApply = fun(Val) when is_function(Val) ->
Val();
(Val) ->
Val
end,
MaybeApply2 = fun(Val, Arg) when is_function(Val) ->
Val(Arg);
(Val, _) ->
Val
end,
ConfigureCmd = fun(Pkg, Flags) ->
{'get-deps',
"sh -c 'cd deps/" ++ Pkg ++
" && CFLAGS=\""++ CFLags ++"\" CPPFLAGS=\""++ CPPFLags ++"\" LDFLAGS=\""++ LDFLags ++"\"" ++
" ./configure " ++ Flags ++ "'"}
end,
AppendStr = fun(Append) ->
fun("") ->
lists:flatten(MaybeApply(Append));
(Val) ->
lists:flatten([Val, " ", MaybeApply(Append)])
end
end,
AppendList = fun(Append) ->
fun(Val) ->
Val ++ MaybeApply(Append)
end
end,
AppendStr2 = fun(Append) ->
fun("", Arg) ->
lists:flatten(MaybeApply2(Append, Arg));
(Val, Arg) ->
lists:flatten([Val, " ", MaybeApply2(Append, Arg)])
end
end,
AppendList2 = fun(Append) ->
fun(Val, Arg) ->
Val ++ MaybeApply2(Append, Arg)
end
end,
Conf = ProcessVars(ProcessVars, CONFIG, []),
Rebar3DepsFilter =
fun(DepsList) ->
lists:map(fun({DepName, _, {git, _, {tag, Version}}}) ->
{DepName, Version};
(Dep) ->
Dep
end, DepsList)
end,
Conf1 = case lists:keytake(post_hook_configure, 1, Conf) of
{value, {_, Items}, Rest} ->
[{post_hooks, [ConfigureCmd(Mod, string:join(Opts, " ")) || {Mod, Opts} <- Items]} | Rest];
_ ->
Conf
end,
GlobalDepsFilter =
fun(Deps) ->
DepNames = lists:map(fun({DepName, _, _}) -> DepName;
({DepName, _}) -> DepName
end, Deps),
lists:filtermap(fun(Dep) ->
case code:lib_dir(Dep) of
{error, _} ->
{true, "Unable to locate dep '" ++ atom_to_list(Dep) ++ "' in system deps."};
_ ->
false
end
end, DepNames)
end,
{ok, Cwd} = file:get_cwd(),
TestConfigFile = filename:join([Cwd, "test", "config.ctc"]),
TestConfig = case file:read_file_info(TestConfigFile) of
{ok, _} ->
"-userconfig ct_config_plain " ++ TestConfigFile ++ " ";
_ ->
""
{ok, _} ->
[" -userconfig ct_config_plain ", TestConfigFile, " "];
_ ->
""
end,
ResolveDepPath = case IsRebar3 of
@@ -134,102 +234,120 @@ ResolveDepPath = case IsRebar3 of
fun("deps/" ++ Rest) ->
Slash = string:str(Rest, "/"),
Dir = "_build/default/lib/" ++
string:sub_string(Rest, 1, Slash-1),
string:sub_string(Rest, 1, Slash - 1),
Dir ++ string:sub_string(Rest, Slash);
(Path) ->
Path
end;
_ ->
fun(P) ->
P
P
end
end,
CtIncludes = case lists:keyfind(eunit_compile_opts, 1, Conf1) of
false ->
[];
{_, EunitCompOpts} ->
[[" -include ", filename:join([Cwd, ResolveDepPath(IncPath)])]
|| {i, IncPath} <- EunitCompOpts]
end,
CtParams = fun(CompileOpts) ->
["-ct_hooks cth_surefire ",
lists:map(fun({i, IncPath}) ->
[" -include ", filename:join([Cwd, ResolveDepPath(IncPath)])]
end, CompileOpts),
TestConfig]
end,
ProcessErlOpt = fun({i, Path}) ->
{i, ResolveDepPath(Path)};
(ErlOpt) ->
ErlOpt
end,
GenDepConfigureLine =
fun(DepPath, Flags) ->
["sh -c 'if test ! -f ",DepPath,"config.status -o ",
"config.status -nt ",DepPath,"config.status; ",
"then (cd ", DepPath, " && ",
"CFLAGS=\"", CFlags,"\" ",
"CPPFLAGS=\"", CPPFlags, "\" "
"LDFLAGS=\"", LDFlags, "\"",
" ./configure ", string:join(Flags, " "),
"); fi'"]
end,
Conf1a = ModCfg(Conf1, [erl_opts],
fun(ErlOpts) -> lists:map(ProcessErlOpt, ErlOpts) end, []),
GenDepsConfigure =
fun(Hooks) ->
lists:map(fun({Pkg, Flags}) ->
DepPath = ResolveDepPath("deps/" ++ Pkg ++ "/"),
{'compile',
lists:flatten(GenDepConfigureLine(DepPath, Flags))}
end, Hooks)
end,
Conf2a = [{ct_extra_params, lists:flatten(["-ct_hooks cth_surefire ", TestConfig,
CtIncludes])} | Conf1a],
ProcessErlOpt = fun(Vals) ->
lists:map(
fun({i, Path}) ->
{i, ResolveDepPath(Path)};
(ErlOpt) ->
ErlOpt
end, Vals)
end,
Conf2 = case IsRebar3 of
true ->
DepsFun = fun(DepsList) ->
lists:filtermap(fun({rebar_elixir_plugin, _, _}) ->
false;
({DepName,_, {git,_, _} = Git}) ->
{true, {DepName, Git}};
(Dep) ->
true
end, DepsList)
end,
RB1 = ModCfg(Conf2a, [deps], DepsFun, []),
ModCfg(RB1, [plugins], fun(V) -> V -- [deps_erl_opts,
rebar_elixir_compiler,
rebar_exunit] ++
[rebar3_hex] end, []);
false ->
Conf2a
end,
ProcssXrefExclusions = fun(Items) ->
[{lists:flatten(["(XC - UC) || (XU - X - B ",
[[" - ", V] || V <- Items], ")"]),
[]}]
end,
ProcessFloatingDeps =
fun(Deps, FDeps) ->
lists:map(fun({DepName, _Ver, {git, Repo, _Commit}} = Dep) ->
case lists:member(DepName, FDeps) of
true ->
{DepName, ".*", {git, Repo}};
_ ->
Dep
end;
(Dep2) ->
Dep2
end, Deps)
end,
Conf3 = case lists:keytake(xref_exclusions, 1, Conf2) of
{value, {_, Items2}, Rest2} ->
[{xref_queries, [{lists:flatten(["(XC - UC) || (XU - X - B ",
[[" - ", V] || V <- Items2], ")"]), []}]} | Rest2];
_ ->
Conf2
end,
TravisPostHooks =
fun(true) ->
[{eunit, "echo '\n%%! -pa .eunit/ deps/coveralls/ebin\n" ++
"main(_)->{ok,F}=file:open(\"erlang.json\",[write])," ++
"io:fwrite(F,\"~s\",[coveralls:convert_file(" ++
"\".eunit/cover.coverdata\", \"" ++
os:getenv("TRAVIS_JOB_ID") ++
"\", \"travis-ci\",\"\")]).' > getcover.erl"},
{eunit, "escript ./getcover.erl"}];
(_) ->
[]
end,
Conf5 = case lists:keytake(floating_deps, 1, Conf3) of
{value, {_, FloatingDeps}, Rest4} ->
case lists:keytake(deps, 1, Rest4) of
{value, {_, Deps}, Rest41} ->
ND = lists:map(fun({DepName, Ver, {git, Repo, _Commit}}=Dep) ->
case lists:member(DepName, FloatingDeps) of
true ->
{DepName, ".*", {git, Repo}};
_ ->
Dep
end;
(Dep2) ->
Dep2
end, Deps),
[{deps, ND} | Rest41];
_ ->
Rest4
end;
_ ->
Conf3
end,
Rules = [
{[provider_hooks], IsRebar3,
AppendList([{pre, [
{compile, {asn, compile}},
{clean, {asn, clean}}
]}]), []},
{[deps], os:getenv("TRAVIS") == "true",
AppendList([{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl.git", "master"}}]), []},
{[post_hooks], [cover_enabled], os:getenv("TRAVIS") == "true",
AppendList2(TravisPostHooks), [], false},
{[pre_hooks], [post_hook_configure], true,
AppendList2(GenDepsConfigure), [], []},
{[ct_extra_params], [eunit_compile_opts], true,
AppendStr2(CtParams), "", []},
{[erl_opts], true,
ProcessErlOpt, []},
{[xref_queries], [xref_exclusions], true,
AppendList2(ProcssXrefExclusions), [], []},
{[deps], [floating_deps], true,
ProcessFloatingDeps, [], []},
{[deps], IsRebar3,
Rebar3DepsFilter, []},
{[deps], SystemDeps /= false,
GlobalDepsFilter, []}
],
%% When running Travis test, upload test coverage result to coveralls:
Conf6 = case {lists:keyfind(cover_enabled, 1, Conf5), os:getenv("TRAVIS")} of
{{cover_enabled, true}, "true"} ->
JobId = os:getenv("TRAVIS_JOB_ID"),
CfgTemp = ModCfg(Conf5, [deps], fun(V) -> [{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl.git", "master"}}|V] end, []),
ModCfg(CfgTemp, [post_hooks], fun(V) -> V ++ [{ct, "echo '\n%%! -pa ebin/ deps/coveralls/ebin\nmain(_)->{ok,F}=file:open(\"erlang.json\",[write]),io:fwrite(F,\"~s\",[coveralls:convert_file(\"logs/all.coverdata\", \""++JobId++"\", \"travis-ci\")]).' > getcover.erl"},
{ct, "escript ./getcover.erl"}] end, []);
_ ->
Conf5
end,
Config = [{plugin_dir, filename:join([filename:dirname(SCRIPT),"plugins"])}]++
FilterConfig(FilterConfig, ProcessVars(ProcessVars, CONFIG, []), Rules),
%io:format("ejabberd configuration:~n ~p~n", [Conf6]),
%io:format("ejabberd configuration:~n ~p~n", [Config]),
Conf6.
Config.
%% Local Variables:
%% mode: erlang
+1 -1
View File
@@ -1,6 +1,6 @@
%%%-------------------------------------------------------------------
%%% @author Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%% @copyright (C) 2013-2016, Evgeniy Khramtsov
%%% @copyright (C) 2013-2017, Evgeniy Khramtsov
%%% @doc
%%%
%%% @end
+105 -50
View File
@@ -1,5 +1,5 @@
--
-- ejabberd, Copyright (C) 2002-2016 ProcessOne
-- ejabberd, Copyright (C) 2002-2017 ProcessOne
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
@@ -41,7 +41,7 @@ CREATE TABLE rosterusers (
ask character(1) NOT NULL,
askmessage text NOT NULL,
server character(1) NOT NULL,
subscribe text,
subscribe text NOT NULL,
type text,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
@@ -84,6 +84,31 @@ CREATE TABLE spool (
CREATE INDEX i_despool ON spool (username);
CREATE TABLE archive (
username text NOT NULL,
timestamp BIGINT UNSIGNED NOT NULL,
peer text NOT NULL,
bare_peer text NOT NULL,
xml text NOT NULL,
txt text,
id INTEGER PRIMARY KEY AUTOINCREMENT,
kind text,
nick text,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX i_username ON archive(username);
CREATE INDEX i_timestamp ON archive(timestamp);
CREATE INDEX i_peer ON archive(peer);
CREATE INDEX i_bare_peer ON archive(bare_peer);
CREATE TABLE archive_prefs (
username text NOT NULL PRIMARY KEY,
def text NOT NULL,
always text NOT NULL,
never text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE vcard (
username text PRIMARY KEY,
@@ -91,12 +116,6 @@ CREATE TABLE vcard (
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE vcard_xupdate (
username text PRIMARY KEY,
hash text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE vcard_search (
username text NOT NULL,
lusername text PRIMARY KEY,
@@ -181,10 +200,10 @@ CREATE TABLE roster_version (
);
CREATE TABLE pubsub_node (
host text,
node text,
parent text,
type text,
host text NOT NULL,
node text NOT NULL,
parent text NOT NULL DEFAULT '',
type text NOT NULL,
nodeid INTEGER PRIMARY KEY AUTOINCREMENT
);
CREATE INDEX i_pubsub_node_parent ON pubsub_node (parent);
@@ -192,22 +211,22 @@ CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node (host, node);
CREATE TABLE pubsub_node_option (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
name text,
val text
name text NOT NULL,
val text NOT NULL
);
CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option (nodeid);
CREATE TABLE pubsub_node_owner (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
owner text
owner text NOT NULL
);
CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner (nodeid);
CREATE TABLE pubsub_state (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
jid text,
jid text NOT NULL,
affiliation character(1),
subscriptions text,
subscriptions text NOT NULL DEFAULT '',
stateid INTEGER PRIMARY KEY AUTOINCREMENT
);
CREATE INDEX i_pubsub_state_jid ON pubsub_state (jid);
@@ -215,19 +234,19 @@ CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state (nodeid, jid);
CREATE TABLE pubsub_item (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
itemid text,
publisher text,
creation text,
modification text,
payload text
itemid text NOT NULL,
publisher text NOT NULL,
creation text NOT NULL,
modification text NOT NULL,
payload text NOT NULL DEFAULT ''
);
CREATE INDEX i_pubsub_item_itemid ON pubsub_item (itemid);
CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item (nodeid, itemid);
CREATE TABLE pubsub_subscription_opt (
subid text,
subid text NOT NULL,
opt_name varchar(32),
opt_value text
opt_value text NOT NULL
);
CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt (subid, opt_name);
@@ -250,6 +269,27 @@ CREATE TABLE muc_registered (
CREATE INDEX i_muc_registered_nick ON muc_registered (nick);
CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered (jid, host);
CREATE TABLE muc_online_room (
name text NOT NULL,
host text NOT NULL,
node text NOT NULL,
pid text NOT NULL
);
CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room (name, host);
CREATE TABLE muc_online_users (
username text NOT NULL,
server text NOT NULL,
resource text NOT NULL,
name text NOT NULL,
host text NOT NULL,
node text NOT NULL
);
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users (username, server);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
@@ -274,32 +314,6 @@ CREATE TABLE caps_features (
CREATE INDEX i_caps_features_node_subnode ON caps_features (node, subnode);
CREATE TABLE archive (
username text NOT NULL,
timestamp BIGINT UNSIGNED NOT NULL,
peer text NOT NULL,
bare_peer text NOT NULL,
xml text NOT NULL,
txt text,
id INTEGER PRIMARY KEY AUTOINCREMENT,
kind text,
nick text,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX i_username ON archive(username);
CREATE INDEX i_timestamp ON archive(timestamp);
CREATE INDEX i_peer ON archive(peer);
CREATE INDEX i_bare_peer ON archive(bare_peer);
CREATE TABLE archive_prefs (
username text NOT NULL PRIMARY KEY,
def text NOT NULL,
always text NOT NULL,
never text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE sm (
usec bigint NOT NULL,
pid text NOT NULL,
@@ -320,3 +334,44 @@ CREATE TABLE oauth_token (
scope text NOT NULL,
expire bigint NOT NULL
);
CREATE TABLE route (
domain text NOT NULL,
server_host text NOT NULL,
node text NOT NULL,
pid text NOT NULL,
local_hint text NOT NULL
);
CREATE UNIQUE INDEX i_route ON route(domain, server_host, node, pid);
CREATE INDEX i_route_domain ON route(domain);
CREATE TABLE bosh (
sid text NOT NULL,
node text NOT NULL,
pid text NOT NULL
);
CREATE UNIQUE INDEX i_bosh_sid ON bosh(sid);
CREATE TABLE carboncopy (
username text NOT NULL,
resource text NOT NULL,
namespace text NOT NULL,
node text NOT NULL
);
CREATE UNIQUE INDEX i_carboncopy_ur ON carboncopy (username, resource);
CREATE INDEX i_carboncopy_user ON carboncopy (username);
CREATE TABLE proxy65 (
sid text NOT NULL,
pid_t text NOT NULL,
pid_i text NOT NULL,
node_t text NOT NULL,
node_i text NOT NULL,
jid_i text NOT NULL
);
CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 (sid);
CREATE INDEX i_proxy65_jid ON proxy65 (jid_i);
+80 -29
View File
@@ -1,5 +1,5 @@
--
-- ejabberd, Copyright (C) 2002-2015 ProcessOne
-- ejabberd, Copyright (C) 2002-2017 ProcessOne
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
@@ -125,6 +125,30 @@ CREATE TABLE [dbo].[muc_room] (
CREATE UNIQUE CLUSTERED INDEX [muc_room_name_host] ON [muc_room] (name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_online_room] (
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
[node] [text] NOT NULL,
[pid] [text] NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [muc_online_room_name_host] ON [muc_online_room] (name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[muc_online_users] (
[username] [varchar] (250) NOT NULL,
[server] [varchar] (250) NOT NULL,
[resource] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
[host] [varchar] (250) NOT NULL,
node text NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_i] ON [muc_online_users] (username, server, resource, name, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_us] ON [muc_online_users] (username, server);
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[privacy_default_list] (
[username] [varchar] (250) NOT NULL,
[name] [varchar] (250) NOT NULL,
@@ -182,11 +206,11 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[pubsub_item] (
[nodeid] [bigint] NULL,
[itemid] [varchar] (255) NULL,
[publisher] [text] NULL,
[creation] [text] NULL,
[modification] [varchar] (255) NULL,
[payload] [text] NULL
[itemid] [varchar] (255) NOT NULL,
[publisher] [text] NOT NULL,
[creation] [text] NOT NULL,
[modification] [varchar] (255) NOT NULL,
[payload] [text] NOT NULL DEFAULT ''
) TEXTIMAGE_ON [PRIMARY];
CREATE INDEX [pubsub_item_itemid] ON [pubsub_item] (itemid)
@@ -197,8 +221,8 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[pubsub_node_option] (
[nodeid] [bigint] NULL,
[name] [text] NULL,
[val] [text] NULL
[name] [text] NOT NULL,
[val] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE CLUSTERED INDEX [pubsub_node_option_nodeid] ON [pubsub_node_option] (nodeid)
@@ -206,7 +230,7 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[pubsub_node_owner] (
[nodeid] [bigint] NULL,
[owner] [text] NULL
[owner] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE CLUSTERED INDEX [pubsub_node_owner_nodeid] ON [pubsub_node_owner] (nodeid)
@@ -214,9 +238,9 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE TABLE [dbo].[pubsub_state] (
[nodeid] [bigint] NULL,
[jid] [varchar] (255) NULL,
[affiliation] [char] (1) NULL,
[subscriptions] [text] NULL,
[jid] [varchar] (255) NOT NULL,
[affiliation] [char] (1) NOT NULL,
[subscriptions] [text] NOT NULL DEFAULT '',
[stateid] [bigint] IDENTITY(1,1) NOT NULL,
CONSTRAINT [pubsub_state_PRIMARY] PRIMARY KEY CLUSTERED
(
@@ -231,19 +255,19 @@ CREATE UNIQUE INDEX [pubsub_state_nodeid_jid] ON [pubsub_state] (nodeid, jid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_subscription_opt] (
[subid] [varchar] (255) NULL,
[opt_name] [varchar] (32) NULL,
[opt_value] [text] NULL
[subid] [varchar] (255) NOT NULL,
[opt_name] [varchar] (32) NOT NULL,
[opt_value] [text] NOT NULL
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [pubsub_subscription_opt_subid_opt_name] ON [pubsub_subscription_opt] (subid, opt_name)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[pubsub_node] (
[host] [varchar] (255) NULL,
[node] [varchar] (255) NULL,
[parent] [varchar] (255) NULL,
[type] [text] NULL,
[host] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[parent] [varchar] (255) NOT NULL DEFAULT '',
[type] [text] NOT NULL,
[nodeid] [bigint] IDENTITY(1,1) NOT NULL,
CONSTRAINT [pubsub_node_PRIMARY] PRIMARY KEY CLUSTERED
(
@@ -446,16 +470,6 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
CREATE INDEX [vcard_search_lorgunit] ON [vcard_search] (lorgunit)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[vcard_xupdate] (
[username] [varchar] (250) NOT NULL,
[hash] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
CONSTRAINT [vcard_xupdate_PRIMARY] PRIMARY KEY CLUSTERED
(
[username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
ALTER TABLE [dbo].[pubsub_item] WITH CHECK ADD CONSTRAINT [pubsub_item_ibfk_1] FOREIGN KEY([nodeid])
REFERENCES [dbo].[pubsub_node] ([nodeid])
ON DELETE CASCADE;
@@ -490,3 +504,40 @@ CREATE TABLE [dbo].[oauth_token] (
[token] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[route] (
[domain] [varchar] (255) NOT NULL,
[server_host] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[pid] [varchar](100) NOT NULL,
[local_hint] [text] NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [route_i] ON [route] (domain, server_host, node, pid)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [route_domain] ON [route] (domain)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[bosh] (
[sid] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL,
[pid] [varchar](100) NOT NULL
CONSTRAINT [bosh_PRIMARY] PRIMARY KEY CLUSTERED
(
[sid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) TEXTIMAGE_ON [PRIMARY];
CREATE TABLE [dbo].[carboncopy] (
[username] [varchar] (255) NOT NULL,
[resource] [varchar] (255) NOT NULL,
[namespace] [varchar] (255) NOT NULL,
[node] [varchar] (255) NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [carboncopy_ur] ON [carboncopy] (username, resource)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE INDEX [carboncopy_user] ON [carboncopy] (username)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+79 -23
View File
@@ -1,5 +1,5 @@
--
-- ejabberd, Copyright (C) 2002-2016 ProcessOne
-- ejabberd, Copyright (C) 2002-2017 ProcessOne
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
@@ -121,12 +121,6 @@ CREATE TABLE vcard (
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE vcard_xupdate (
username varchar(191) PRIMARY KEY,
hash text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE vcard_search (
username varchar(191) NOT NULL,
lusername varchar(191) PRIMARY KEY,
@@ -218,10 +212,10 @@ CREATE TABLE roster_version (
-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
CREATE TABLE pubsub_node (
host text,
node text,
parent text,
type text,
host text NOT NULL,
node text NOT NULL,
parent VARCHAR(191) NOT NULL DEFAULT '',
type text NOT NULL,
nodeid bigint auto_increment primary key
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_pubsub_node_parent ON pubsub_node(parent(120));
@@ -229,24 +223,24 @@ CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node(host(20), node(120));
CREATE TABLE pubsub_node_option (
nodeid bigint,
name text,
val text
name text NOT NULL,
val text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option(nodeid);
ALTER TABLE `pubsub_node_option` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
CREATE TABLE pubsub_node_owner (
nodeid bigint,
owner text
owner text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner(nodeid);
ALTER TABLE `pubsub_node_owner` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
CREATE TABLE pubsub_state (
nodeid bigint,
jid text,
jid text NOT NULL,
affiliation character(1),
subscriptions text,
subscriptions VARCHAR(191) NOT NULL DEFAULT '',
stateid bigint auto_increment primary key
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_pubsub_state_jid ON pubsub_state(jid(60));
@@ -255,20 +249,20 @@ ALTER TABLE `pubsub_state` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (
CREATE TABLE pubsub_item (
nodeid bigint,
itemid text,
publisher text,
creation text,
modification text,
payload text
itemid text NOT NULL,
publisher text NOT NULL,
creation text NOT NULL,
modification text NOT NULL,
payload text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX i_pubsub_item_itemid ON pubsub_item(itemid(36));
CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item(nodeid, itemid(36));
ALTER TABLE `pubsub_item` ADD FOREIGN KEY (`nodeid`) REFERENCES `pubsub_node` (`nodeid`) ON DELETE CASCADE;
CREATE TABLE pubsub_subscription_opt (
subid text,
subid text NOT NULL,
opt_name varchar(32),
opt_value text
opt_value text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt(subid(32), opt_name(32));
@@ -291,6 +285,27 @@ CREATE TABLE muc_registered (
CREATE INDEX i_muc_registered_nick USING BTREE ON muc_registered(nick(75));
CREATE UNIQUE INDEX i_muc_registered_jid_host USING BTREE ON muc_registered(jid(75), host(75));
CREATE TABLE muc_online_room (
name text NOT NULL,
host text NOT NULL,
node text NOT NULL,
pid text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_muc_online_room_name_host USING BTREE ON muc_online_room(name(75), host(75));
CREATE TABLE muc_online_users (
username text NOT NULL,
server text NOT NULL,
resource text NOT NULL,
name text NOT NULL,
host text NOT NULL,
node text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_muc_online_users USING BTREE ON muc_online_users(username(75), server(75), resource(75), name(75), host(75));
CREATE INDEX i_muc_online_users_us USING BTREE ON muc_online_users(username(75), server(75));
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
@@ -335,3 +350,44 @@ CREATE TABLE oauth_token (
scope text NOT NULL,
expire bigint NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE route (
domain text NOT NULL,
server_host text NOT NULL,
node text NOT NULL,
pid text NOT NULL,
local_hint text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_route ON route(domain(75), server_host(75), node(75), pid(75));
CREATE INDEX i_route_domain ON route(domain(75));
CREATE TABLE bosh (
sid text NOT NULL,
node text NOT NULL,
pid text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_bosh_sid ON bosh(sid(75));
CREATE TABLE carboncopy (
username text NOT NULL,
resource text NOT NULL,
namespace text NOT NULL,
node text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_carboncopy_ur ON carboncopy (username(75), resource(75));
CREATE INDEX i_carboncopy_user ON carboncopy (username(75));
CREATE TABLE proxy65 (
sid text NOT NULL,
pid_t text NOT NULL,
pid_i text NOT NULL,
node_t text NOT NULL,
node_i text NOT NULL,
jid_i text NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 (sid(191));
CREATE INDEX i_proxy65_jid ON proxy65 (jid_i(191));
+81 -25
View File
@@ -1,5 +1,5 @@
--
-- ejabberd, Copyright (C) 2002-2016 ProcessOne
-- ejabberd, Copyright (C) 2002-2017 ProcessOne
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
@@ -10,7 +10,7 @@
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
--
-- You should have received a copy of the GNU General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -45,7 +45,7 @@ CREATE TABLE rosterusers (
ask character(1) NOT NULL,
askmessage text NOT NULL,
server character(1) NOT NULL,
subscribe text,
subscribe text NOT NULL,
"type" text,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
@@ -120,12 +120,6 @@ CREATE TABLE vcard (
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE TABLE vcard_xupdate (
username text PRIMARY KEY,
hash text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE TABLE vcard_search (
username text NOT NULL,
lusername text PRIMARY KEY,
@@ -224,10 +218,10 @@ CREATE TABLE roster_version (
-- ALTER TABLE rosterusers ALTER COLUMN askmessage SET NOT NULL;
CREATE TABLE pubsub_node (
host text,
node text,
parent text,
"type" text,
host text NOT NULL,
node text NOT NULL,
parent text NOT NULL DEFAULT '',
"type" text NOT NULL,
nodeid SERIAL UNIQUE
);
CREATE INDEX i_pubsub_node_parent ON pubsub_node USING btree (parent);
@@ -235,22 +229,22 @@ CREATE UNIQUE INDEX i_pubsub_node_tuple ON pubsub_node USING btree (host, node);
CREATE TABLE pubsub_node_option (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
name text,
val text
name text NOT NULL,
val text NOT NULL
);
CREATE INDEX i_pubsub_node_option_nodeid ON pubsub_node_option USING btree (nodeid);
CREATE TABLE pubsub_node_owner (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
owner text
owner text NOT NULL
);
CREATE INDEX i_pubsub_node_owner_nodeid ON pubsub_node_owner USING btree (nodeid);
CREATE TABLE pubsub_state (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
jid text,
jid text NOT NULL,
affiliation character(1),
subscriptions text,
subscriptions text NOT NULL DEFAULT '',
stateid SERIAL UNIQUE
);
CREATE INDEX i_pubsub_state_jid ON pubsub_state USING btree (jid);
@@ -258,19 +252,19 @@ CREATE UNIQUE INDEX i_pubsub_state_tuple ON pubsub_state USING btree (nodeid, ji
CREATE TABLE pubsub_item (
nodeid bigint REFERENCES pubsub_node(nodeid) ON DELETE CASCADE,
itemid text,
publisher text,
creation text,
modification text,
payload text
itemid text NOT NULL,
publisher text NOT NULL,
creation text NOT NULL,
modification text NOT NULL,
payload text NOT NULL DEFAULT ''
);
CREATE INDEX i_pubsub_item_itemid ON pubsub_item USING btree (itemid);
CREATE UNIQUE INDEX i_pubsub_item_tuple ON pubsub_item USING btree (nodeid, itemid);
CREATE TABLE pubsub_subscription_opt (
subid text,
subid text NOT NULL,
opt_name varchar(32),
opt_value text
opt_value text NOT NULL
);
CREATE UNIQUE INDEX i_pubsub_subscription_opt ON pubsub_subscription_opt USING btree (subid, opt_name);
@@ -293,6 +287,27 @@ CREATE TABLE muc_registered (
CREATE INDEX i_muc_registered_nick ON muc_registered USING btree (nick);
CREATE UNIQUE INDEX i_muc_registered_jid_host ON muc_registered USING btree (jid, host);
CREATE TABLE muc_online_room (
name text NOT NULL,
host text NOT NULL,
node text NOT NULL,
pid text NOT NULL
);
CREATE UNIQUE INDEX i_muc_online_room_name_host ON muc_online_room USING btree (name, host);
CREATE TABLE muc_online_users (
username text NOT NULL,
server text NOT NULL,
resource text NOT NULL,
name text NOT NULL,
host text NOT NULL,
node text NOT NULL
);
CREATE UNIQUE INDEX i_muc_online_users ON muc_online_users USING btree (username, server, resource, name, host);
CREATE INDEX i_muc_online_users_us ON muc_online_users USING btree (username, server);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
@@ -339,3 +354,44 @@ CREATE TABLE oauth_token (
);
CREATE UNIQUE INDEX i_oauth_token_token ON oauth_token USING btree (token);
CREATE TABLE route (
domain text NOT NULL,
server_host text NOT NULL,
node text NOT NULL,
pid text NOT NULL,
local_hint text NOT NULL
);
CREATE UNIQUE INDEX i_route ON route USING btree (domain, server_host, node, pid);
CREATE INDEX i_route_domain ON route USING btree (domain);
CREATE TABLE bosh (
sid text NOT NULL,
node text NOT NULL,
pid text NOT NULL
);
CREATE UNIQUE INDEX i_bosh_sid ON bosh USING btree (sid);
CREATE TABLE carboncopy (
username text NOT NULL,
resource text NOT NULL,
namespace text NOT NULL,
node text NOT NULL
);
CREATE UNIQUE INDEX i_carboncopy_ur ON carboncopy USING btree (username, resource);
CREATE INDEX i_carboncopy_user ON carboncopy USING btree (username);
CREATE TABLE proxy65 (
sid text NOT NULL,
pid_t text NOT NULL,
pid_i text NOT NULL,
node_t text NOT NULL,
node_i text NOT NULL,
jid_i text NOT NULL
);
CREATE UNIQUE INDEX i_proxy65_sid ON proxy65 USING btree (sid);
CREATE INDEX i_proxy65_jid ON proxy65 USING btree (jid_i);
+75 -32
View File
@@ -5,7 +5,7 @@
%%% Created : 18 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -25,12 +25,13 @@
-module(acl).
-behaviour(gen_server).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-export([add_access/3, clear/0]).
-export([start/0, add/3, add_list/3, add_local/3, add_list_local/3,
-export([start_link/0, add/3, add_list/3, add_local/3, add_list_local/3,
load_from_config/0, match_rule/3, any_rules_allowed/3,
transform_options/1, opt_type/1, acl_rule_matches/3,
acl_rule_verify/1, access_matches/3,
@@ -38,6 +39,9 @@
parse_ip_netmask/1,
access_rules_validator/1, shaper_rules_validator/1,
normalize_spec/1, resolve_access/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -46,6 +50,7 @@
-record(acl, {aclname, aclspec}).
-record(access, {name :: aclname(),
rules = [] :: [access_rule()]}).
-record(state, {}).
-type regexp() :: binary().
-type iprange() :: {inet:ip_address(), integer()} | binary().
@@ -75,7 +80,10 @@
-export_type([acl/0]).
start() ->
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
ejabberd_mnesia:create(?MODULE, acl,
[{ram_copies, [node()]}, {type, bag},
{local_content, true},
@@ -84,11 +92,26 @@ start() ->
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, access)}]),
mnesia:add_table_copy(acl, node(), ram_copies),
mnesia:add_table_copy(access, node(), ram_copies),
ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20),
load_from_config(),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-spec add(binary(), aclname(), aclspec()) -> ok | {error, any()}.
add(Host, ACLName, ACLSpec) ->
@@ -176,13 +199,13 @@ load_from_config() ->
lists:foreach(
fun(Host) ->
ACLs = ejabberd_config:get_option(
{acl, Host}, fun(V) -> V end, []),
{acl, Host}, []),
AccessRules = ejabberd_config:get_option(
{access, Host}, fun(V) -> V end, []),
{access, Host}, []),
AccessRulesNew = ejabberd_config:get_option(
{access_rules, Host}, fun(V) -> V end, []),
{access_rules, Host}, []),
ShaperRules = ejabberd_config:get_option(
{shaper_rules, Host}, fun(V) -> V end, []),
{shaper_rules, Host}, []),
lists:foreach(
fun({ACLName, SpecList}) ->
lists:foreach(
@@ -243,24 +266,42 @@ normalize_spec(Spec) ->
case Spec of
all -> all;
none -> none;
{acl, N} -> {acl, N};
{user, {U, S}} -> {user, {nodeprep(U), nameprep(S)}};
{user, U} -> {user, split_user_server(U, fun nodeprep/1, fun nameprep/1)};
{shared_group, {G, H}} -> {shared_group, {b(G), nameprep(H)}};
{shared_group, G} -> {shared_group, split_user_server(G, fun b/1, fun nameprep/1)};
{user_regexp, {UR, S}} -> {user_regexp, {b(UR), nameprep(S)}};
{user_regexp, UR} -> {user_regexp, split_user_server(UR, fun b/1, fun nameprep/1)};
{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, split_user_server(UR, fun b/1, fun nameprep/1)};
{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)};
{resource_regexp, R} -> {resource_regexp, b(R)};
{server_glob, S} -> {server_glob, b(S)};
{resource_glob, R} -> {resource_glob, b(R)};
{ip, {Net, Mask}} -> {ip, {Net, Mask}};
{acl, N} when is_atom(N) ->
{acl, N};
{user, {U, S}} when is_binary(U), is_binary(S) ->
{user, {nodeprep(U), nameprep(S)}};
{user, U} when is_binary(U) ->
{user, split_user_server(U, fun nodeprep/1, fun nameprep/1)};
{shared_group, {G, H}} when is_binary(G), is_binary(H) ->
{shared_group, {b(G), nameprep(H)}};
{shared_group, G} when is_binary(G) ->
{shared_group, split_user_server(G, fun b/1, fun nameprep/1)};
{user_regexp, {UR, S}} when is_binary(UR), is_binary(S) ->
{user_regexp, {b(UR), nameprep(S)}};
{user_regexp, UR} when is_binary(UR) ->
{user_regexp, split_user_server(UR, fun b/1, fun nameprep/1)};
{node_regexp, {UR, SR}} when is_binary(UR), is_binary(SR) ->
{node_regexp, {b(UR), b(SR)}};
{user_glob, {UR, S}} when is_binary(UR), is_binary(S) ->
{user_glob, {b(UR), nameprep(S)}};
{user_glob, UR} when is_binary(UR) ->
{user_glob, split_user_server(UR, fun b/1, fun nameprep/1)};
{node_glob, {UR, SR}} when is_binary(UR), is_binary(SR) ->
{node_glob, {b(UR), b(SR)}};
{server, S} when is_binary(S) ->
{server, nameprep(S)};
{resource, R} when is_binary(R) ->
{resource, resourceprep(R)};
{server_regexp, SR} when is_binary(SR) ->
{server_regexp, b(SR)};
{resource_regexp, R} when is_binary(R) ->
{resource_regexp, b(R)};
{server_glob, S} when is_binary(S) ->
{server_glob, b(S)};
{resource_glob, R} when is_binary(R) ->
{resource_glob, b(R)};
{ip, {Net, Mask}} when is_binary(Net), is_integer(Mask) ->
{ip, {Net, Mask}};
{ip, S} ->
case parse_ip_netmask(b(S)) of
{ok, Net, Mask} ->
@@ -268,10 +309,12 @@ normalize_spec(Spec) ->
error ->
?INFO_MSG("Invalid network address: ~p", [S]),
none
end
end;
BadVal ->
throw({<<"Invalid acl value">>, BadVal})
end.
-spec any_rules_allowed(global | binary(), access_name(),
-spec any_rules_allowed(global | binary(), [access_name()],
jid() | ljid() | inet:ip_address()) -> boolean().
any_rules_allowed(Host, Access, Entity) ->
@@ -460,7 +503,7 @@ resolve_access(Name, Host) when is_atom(Name) ->
resolve_access(Rules, _Host) when is_list(Rules) ->
Rules.
-spec access_matches(atom()|list(), any(), global|binary()) -> allow|deny.
-spec access_matches(atom()|list(), any(), global|binary()) -> allow|deny|atom()|integer().
access_matches(Rules, Data, Host) ->
case resolve_access(Rules, Host) of
all -> allow;
@@ -582,7 +625,7 @@ access_rules_validator(Rules0) ->
(deny) -> true;
(_) -> false
end),
throw({replace_with, Rules}).
Rules.
shaper_rules_validator(Name) when is_atom(Name) ->
@@ -593,7 +636,7 @@ shaper_rules_validator(Rules0) ->
(V2) when is_integer(V2) -> true;
(_) -> false
end),
throw({replace_with, Rules}).
Rules.
access_shaper_rules_validator([{Type, Acls} = Rule | Rest], RuleTypeCheck) ->
case RuleTypeCheck(Type) of
+91 -73
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -25,23 +25,20 @@
-module(cyrsasl).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-behaviour(gen_server).
-export([start/0, register_mechanism/3, listmech/1,
-export([start_link/0, register_mechanism/3, listmech/1,
server_new/7, server_start/3, server_step/2,
opt_type/1]).
get_mech/1, format_error/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
%%
-export_type([
mechanism/0,
mechanisms/0,
sasl_mechanism/0
]).
-record(state, {}).
-record(sasl_mechanism,
{mechanism = <<"">> :: mechanism() | '$1',
@@ -51,12 +48,22 @@
-type(mechanism() :: binary()).
-type(mechanisms() :: [mechanism(),...]).
-type(password_type() :: plain | digest | scram).
-type(props() :: [{username, binary()} |
{authzid, binary()} |
{auth_module, atom()}]).
-type sasl_property() :: {username, binary()} |
{authzid, binary()} |
{mechanism, binary()} |
{auth_module, atom()}.
-type sasl_return() :: {ok, [sasl_property()]} |
{ok, [sasl_property()], binary()} |
{continue, binary(), sasl_state()} |
{error, atom(), binary()}.
-type(sasl_mechanism() :: #sasl_mechanism{}).
-type error_reason() :: cyrsasl_digest:error_reason() |
cyrsasl_oauth:error_reason() |
cyrsasl_plain:error_reason() |
cyrsasl_scram:error_reason() |
unsupported_mechanism | nodeprep_failed |
empty_username | aborted.
-record(sasl_state,
{
service,
@@ -65,18 +72,23 @@
get_password,
check_password,
check_password_digest,
mech_name = <<"">>,
mech_mod,
mech_state
}).
-type sasl_state() :: #sasl_state{}.
-export_type([mechanism/0, mechanisms/0, sasl_mechanism/0, error_reason/0,
sasl_state/0, sasl_return/0, sasl_property/0]).
-callback start(list()) -> any().
-callback stop() -> any().
-callback mech_new(binary(), fun(), fun(), fun()) -> any().
-callback mech_step(any(), binary()) -> {ok, props()} |
{ok, props(), binary()} |
{continue, binary(), any()} |
{error, atom()} |
{error, atom(), binary()}.
-callback mech_step(any(), binary()) -> sasl_return().
start() ->
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
ets:new(sasl_mechanism,
[named_table, public,
{keypos, #sasl_mechanism.mechanism}]),
@@ -85,35 +97,67 @@ start() ->
cyrsasl_scram:start([]),
cyrsasl_anonymous:start([]),
cyrsasl_oauth:start([]),
ok.
{ok, #state{}}.
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
cyrsasl_plain:stop(),
cyrsasl_digest:stop(),
cyrsasl_scram:stop(),
cyrsasl_anonymous:stop(),
cyrsasl_oauth:stop().
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-spec format_error(mechanism() | sasl_state(), error_reason()) -> {atom(), binary()}.
format_error(_, unsupported_mechanism) ->
{'invalid-mechanism', <<"Unsupported mechanism">>};
format_error(_, nodeprep_failed) ->
{'bad-protocol', <<"Nodeprep failed">>};
format_error(_, empty_username) ->
{'bad-protocol', <<"Empty username">>};
format_error(_, aborted) ->
{'aborted', <<"Aborted">>};
format_error(#sasl_state{mech_mod = Mod}, Reason) ->
Mod:format_error(Reason);
format_error(Mech, Reason) ->
case ets:lookup(sasl_mechanism, Mech) of
[#sasl_mechanism{module = Mod}] ->
Mod:format_error(Reason);
[] ->
{'invalid-mechanism', <<"Unsupported mechanism">>}
end.
%%
-spec register_mechanism(Mechanim :: mechanism(), Module :: module(),
PasswordType :: password_type()) -> any().
register_mechanism(Mechanism, Module, PasswordType) ->
case is_disabled(Mechanism) of
false ->
ets:insert(sasl_mechanism,
#sasl_mechanism{mechanism = Mechanism, module = Module,
password_type = PasswordType});
true ->
?DEBUG("SASL mechanism ~p is disabled", [Mechanism]),
true
end.
password_type = PasswordType}).
check_credentials(_State, Props) ->
User = proplists:get_value(authzid, Props, <<>>),
case jid:nodeprep(User) of
error -> {error, 'not-authorized'};
<<"">> -> {error, 'not-authorized'};
error -> {error, nodeprep_failed};
<<"">> -> {error, empty_username};
_LUser -> ok
end.
-spec listmech(Host ::binary()) -> Mechanisms::mechanisms().
listmech(Host) ->
Mechs = ets:select(sasl_mechanism,
ets:select(sasl_mechanism,
[{#sasl_mechanism{mechanism = '$1',
password_type = '$2', _ = '_'},
case catch ejabberd_auth:store_type(Host) of
@@ -125,9 +169,10 @@ listmech(Host) ->
[];
_Else -> []
end,
['$1']}]),
filter_anonymous(Host, Mechs).
['$1']}]).
-spec server_new(binary(), binary(), binary(), term(),
fun(), fun(), fun()) -> sasl_state().
server_new(Service, ServerFQDN, UserRealm, _SecFlags,
GetPassword, CheckPassword, CheckPasswordDigest) ->
#sasl_state{service = Service, myname = ServerFQDN,
@@ -135,8 +180,7 @@ server_new(Service, ServerFQDN, UserRealm, _SecFlags,
check_password = CheckPassword,
check_password_digest = CheckPasswordDigest}.
server_start(State, Mech, undefined) ->
server_start(State, Mech, <<"">>);
-spec server_start(sasl_state(), mechanism(), binary()) -> sasl_return().
server_start(State, Mech, ClientIn) ->
case lists:member(Mech,
listmech(State#sasl_state.myname))
@@ -150,15 +194,15 @@ server_start(State, Mech, ClientIn) ->
State#sasl_state.check_password,
State#sasl_state.check_password_digest),
server_step(State#sasl_state{mech_mod = Module,
mech_name = Mech,
mech_state = MechState},
ClientIn);
_ -> {error, 'no-mechanism'}
_ -> {error, unsupported_mechanism, <<"">>}
end;
false -> {error, 'no-mechanism'}
false -> {error, unsupported_mechanism, <<"">>}
end.
server_step(State, undefined) ->
server_step(State, <<"">>);
-spec server_step(sasl_state(), binary()) -> sasl_return().
server_step(State, ClientIn) ->
Module = State#sasl_state.mech_mod,
MechState = State#sasl_state.mech_state,
@@ -166,47 +210,21 @@ server_step(State, ClientIn) ->
{ok, Props} ->
case check_credentials(State, Props) of
ok -> {ok, Props};
{error, Error} -> {error, Error}
{error, Error} -> {error, Error, <<"">>}
end;
{ok, Props, ServerOut} ->
case check_credentials(State, Props) of
ok -> {ok, Props, ServerOut};
{error, Error} -> {error, Error}
{error, Error} -> {error, Error, <<"">>}
end;
{continue, ServerOut, NewMechState} ->
{continue, ServerOut, State#sasl_state{mech_state = NewMechState}};
{error, Error, Username} ->
{error, Error, Username};
{error, Error} ->
{error, Error}
{error, Error, <<"">>}
end.
%% Remove the anonymous mechanism from the list if not enabled for the given
%% host
%%
-spec filter_anonymous(Host :: binary(), Mechs :: mechanisms()) -> mechanisms().
filter_anonymous(Host, Mechs) ->
case ejabberd_auth_anonymous:is_sasl_anonymous_enabled(Host) of
true -> Mechs;
false -> Mechs -- [<<"ANONYMOUS">>]
end.
-spec is_disabled(Mechanism :: mechanism()) -> boolean().
is_disabled(Mechanism) ->
Disabled = ejabberd_config:get_option(
disable_sasl_mechanisms,
fun(V) when is_list(V) ->
lists:map(fun(M) -> str:to_upper(M) end, V);
(V) ->
[str:to_upper(V)]
end, []),
lists:member(Mechanism, Disabled).
opt_type(disable_sasl_mechanisms) ->
fun (V) when is_list(V) ->
lists:map(fun (M) -> str:to_upper(M) end, V);
(V) -> [str:to_upper(V)]
end;
opt_type(_) -> [disable_sasl_mechanisms].
-spec get_mech(sasl_state()) -> binary().
get_mech(#sasl_state{mech_name = Mech}) ->
Mech.
+6 -8
View File
@@ -6,7 +6,7 @@
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -35,18 +35,16 @@
-record(state, {server = <<"">> :: binary()}).
start(_Opts) ->
cyrsasl:register_mechanism(<<"ANONYMOUS">>, ?MODULE, plain),
ok.
cyrsasl:register_mechanism(<<"ANONYMOUS">>, ?MODULE, plain).
stop() -> ok.
mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
{ok, #state{server = Host}}.
mech_step(#state{server = Server} = S, ClientIn) ->
mech_step(#state{}, _ClientIn) ->
User = iolist_to_binary([randoms:get_string(),
integer_to_binary(p1_time_compat:unique_integer([positive]))]),
case ejabberd_auth:is_user_exists(User, Server) of
true -> mech_step(S, ClientIn);
false -> {ok, [{username, User}, {authzid, User}, {auth_module, ejabberd_auth_anonymous}]}
end.
{ok, [{username, User},
{authzid, User},
{auth_module, ejabberd_auth_anonymous}]}.
+44 -40
View File
@@ -5,7 +5,7 @@
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -30,7 +30,7 @@
-author('alexey@sevcom.net').
-export([start/1, stop/0, mech_new/4, mech_step/2,
parse/1, opt_type/1]).
parse/1, format_error/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -39,31 +39,43 @@
-type get_password_fun() :: fun((binary()) -> {false, any()} |
{binary(), atom()}).
-type check_password_fun() :: fun((binary(), binary(), binary(),
-type check_password_fun() :: fun((binary(), binary(), binary(), binary(),
fun((binary()) -> binary())) ->
{boolean(), any()} |
false).
-type error_reason() :: parser_failed | invalid_digest_uri |
not_authorized | unexpected_response.
-export_type([error_reason/0]).
-record(state, {step = 1 :: 1 | 3 | 5,
nonce = <<"">> :: binary(),
username = <<"">> :: binary(),
authzid = <<"">> :: binary(),
get_password = fun(_) -> {false, <<>>} end :: get_password_fun(),
check_password = fun(_, _, _, _, _) -> false end :: check_password_fun(),
get_password :: get_password_fun(),
check_password :: check_password_fun(),
auth_module :: atom(),
host = <<"">> :: binary(),
hostfqdn = <<"">> :: binary() | [binary()]}).
hostfqdn = [] :: [binary()]}).
start(_Opts) ->
Fqdn = get_local_fqdn(),
?INFO_MSG("FQDN used to check DIGEST-MD5 SASL authentication: ~p",
?INFO_MSG("FQDN used to check DIGEST-MD5 SASL authentication: ~s",
[Fqdn]),
cyrsasl:register_mechanism(<<"DIGEST-MD5">>, ?MODULE,
digest).
stop() -> ok.
-spec format_error(error_reason()) -> {atom(), binary()}.
format_error(parser_failed) ->
{'bad-protocol', <<"Response decoding failed">>};
format_error(invalid_digest_uri) ->
{'bad-protocol', <<"Invalid digest URI">>};
format_error(not_authorized) ->
{'not-authorized', <<"Invalid username or password">>};
format_error(unexpected_response) ->
{'bad-protocol', <<"Unexpected response">>}.
mech_new(Host, GetPassword, _CheckPassword,
CheckPasswordDigest) ->
{ok,
@@ -80,8 +92,8 @@ mech_step(#state{step = 1, nonce = Nonce} = State, _) ->
mech_step(#state{step = 3, nonce = Nonce} = State,
ClientIn) ->
case parse(ClientIn) of
bad -> {error, 'bad-protocol'};
KeyVals ->
bad -> {error, parser_failed};
KeyVals ->
DigestURI = proplists:get_value(<<"digest-uri">>, KeyVals, <<>>),
UserName = proplists:get_value(<<"username">>, KeyVals, <<>>),
case is_digesturi_valid(DigestURI, State#state.host,
@@ -92,14 +104,14 @@ mech_step(#state{step = 3, nonce = Nonce} = State,
"seems invalid: ~p (checking for Host "
"~p, FQDN ~p)",
[DigestURI, State#state.host, State#state.hostfqdn]),
{error, 'not-authorized', UserName};
{error, invalid_digest_uri, UserName};
true ->
AuthzId = proplists:get_value(<<"authzid">>, KeyVals, <<>>),
case (State#state.get_password)(UserName) of
{false, _} -> {error, 'not-authorized', UserName};
{false, _} -> {error, not_authorized, UserName};
{Passwd, AuthModule} ->
case (State#state.check_password)(UserName, UserName, <<"">>,
proplists:get_value(<<"response">>, KeyVals, <<>>),
proplists:get_value(<<"response">>, KeyVals, <<>>),
fun (PW) ->
response(KeyVals,
UserName,
@@ -116,8 +128,8 @@ mech_step(#state{step = 3, nonce = Nonce} = State,
State#state{step = 5, auth_module = AuthModule,
username = UserName,
authzid = AuthzId}};
false -> {error, 'not-authorized', UserName};
{false, _} -> {error, 'not-authorized', UserName}
false -> {error, not_authorized, UserName};
{false, _} -> {error, not_authorized, UserName}
end
end
end
@@ -134,7 +146,7 @@ mech_step(#state{step = 5, auth_module = AuthModule,
{auth_module, AuthModule}]};
mech_step(A, B) ->
?DEBUG("SASL DIGEST: A ~p B ~p", [A, B]),
{error, 'bad-protocol'}.
{error, unexpected_response}.
parse(S) -> parse1(binary_to_list(S), "", []).
@@ -192,8 +204,6 @@ is_digesturi_valid(DigestURICase, JabberDomain,
false
end.
is_host_fqdn(Host, Fqdn) when is_binary(Fqdn) ->
Host == Fqdn;
is_host_fqdn(_Host, []) ->
false;
is_host_fqdn(Host, [Fqdn | _FqdnTail]) when Host == Fqdn ->
@@ -202,30 +212,17 @@ is_host_fqdn(Host, [Fqdn | FqdnTail]) when Host /= Fqdn ->
is_host_fqdn(Host, FqdnTail).
get_local_fqdn() ->
case catch get_local_fqdn2() of
Str when is_binary(Str) -> Str;
List when is_list(List) -> List;
_ ->
<<"unknown-fqdn, please configure fqdn "
"option in ejabberd.yml!">>
end.
get_local_fqdn2() ->
case ejabberd_config:get_option(
fqdn, fun(X) -> X end) of
ConfiguredFqdn when is_binary(ConfiguredFqdn) ->
ConfiguredFqdn;
[A | _] = ConfiguredFqdns when is_binary(A) ->
ConfiguredFqdns;
undefined ->
{ok, Hostname} = inet:gethostname(),
{ok, {hostent, Fqdn, _, _, _, _}} =
inet:gethostbyname(Hostname),
list_to_binary(Fqdn)
case ejabberd_config:get_option(fqdn) of
undefined ->
{ok, Hostname} = inet:gethostname(),
{ok, {hostent, Fqdn, _, _, _, _}} = inet:gethostbyname(Hostname),
[list_to_binary(Fqdn)];
Fqdn ->
Fqdn
end.
hex(S) ->
p1_sha:to_hexlist(S).
str:to_hexlist(S).
proplists_get_bin_value(Key, Pairs, Default) ->
case proplists:get_value(Key, Pairs, Default) of
@@ -263,5 +260,12 @@ response(KeyVals, User, Passwd, Nonce, AuthzId,
":", (hex((erlang:md5(A2))))/binary>>,
hex((erlang:md5(T))).
opt_type(fqdn) -> fun iolist_to_binary/1;
-spec opt_type(fqdn) -> fun((binary() | [binary()]) -> [binary()]);
(atom()) -> [atom()].
opt_type(fqdn) ->
fun(FQDN) when is_binary(FQDN) ->
[FQDN];
(FQDNs) when is_list(FQDNs) ->
[iolist_to_binary(FQDN) || FQDN <- FQDNs]
end;
opt_type(_) -> [fqdn].
+23 -10
View File
@@ -5,7 +5,7 @@
%%% Created : 17 Sep 2015 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,18 +27,25 @@
-author('alexey@process-one.net').
-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1, format_error/1]).
-behaviour(cyrsasl).
-record(state, {host}).
-type error_reason() :: parser_failed | not_authorized.
-export_type([error_reason/0]).
start(_Opts) ->
cyrsasl:register_mechanism(<<"X-OAUTH2">>, ?MODULE, plain),
ok.
cyrsasl:register_mechanism(<<"X-OAUTH2">>, ?MODULE, plain).
stop() -> ok.
-spec format_error(error_reason()) -> {atom(), binary()}.
format_error(parser_failed) ->
{'bad-protocol', <<"Response decoding failed">>};
format_error(not_authorized) ->
{'not-authorized', <<"Invalid token">>}.
mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
{ok, #state{host = Host}}.
@@ -46,15 +53,15 @@ mech_step(State, ClientIn) ->
case prepare(ClientIn) of
[AuthzId, User, Token] ->
case ejabberd_oauth:check_token(
User, State#state.host, <<"sasl_auth">>, Token) of
User, State#state.host, [<<"sasl_auth">>], Token) of
true ->
{ok,
[{username, User}, {authzid, AuthzId},
{auth_module, ejabberd_oauth}]};
_ ->
{error, 'not-authorized', User}
{error, not_authorized, User}
end;
_ -> {error, 'bad-protocol'}
_ -> {error, parser_failed}
end.
prepare(ClientIn) ->
@@ -62,12 +69,18 @@ prepare(ClientIn) ->
[<<"">>, UserMaybeDomain, Token] ->
case parse_domain(UserMaybeDomain) of
%% <NUL>login@domain<NUL>pwd
[User, _Domain] -> [UserMaybeDomain, User, Token];
[User, _Domain] -> [User, User, Token];
%% <NUL>login<NUL>pwd
[User] -> [<<"">>, User, Token]
[User] -> [User, User, Token]
end;
%% login@domain<NUL>login<NUL>pwd
[AuthzId, User, Token] -> [AuthzId, User, Token];
[AuthzId, User, Token] ->
case parse_domain(AuthzId) of
%% login@domain<NUL>login<NUL>pwd
[AuthzUser, _Domain] -> [AuthzUser, User, Token];
%% login<NUL>login<NUL>pwd
[AuthzUser] -> [AuthzUser, User, Token]
end;
_ -> error
end.
+13 -6
View File
@@ -5,7 +5,7 @@
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,18 +27,25 @@
-author('alexey@process-one.net').
-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
-export([start/1, stop/0, mech_new/4, mech_step/2, parse/1, format_error/1]).
-behaviour(cyrsasl).
-record(state, {check_password}).
-type error_reason() :: parser_failed | not_authorized.
-export_type([error_reason/0]).
start(_Opts) ->
cyrsasl:register_mechanism(<<"PLAIN">>, ?MODULE, plain),
ok.
cyrsasl:register_mechanism(<<"PLAIN">>, ?MODULE, plain).
stop() -> ok.
-spec format_error(error_reason()) -> {atom(), binary()}.
format_error(parser_failed) ->
{'bad-protocol', <<"Response decoding failed">>};
format_error(not_authorized) ->
{'not-authorized', <<"Invalid username or password">>}.
mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
{ok, #state{check_password = CheckPassword}}.
@@ -50,9 +57,9 @@ mech_step(State, ClientIn) ->
{ok,
[{username, User}, {authzid, AuthzId},
{auth_module, AuthModule}]};
_ -> {error, 'not-authorized', User}
_ -> {error, not_authorized, User}
end;
_ -> {error, 'bad-protocol'}
_ -> {error, parser_failed}
end.
prepare(ClientIn) ->
+75 -45
View File
@@ -5,7 +5,7 @@
%%% Created : 7 Aug 2011 by Stephen Röttger <stephen.roettger@googlemail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -29,7 +29,7 @@
-protocol({rfc, 5802}).
-export([start/1, stop/0, mech_new/4, mech_step/2]).
-export([start/1, stop/0, mech_new/4, mech_step/2, format_error/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -41,22 +41,47 @@
stored_key = <<"">> :: binary(),
server_key = <<"">> :: binary(),
username = <<"">> :: binary(),
get_password :: fun(),
check_password :: fun(),
auth_module :: module(),
get_password :: fun((binary()) ->
{false | ejabberd_auth:password(), module()}),
auth_message = <<"">> :: binary(),
client_nonce = <<"">> :: binary(),
server_nonce = <<"">> :: binary()}).
-define(SALT_LENGTH, 16).
-define(NONCE_LENGTH, 16).
-type error_reason() :: unsupported_extension | bad_username |
not_authorized | saslprep_failed |
parser_failed | bad_attribute |
nonce_mismatch | bad_channel_binding.
-export_type([error_reason/0]).
start(_Opts) ->
cyrsasl:register_mechanism(<<"SCRAM-SHA-1">>, ?MODULE,
scram).
stop() -> ok.
-spec format_error(error_reason()) -> {atom(), binary()}.
format_error(unsupported_extension) ->
{'bad-protocol', <<"Unsupported extension">>};
format_error(bad_username) ->
{'invalid-authzid', <<"Malformed username">>};
format_error(not_authorized) ->
{'not-authorized', <<"Invalid username or password">>};
format_error(saslprep_failed) ->
{'not-authorized', <<"SASLprep failed">>};
format_error(parser_failed) ->
{'bad-protocol', <<"Response decoding failed">>};
format_error(bad_attribute) ->
{'bad-protocol', <<"Malformed or unexpected attribute">>};
format_error(nonce_mismatch) ->
{'bad-protocol', <<"Nonce mismatch">>};
format_error(bad_channel_binding) ->
{'bad-protocol', <<"Invalid channel binding">>}.
mech_new(_Host, GetPassword, _CheckPassword,
_CheckPasswordDigest) ->
{ok, #state{step = 2, get_password = GetPassword}}.
@@ -64,30 +89,38 @@ mech_new(_Host, GetPassword, _CheckPassword,
mech_step(#state{step = 2} = State, ClientIn) ->
case re:split(ClientIn, <<",">>, [{return, binary}]) of
[_CBind, _AuthorizationIdentity, _UserNameAttribute, _ClientNonceAttribute, ExtensionAttribute | _]
when ExtensionAttribute /= [] ->
{error, 'protocol-error-extension-not-supported'};
when ExtensionAttribute /= <<"">> ->
{error, unsupported_extension};
[CBind, _AuthorizationIdentity, UserNameAttribute, ClientNonceAttribute | _]
when (CBind == <<"y">>) or (CBind == <<"n">>) ->
case parse_attribute(UserNameAttribute) of
{error, Reason} -> {error, Reason};
{_, EscapedUserName} ->
case unescape_username(EscapedUserName) of
error -> {error, 'protocol-error-bad-username'};
error -> {error, bad_username};
UserName ->
case parse_attribute(ClientNonceAttribute) of
{$r, ClientNonce} ->
{Ret, _AuthModule} = (State#state.get_password)(UserName),
case {Ret, jid:resourceprep(Ret)} of
{false, _} -> {error, 'not-authorized', UserName};
{_, error} when is_binary(Ret) -> ?WARNING_MSG("invalid plain password", []), {error, 'not-authorized', UserName};
{Ret, _} ->
{Pass, AuthModule} = (State#state.get_password)(UserName),
LPass = if is_binary(Pass) -> jid:resourceprep(Pass);
true -> Pass
end,
if Pass == false ->
{error, not_authorized, UserName};
LPass == error ->
{error, saslprep_failed, UserName};
true ->
{StoredKey, ServerKey, Salt, IterationCount} =
if is_tuple(Ret) -> Ret;
if is_record(Pass, scram) ->
{base64:decode(Pass#scram.storedkey),
base64:decode(Pass#scram.serverkey),
base64:decode(Pass#scram.salt),
Pass#scram.iterationcount};
true ->
TempSalt =
randoms:bytes(?SALT_LENGTH),
SaltedPassword =
scram:salted_password(Ret,
scram:salted_password(Pass,
TempSalt,
?SCRAM_DEFAULT_ITERATION_COUNT),
{scram:stored_key(scram:client_key(SaltedPassword)),
@@ -99,19 +132,20 @@ mech_step(#state{step = 2} = State, ClientIn) ->
str:substr(ClientIn,
str:str(ClientIn, <<"n=">>)),
ServerNonce =
jlib:encode_base64(randoms:bytes(?NONCE_LENGTH)),
base64:encode(randoms:bytes(?NONCE_LENGTH)),
ServerFirstMessage =
iolist_to_binary(
["r=",
ClientNonce,
ServerNonce,
",", "s=",
jlib:encode_base64(Salt),
base64:encode(Salt),
",", "i=",
integer_to_list(IterationCount)]),
{continue, ServerFirstMessage,
State#state{step = 4, stored_key = StoredKey,
server_key = ServerKey,
auth_module = AuthModule,
auth_message =
<<ClientFirstMessageBare/binary,
",", ServerFirstMessage/binary>>,
@@ -119,11 +153,11 @@ mech_step(#state{step = 2} = State, ClientIn) ->
server_nonce = ServerNonce,
username = UserName}}
end;
_Else -> {error, 'not-supported'}
_ -> {error, bad_attribute}
end
end
end;
_Else -> {error, 'bad-protocol'}
_Else -> {error, parser_failed}
end;
mech_step(#state{step = 4} = State, ClientIn) ->
case str:tokens(ClientIn, <<",">>) of
@@ -131,7 +165,9 @@ mech_step(#state{step = 4} = State, ClientIn) ->
ClientProofAttribute] ->
case parse_attribute(GS2ChannelBindingAttribute) of
{$c, CVal} ->
ChannelBindingSupport = binary:at(jlib:decode_base64(CVal), 0),
ChannelBindingSupport = try binary:first(base64:decode(CVal))
catch _:badarg -> 0
end,
if (ChannelBindingSupport == $n)
or (ChannelBindingSupport == $y) ->
Nonce = <<(State#state.client_nonce)/binary,
@@ -140,7 +176,9 @@ mech_step(#state{step = 4} = State, ClientIn) ->
{$r, CompareNonce} when CompareNonce == Nonce ->
case parse_attribute(ClientProofAttribute) of
{$p, ClientProofB64} ->
ClientProof = jlib:decode_base64(ClientProofB64),
ClientProof = try base64:decode(ClientProofB64)
catch _:badarg -> <<>>
end,
AuthMessage = iolist_to_binary(
[State#state.auth_message,
",",
@@ -158,39 +196,31 @@ mech_step(#state{step = 4} = State, ClientIn) ->
scram:server_signature(State#state.server_key,
AuthMessage),
{ok, [{username, State#state.username},
{auth_module, State#state.auth_module},
{authzid, State#state.username}],
<<"v=",
(jlib:encode_base64(ServerSignature))/binary>>};
true -> {error, 'bad-auth', State#state.username}
(base64:encode(ServerSignature))/binary>>};
true -> {error, not_authorized, State#state.username}
end;
_Else -> {error, 'bad-protocol'}
_ -> {error, bad_attribute}
end;
{$r, _} -> {error, 'bad-nonce'};
_Else -> {error, 'bad-protocol'}
{$r, _} -> {error, nonce_mismatch};
_ -> {error, bad_attribute}
end;
true -> {error, 'bad-channel-binding'}
true -> {error, bad_channel_binding}
end;
_Else -> {error, 'bad-protocol'}
_ -> {error, bad_attribute}
end;
_Else -> {error, 'bad-protocol'}
_ -> {error, parser_failed}
end.
parse_attribute(Attribute) ->
AttributeLen = byte_size(Attribute),
if AttributeLen >= 3 ->
AttributeS = binary_to_list(Attribute),
SecondChar = lists:nth(2, AttributeS),
case is_alpha(lists:nth(1, AttributeS)) of
true ->
if SecondChar == $= ->
String = str:substr(Attribute, 3),
{lists:nth(1, AttributeS), String};
true -> {error, 'bad-format-second-char-not-equal-sign'}
end;
_Else -> {error, 'bad-format-first-char-not-a-letter'}
end;
true -> {error, 'bad-format-attribute-too-short'}
end.
parse_attribute(<<Name, $=, Val/binary>>) when Val /= <<>> ->
case is_alpha(Name) of
true -> {Name, Val};
false -> {error, bad_attribute}
end;
parse_attribute(_) ->
{error, bad_attribute}.
unescape_username(<<"">>) -> <<"">>;
unescape_username(EscapedUsername) ->
+1 -1
View File
@@ -5,7 +5,7 @@
%%% Created : 16 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
+37 -35
View File
@@ -5,7 +5,7 @@
%%% Created : 7 Sep 2016 by Paweł Chmielowski <pawel@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -109,6 +109,7 @@ start_link() ->
{ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} |
{stop, Reason :: term()} | ignore.
init([]) ->
ejabberd_hooks:add(config_reloaded, ?MODULE, invalidate, 90),
{ok, #state{}}.
%%--------------------------------------------------------------------
@@ -209,7 +210,7 @@ handle_info(_Info, State) ->
-spec terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
State :: #state{}) -> term().
terminate(_Reason, _State) ->
ok.
ejabberd_hooks:delete(config_reloaded, ?MODULE, invalidate, 90).
%%--------------------------------------------------------------------
%% @private
@@ -230,30 +231,33 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
-spec get_definitions(#state{}) -> {#state{}, any()}.
get_definitions(#state{definitions = Defs, fragments_generators = Gens} = State) ->
DefaultOptions = [{<<"console commands">>,
{[ejabberd_ctl],
[{acl, all}],
{all, none}}},
{<<"admin access">>,
get_definitions(#state{definitions = Defs} = State) when Defs /= none ->
{State, Defs};
get_definitions(#state{definitions = none, fragments_generators = Gens} = State) ->
DefaultOptions = [{<<"admin access">>,
{[],
[{acl, admin}],
[{acl,{acl,admin}},
{oauth,[<<"ejabberd:admin">>],[{acl,{acl,admin}}]}],
{all, [start, stop]}}}],
NDefs = case Defs of
none ->
ApiPerms = ejabberd_config:get_option(api_permissions, fun(A) -> A end, DefaultOptions),
AllCommands = ejabberd_commands:get_commands_definition(),
Frags = lists:foldl(
fun({_Name, Generator}, Acc) ->
Acc ++ Generator()
end, [], Gens),
lists:map(
fun({Name, {From, Who, {Add, Del}}}) ->
Cmds = filter_commands_with_permissions(AllCommands, Add, Del),
{Name, {From, Who, Cmds}}
end, ApiPerms ++ Frags);
V ->
V
ApiPerms = ejabberd_config:get_option(api_permissions, DefaultOptions),
AllCommands = ejabberd_commands:get_commands_definition(),
Frags = lists:foldl(
fun({_Name, Generator}, Acc) ->
Acc ++ Generator()
end, [], Gens),
NDefs0 = lists:map(
fun({Name, {From, Who, {Add, Del}}}) ->
Cmds = filter_commands_with_permissions(AllCommands, Add, Del),
{Name, {From, Who, Cmds}}
end, ApiPerms ++ Frags),
NDefs = case lists:keyfind(<<"console commands">>, 1, NDefs0) of
false ->
[{<<"console commands">>,
{[ejabberd_ctl],
[{acl, all}],
filter_commands_with_permissions(AllCommands, all, none)}} | NDefs0];
_ ->
NDefs0
end,
{State#state{definitions = NDefs}, NDefs}.
@@ -274,7 +278,7 @@ matches_definition({_Name, {From, Who, What}}, Cmd, Module, Host, CallerInfo) ->
lists:any(
fun({access, Access}) ->
acl:access_matches(Access, CallerInfo, Host) == allow;
({acl, Acl} = Acl) ->
({acl, Acl}) ->
acl:acl_rule_matches(Acl, CallerInfo, Host)
end, List);
_ ->
@@ -329,7 +333,7 @@ command_matches_patterns(C, [_ | Tail]) ->
%%%===================================================================
parse_api_permissions(Data) when is_list(Data) ->
throw({replace_with, [parse_api_permission(Name, Args) || {Name, Args} <- Data]}).
[parse_api_permission(Name, Args) || {Name, Args} <- Data].
parse_api_permission(Name, Args0) ->
Args = lists:flatten(Args0),
@@ -358,7 +362,10 @@ parse_who(Name, Atom, ParseOauth) when is_atom(Atom) ->
parse_who(Name, [Atom], ParseOauth);
parse_who(Name, Defs, ParseOauth) when is_list(Defs) ->
lists:map(
fun([{access, Val}]) ->
fun([Val]) ->
[NVal] = parse_who(Name, [Val], ParseOauth),
NVal;
({access, Val}) ->
try acl:access_rules_validator(Val) of
Rule ->
{access, Rule}
@@ -366,13 +373,11 @@ parse_who(Name, Defs, ParseOauth) when is_list(Defs) ->
throw:{invalid_syntax, Msg} ->
report_error(<<"Invalid access rule: '~s' used inside 'who' section for api_permission '~s'">>,
[Msg, Name]);
throw:{replace_with, NVal} ->
{access, NVal};
error:_ ->
report_error(<<"Invalid access rule '~p' used inside 'who' section for api_permission '~s'">>,
[Val, Name])
end;
([{oauth, OauthList}]) when is_list(OauthList) ->
({oauth, OauthList}) when is_list(OauthList) ->
case ParseOauth of
oauth ->
Nested = parse_who(Name, lists:flatten(OauthList), scope),
@@ -408,7 +413,7 @@ parse_who(Name, Defs, ParseOauth) when is_list(Defs) ->
end;
(Atom) when is_atom(Atom) ->
{acl, {acl, Atom}};
([Other]) ->
(Other) ->
try acl:normalize_spec(Other) of
Rule2 ->
{acl, Rule2}
@@ -416,10 +421,7 @@ parse_who(Name, Defs, ParseOauth) when is_list(Defs) ->
_:_ ->
report_error(<<"Invalid value '~p' used inside 'who' section for api_permission '~s'">>,
[Other, Name])
end;
(Invalid) ->
report_error(<<"Invalid value '~p' used inside 'who' section for api_permission '~s'">>,
[Invalid, Name])
end
end, Defs);
parse_who(Name, Val, _ParseOauth) ->
report_error(<<"Invalid value '~p' used inside 'who' section for api_permission '~s'">>,
+49 -17
View File
@@ -5,7 +5,7 @@
%%% Created : 7 May 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -26,7 +26,9 @@
-module(ejabberd_admin).
-author('mickael.remond@process-one.net').
-export([start/0, stop/0,
-behaviour(gen_server).
-export([start_link/0,
%% Server
status/0, reopen_log/0, rotate_log/0,
set_loglevel/1,
@@ -52,19 +54,43 @@
dump_to_textfile/1, dump_to_textfile/2,
mnesia_change_nodename/4,
restore/1, % Still used by some modules
clear_cache/0,
get_commands_spec/0
]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_commands.hrl").
start() ->
ejabberd_commands:register_commands(get_commands_spec()).
-record(state, {}).
stop() ->
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
process_flag(trap_exit, true),
ejabberd_commands:register_commands(get_commands_spec()),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
Reply = ok,
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ejabberd_commands:unregister_commands(get_commands_spec()).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%
%%% ejabberd commands
%%%
@@ -112,7 +138,7 @@ get_commands_spec() ->
desc = "Get the current loglevel",
module = ejabberd_logger, function = get,
result_desc = "Tuple with the log level number, its keyword and description",
result_example = {4, <<"info">>, <<"Info">>},
result_example = {4, info, <<"Info">>},
args = [],
result = {leveltuple, {tuple, [{levelnumber, integer},
{levelatom, atom},
@@ -174,7 +200,7 @@ get_commands_spec() ->
args = [],
result = {vhosts, {list, {vhost, string}}}},
#ejabberd_commands{name = reload_config, tags = [server],
desc = "Reload config file in memory (only affects ACL and Access)",
desc = "Reload config file in memory",
module = ?MODULE, function = reload_config,
args = [],
result = {res, rescode}},
@@ -277,6 +303,7 @@ get_commands_spec() ->
#ejabberd_commands{name = export2sql, tags = [mnesia],
desc = "Export virtual host information from Mnesia tables to SQL file",
longdesc = "Configure the modules to use SQL, then call this command.",
module = ejd2sql, function = export,
args_desc = ["Vhost", "Full path to the destination SQL file"],
args_example = ["example.com", "/var/lib/ejabberd/example.com.sql"],
@@ -335,7 +362,11 @@ get_commands_spec() ->
module = ?MODULE, function = install_fallback_mnesia,
args_desc = ["Full path to the fallback file"],
args_example = ["/var/lib/ejabberd/database.fallback"],
args = [{file, string}], result = {res, restuple}}
args = [{file, string}], result = {res, restuple}},
#ejabberd_commands{name = clear_cache, tags = [server],
desc = "Clear database cache on all nodes",
module = ?MODULE, function = clear_cache,
args = [], result = {res, rescode}}
].
@@ -414,7 +445,7 @@ send_service_message_all_mucs(Subject, AnnouncementText) ->
fun(ServerHost) ->
MUCHost = gen_mod:get_module_opt_host(
ServerHost, mod_muc, <<"conference.@HOST@">>),
mod_muc:broadcast_service_message(MUCHost, Message)
mod_muc:broadcast_service_message(ServerHost, MUCHost, Message)
end,
?MYHOSTS).
@@ -448,9 +479,9 @@ update_module(ModuleNameString) ->
register(User, Host, Password) ->
case ejabberd_auth:try_register(User, Host, Password) of
{atomic, ok} ->
ok ->
{ok, io_lib:format("User ~s@~s successfully registered", [User, Host])};
{atomic, exists} ->
{error, exists} ->
Msg = io_lib:format("User ~s@~s already registered", [User, Host]),
{error, conflict, 10090, Msg};
{error, Reason} ->
@@ -464,7 +495,7 @@ unregister(User, Host) ->
{ok, ""}.
registered_users(Host) ->
Users = ejabberd_auth:get_vh_registered_users(Host),
Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort(Users),
lists:map(fun({U, _S}) -> U end, SUsers).
@@ -472,10 +503,7 @@ registered_vhosts() ->
?MYHOSTS.
reload_config() ->
ejabberd_config:reload_file(),
acl:load_from_config(),
shaper:load_from_config(),
ejabberd_access_permissions:invalidate().
ejabberd_config:reload_file().
%%%
%%% Cluster management
@@ -589,7 +617,7 @@ restore(Path) ->
%% Obsolete tables or tables created by module who are no longer used are not
%% restored and are ignored.
keep_tables() ->
lists:flatten([acl, passwd, config, local_config,
lists:flatten([acl, passwd, config,
keep_modules_tables()]).
%% Returns the list of modules tables in use, according to the list of actually
@@ -737,3 +765,7 @@ mnesia_change_nodename(FromString, ToString, Source, Target) ->
{[Other], Acc}
end,
mnesia:traverse_backup(Source, Target, Convert, switched).
clear_cache() ->
Nodes = ejabberd_cluster:get_nodes(),
lists:foreach(fun(T) -> ets_cache:clear(T, Nodes) end, ets_cache:all()).
+35 -106
View File
@@ -5,7 +5,7 @@
%%% Created : 31 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -30,8 +30,7 @@
-behaviour(application).
-export([start/2, prep_stop/1, stop/1,
init/0, opt_type/1]).
-export([start/2, prep_stop/1, stop/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -41,44 +40,30 @@
%%%
start(normal, _Args) ->
{T1, _} = statistics(wall_clock),
ejabberd_logger:start(),
write_pid_file(),
start_apps(),
start_elixir_application(),
ejabberd:check_app(ejabberd),
randoms:start(),
db_init(),
start(),
translate:start(),
ejabberd_access_permissions:start_link(),
ejabberd_ctl:init(),
ejabberd_commands:init(),
ejabberd_admin:start(),
gen_mod:start(),
ext_mod:start(),
setup_if_elixir_conf_used(),
ejabberd_config:start(),
ejabberd_mnesia:start(),
set_settings_from_config(),
acl:start(),
shaper:start(),
connect_nodes(),
Sup = ejabberd_sup:start_link(),
ejabberd_rdbms:start(),
ejabberd_riak_sup:start(),
ejabberd_redis:start(),
ejabberd_sm:start(),
cyrsasl:start(),
% Profiling
%ejabberd_debug:eprof_start(),
%ejabberd_debug:fprof_start(),
file_queue_init(),
maybe_add_nameservers(),
ejabberd_auth:start(),
ejabberd_oauth:start(),
gen_mod:start_modules(),
ejabberd_listener:start_listeners(),
register_elixir_config_hooks(),
?INFO_MSG("ejabberd ~s is started in the node ~p", [?VERSION, node()]),
Sup;
connect_nodes(),
case ejabberd_sup:start_link() of
{ok, SupPid} ->
register_elixir_config_hooks(),
{T2, _} = statistics(wall_clock),
?INFO_MSG("ejabberd ~s is started in the node ~p in ~.2fs",
[?VERSION, node(), (T2-T1)/1000]),
lists:foreach(fun erlang:garbage_collect/1, processes()),
{ok, SupPid};
Err ->
Err
end;
start(_, _) ->
{error, badarg}.
@@ -87,10 +72,8 @@ start(_, _) ->
%% before shutting down the processes of the application.
prep_stop(State) ->
ejabberd_listener:stop_listeners(),
ejabberd_admin:stop(),
broadcast_c2s_shutdown(),
ejabberd_sm:stop(),
gen_mod:stop_modules(),
timer:sleep(5000),
State.
%% All the processes were killed when this function is called
@@ -105,49 +88,8 @@ stop(_State) ->
%%% Internal functions
%%%
start() ->
spawn_link(?MODULE, init, []).
init() ->
register(ejabberd, self()),
loop().
loop() ->
receive
_ ->
loop()
end.
db_init() ->
ejabberd_config:env_binary_to_list(mnesia, dir),
MyNode = node(),
DbNodes = mnesia:system_info(db_nodes),
case lists:member(MyNode, DbNodes) of
true ->
ok;
false ->
?CRITICAL_MSG("Node name mismatch: I'm [~s], "
"the database is owned by ~p", [MyNode, DbNodes]),
?CRITICAL_MSG("Either set ERLANG_NODE in ejabberdctl.cfg "
"or change node name in Mnesia", []),
erlang:error(node_name_mismatch)
end,
case mnesia:system_info(extra_db_nodes) of
[] ->
mnesia:create_schema([node()]);
_ ->
ok
end,
ejabberd:start_app(mnesia, permanent),
mnesia:wait_for_tables(mnesia:system_info(local_tables), infinity).
connect_nodes() ->
Nodes = ejabberd_config:get_option(
cluster_nodes,
fun(Ns) ->
true = lists:all(fun is_atom/1, Ns),
Ns
end, []),
Nodes = ejabberd_config:get_option(cluster_nodes, []),
lists:foreach(fun(Node) ->
net_kernel:connect_node(Node)
end, Nodes).
@@ -164,16 +106,6 @@ add_windows_nameservers() ->
?INFO_MSG("Adding machine's DNS IPs to Erlang system:~n~p", [IPTs]),
lists:foreach(fun(IPT) -> inet_db:add_ns(IPT) end, IPTs).
broadcast_c2s_shutdown() ->
Children = ejabberd_sm:get_all_pids(),
lists:foreach(
fun(C2SPid) when node(C2SPid) == node() ->
C2SPid ! system_shutdown;
(_) ->
ok
end, Children).
%%%
%%% PID file
%%%
@@ -205,40 +137,37 @@ delete_pid_file() ->
end.
set_settings_from_config() ->
Level = ejabberd_config:get_option(
loglevel,
fun(P) when P>=0, P=<5 -> P end,
4),
ejabberd_logger:set(Level),
Ticktime = ejabberd_config:get_option(
net_ticktime,
opt_type(net_ticktime),
60),
Ticktime = ejabberd_config:get_option(net_ticktime, 60),
net_kernel:set_net_ticktime(Ticktime).
file_queue_init() ->
QueueDir = case ejabberd_config:queue_dir() of
undefined ->
MnesiaDir = mnesia:system_info(directory),
filename:join(MnesiaDir, "queue");
Path ->
Path
end,
p1_queue:start(QueueDir).
start_apps() ->
crypto:start(),
ejabberd:start_app(sasl),
ejabberd:start_app(ssl),
ejabberd:start_app(p1_utils),
ejabberd:start_app(fast_yaml),
ejabberd:start_app(fast_tls),
ejabberd:start_app(xmpp),
ejabberd:start_app(cache_tab).
-spec opt_type(net_ticktime) -> fun((pos_integer()) -> pos_integer());
(cluster_nodes) -> fun(([node()]) -> [node()]);
(atom()) -> atom().
opt_type(net_ticktime) ->
fun (P) when is_integer(P), P > 0 -> P end;
opt_type(cluster_nodes) ->
fun (Ns) -> true = lists:all(fun is_atom/1, Ns), Ns end;
opt_type(loglevel) ->
fun (P) when P >= 0, P =< 5 -> P end;
opt_type(modules) ->
fun (Mods) ->
lists:map(fun ({M, A}) when is_atom(M), is_list(A) ->
{M, A}
end,
Mods)
end;
opt_type(_) -> [cluster_nodes, loglevel, modules, net_ticktime].
opt_type(_) -> [cluster_nodes, net_ticktime].
setup_if_elixir_conf_used() ->
case ejabberd_config:is_using_elixir_config() of
+692 -302
View File
File diff suppressed because it is too large Load Diff
+47 -141
View File
@@ -5,7 +5,7 @@
%%% Created : 17 Feb 2006 by Mickael Remond <mremond@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -26,9 +26,11 @@
-module(ejabberd_auth_anonymous).
-behaviour(ejabberd_config).
-behaviour(ejabberd_auth).
-author('mickael.remond@process-one.net').
-export([start/1,
stop/1,
allow_anonymous/1,
is_sasl_anonymous_enabled/1,
is_login_anonymous_enabled/1,
@@ -38,37 +40,27 @@
unregister_connection/3
]).
-export([login/2, set_password/3, check_password/4,
check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password_s/2,
get_password/2, get_password/3, is_user_exists/2,
remove_user/2, remove_user/3, store_type/0,
plain_password_required/0, opt_type/1]).
-export([login/2, check_password/4, user_exists/2,
get_users/2, count_users/2, store_type/1,
plain_password_required/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jid.hrl").
%% Create the anonymous table if at least one virtual host has anonymous features enabled
%% Register to login / logout events
-record(anonymous, {us = {<<"">>, <<"">>} :: {binary(), binary()},
sid = ejabberd_sm:make_sid() :: ejabberd_sm:sid()}).
start(Host) ->
%% TODO: Check cluster mode
ejabberd_mnesia:create(?MODULE, anonymous, [{ram_copies, [node()]},
{type, bag},
{attributes, record_info(fields, anonymous)}]),
%% The hooks are needed to add / remove users from the anonymous tables
ejabberd_hooks:add(sm_register_connection_hook, Host,
?MODULE, register_connection, 100),
ejabberd_hooks:add(sm_remove_connection_hook, Host,
?MODULE, unregister_connection, 100),
ok.
stop(Host) ->
ejabberd_hooks:delete(sm_register_connection_hook, Host,
?MODULE, register_connection, 100),
ejabberd_hooks:delete(sm_remove_connection_hook, Host,
?MODULE, unregister_connection, 100).
%% Return true if anonymous is allowed for host or false otherwise
allow_anonymous(Host) ->
lists:member(?MODULE, ejabberd_auth:auth_modules(Host)).
@@ -103,87 +95,47 @@ is_login_anonymous_enabled(Host) ->
%% Return the anonymous protocol to use: sasl_anon|login_anon|both
%% defaults to login_anon
anonymous_protocol(Host) ->
ejabberd_config:get_option(
{anonymous_protocol, Host},
fun(sasl_anon) -> sasl_anon;
(login_anon) -> login_anon;
(both) -> both
end,
sasl_anon).
ejabberd_config:get_option({anonymous_protocol, Host}, sasl_anon).
%% Return true if multiple connections have been allowed in the config file
%% defaults to false
allow_multiple_connections(Host) ->
ejabberd_config:get_option(
{allow_multiple_connections, Host},
fun(V) when is_boolean(V) -> V end,
false).
ejabberd_config:get_option({allow_multiple_connections, Host}, false).
%% Check if user exist in the anonymus database
anonymous_user_exist(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({anonymous, US}) of
[] ->
false;
[_H|_T] ->
true
end.
%% Remove connection from Mnesia tables
remove_connection(SID, LUser, LServer) ->
US = {LUser, LServer},
F = fun () -> mnesia:delete_object({anonymous, US, SID})
end,
mnesia:transaction(F).
lists:any(
fun({_LResource, Info}) ->
proplists:get_value(auth_module, Info) == ?MODULE
end, ejabberd_sm:get_user_info(User, Server)).
%% Register connection
-spec register_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> ok.
register_connection(SID,
register_connection(_SID,
#jid{luser = LUser, lserver = LServer}, Info) ->
AuthModule = proplists:get_value(auth_module, Info, undefined),
case AuthModule == (?MODULE) of
true ->
ejabberd_hooks:run(register_user, LServer,
[LUser, LServer]),
US = {LUser, LServer},
mnesia:sync_dirty(fun () ->
mnesia:write(#anonymous{us = US,
sid = SID})
end);
false -> ok
case proplists:get_value(auth_module, Info) of
?MODULE ->
ejabberd_hooks:run(register_user, LServer, [LUser, LServer]);
_ ->
ok
end.
%% Remove an anonymous user from the anonymous users table
-spec unregister_connection(ejabberd_sm:sid(), jid(), ejabberd_sm:info()) -> any().
unregister_connection(SID,
#jid{luser = LUser, lserver = LServer}, _) ->
purge_hook(anonymous_user_exist(LUser, LServer), LUser,
LServer),
remove_connection(SID, LUser, LServer).
%% Launch the hook to purge user data only for anonymous users
purge_hook(false, _LUser, _LServer) ->
ok;
purge_hook(true, LUser, LServer) ->
ejabberd_hooks:run(anonymous_purge_hook, LServer,
[LUser, LServer]).
unregister_connection(_SID,
#jid{luser = LUser, lserver = LServer}, Info) ->
case proplists:get_value(auth_module, Info) of
?MODULE ->
ejabberd_hooks:run(remove_user, LServer, [LUser, LServer]);
_ ->
ok
end.
%% ---------------------------------
%% Specific anonymous auth functions
%% ---------------------------------
%% When anonymous login is enabled, check the password for permenant users
%% before allowing access
check_password(User, AuthzId, Server, Password) ->
check_password(User, AuthzId, Server, Password, undefined,
undefined).
check_password(User, _AuthzId, Server, _Password, _Digest,
_DigestGen) ->
check_password(User, _AuthzId, Server, _Password) ->
case
ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
ejabberd_auth:user_exists_in_other_modules(?MODULE,
User, Server)
of
%% If user exists in other module, reject anonnymous authentication
@@ -207,71 +159,25 @@ login(User, Server) ->
end
end.
%% When anonymous login is enabled, check that the user is permanent before
%% changing its password
set_password(User, Server, _Password) ->
case anonymous_user_exist(User, Server) of
true -> ok;
false -> {error, not_allowed}
end.
get_users(Server, _) ->
[{U, S} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(Server)].
%% When anonymous login is enabled, check if permanent users are allowed on
%% the server:
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
count_users(Server, Opts) ->
length(get_users(Server, Opts)).
dirty_get_registered_users() -> [].
get_vh_registered_users(Server) ->
[{U, S}
|| {U, S, _R}
<- ejabberd_sm:get_vh_session_list(Server)].
get_vh_registered_users(Server, _) ->
get_vh_registered_users(Server).
get_vh_registered_users_number(Server) ->
length(get_vh_registered_users(Server)).
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
%% Return password of permanent user or false for anonymous users
get_password(User, Server) ->
get_password(User, Server, <<"">>).
get_password(User, Server, DefaultValue) ->
case anonymous_user_exist(User, Server) or
login(User, Server)
of
%% We return the default value if the user is anonymous
true -> DefaultValue;
%% We return the permanent user password otherwise
false -> false
end.
get_password_s(User, Server) ->
case get_password(User, Server) of
false ->
<<"">>;
Password ->
Password
end.
%% Returns true if the user exists in the DB or if an anonymous user is logged
%% under the given name
is_user_exists(User, Server) ->
user_exists(User, Server) ->
anonymous_user_exist(User, Server).
remove_user(_User, _Server) -> {error, not_allowed}.
plain_password_required(_) ->
false.
remove_user(_User, _Server, _Password) -> not_allowed.
plain_password_required() -> false.
store_type() ->
plain.
store_type(_) ->
external.
-spec opt_type(allow_multiple_connection) -> fun((boolean()) -> boolean());
(anonymous_protocol) -> fun((sasl_anon | login_anon | both) ->
sasl_anon | login_anon | both);
(atom()) -> [atom()].
opt_type(allow_multiple_connections) ->
fun (V) when is_boolean(V) -> V end;
opt_type(anonymous_protocol) ->
+32 -255
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -31,15 +31,9 @@
-behaviour(ejabberd_auth).
-export([start/1, set_password/3, check_password/4,
check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, plain_password_required/0,
opt_type/1]).
-export([start/1, stop/1, set_password/3, check_password/4,
try_register/3, user_exists/2, remove_user/2,
store_type/1, plain_password_required/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -48,279 +42,62 @@
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
Cmd = ejabberd_config:get_option(
{extauth_program, Host},
fun(V) ->
binary_to_list(iolist_to_binary(V))
end,
"extauth"),
extauth:start(Host, Cmd),
check_cache_last_options(Host),
ejabberd_auth_mnesia:start(Host).
Cmd = ejabberd_config:get_option({extauth_program, Host}, "extauth"),
extauth:start(Host, Cmd).
check_cache_last_options(Server) ->
case get_cache_option(Server) of
false -> no_cache;
{true, _CacheTime} ->
case get_mod_last_configured(Server) of
no_mod_last ->
?ERROR_MSG("In host ~p extauth is used, extauth_cache "
"is enabled but mod_last is not enabled.",
[Server]),
no_cache;
_ -> cache
end
end.
stop(Host) ->
extauth:stop(Host).
plain_password_required() -> true.
plain_password_required(_) -> true.
store_type() -> external.
store_type(_) -> external.
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
case get_cache_option(Server) of
false ->
check_password_extauth(User, AuthzId, Server, Password);
{true, CacheTime} ->
check_password_cache(User, AuthzId, Server, Password,
CacheTime)
end
check_password_extauth(User, AuthzId, Server, Password)
end.
check_password(User, AuthzId, Server, Password, _Digest,
_DigestGen) ->
check_password(User, AuthzId, Server, Password).
set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of
true ->
set_password_mnesia(User, Server, Password), ok;
_ -> {error, unknown_problem}
true -> ok;
_ -> {error, db_failure}
end.
try_register(User, Server, Password) ->
case get_cache_option(Server) of
false -> try_register_extauth(User, Server, Password);
{true, _CacheTime} ->
try_register_external_cache(User, Server, Password)
end.
extauth:try_register(User, Server, Password).
dirty_get_registered_users() ->
ejabberd_auth_mnesia:dirty_get_registered_users().
get_vh_registered_users(Server) ->
ejabberd_auth_mnesia:get_vh_registered_users(Server).
get_vh_registered_users(Server, Data) ->
ejabberd_auth_mnesia:get_vh_registered_users(Server,
Data).
get_vh_registered_users_number(Server) ->
ejabberd_auth_mnesia:get_vh_registered_users_number(Server).
get_vh_registered_users_number(Server, Data) ->
ejabberd_auth_mnesia:get_vh_registered_users_number(Server,
Data).
%% The password can only be returned if cache is enabled, cached info exists and is fresh enough.
get_password(User, Server) ->
case get_cache_option(Server) of
false -> false;
{true, CacheTime} ->
get_password_cache(User, Server, CacheTime)
end.
get_password_s(User, Server) ->
case get_password(User, Server) of
false -> <<"">>;
Other -> Other
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
try extauth:is_user_exists(User, Server) of
Res -> Res
user_exists(User, Server) ->
try extauth:user_exists(User, Server) of
Res -> Res
catch
_:Error -> {error, Error}
_:Error ->
?ERROR_MSG("external authentication program failure: ~p",
[Error]),
{error, db_failure}
end.
remove_user(User, Server) ->
case extauth:remove_user(User, Server) of
false -> false;
true ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
ejabberd_auth_mnesia:remove_user(User, Server)
end
false -> {error, not_allowed};
true -> ok
end.
remove_user(User, Server, Password) ->
case extauth:remove_user(User, Server, Password) of
false -> false;
true ->
case get_cache_option(Server) of
false -> false;
{true, _CacheTime} ->
ejabberd_auth_mnesia:remove_user(User, Server,
Password)
end
end.
%%%
%%% Extauth cache management
%%%
%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
get_cache_option(Host) ->
case ejabberd_config:get_option(
{extauth_cache, Host},
fun(false) -> undefined;
(I) when is_integer(I), I >= 0 -> I
end) of
undefined -> false;
CacheTime -> {true, CacheTime}
end.
%% @spec (User, AuthzId, Server, Password) -> true | false
check_password_extauth(User, _AuthzId, Server, Password) ->
extauth:check_password(User, Server, Password) andalso
Password /= <<"">>.
%% @spec (User, Server, Password) -> true | false
try_register_extauth(User, Server, Password) ->
extauth:try_register(User, Server, Password).
check_password_cache(User, AuthzId, Server, Password, 0) ->
check_password_external_cache(User, AuthzId, Server, Password);
check_password_cache(User, AuthzId, Server, Password,
CacheTime) ->
case get_last_access(User, Server) of
online ->
check_password_mnesia(User, AuthzId, Server, Password);
never ->
check_password_external_cache(User, AuthzId, Server, Password);
mod_last_required ->
?ERROR_MSG("extauth is used, extauth_cache is enabled "
"but mod_last is not enabled in that "
"host",
[]),
check_password_external_cache(User, AuthzId, Server, Password);
TimeStamp ->
case is_fresh_enough(TimeStamp, CacheTime) of
%% If no need to refresh, check password against Mnesia
true ->
case check_password_mnesia(User, AuthzId, Server, Password) of
%% If password valid in Mnesia, accept it
true -> true;
%% Else (password nonvalid in Mnesia), check in extauth and cache result
false ->
check_password_external_cache(User, AuthzId, Server, Password)
end;
%% Else (need to refresh), check in extauth and cache result
false ->
check_password_external_cache(User, AuthzId, Server, Password)
end
end.
get_password_mnesia(User, Server) ->
ejabberd_auth_mnesia:get_password(User, Server).
-spec get_password_cache(User::binary(), Server::binary(), CacheTime::integer()) -> Password::string() | false.
get_password_cache(User, Server, CacheTime) ->
case get_last_access(User, Server) of
online -> get_password_mnesia(User, Server);
never -> false;
mod_last_required ->
?ERROR_MSG("extauth is used, extauth_cache is enabled "
"but mod_last is not enabled in that "
"host",
[]),
false;
TimeStamp ->
case is_fresh_enough(TimeStamp, CacheTime) of
true -> get_password_mnesia(User, Server);
false -> false
end
end.
%% Check the password using extauth; if success then cache it
check_password_external_cache(User, AuthzId, Server, Password) ->
case check_password_extauth(User, AuthzId, Server, Password) of
true ->
set_password_mnesia(User, Server, Password), true;
false -> false
end.
%% Try to register using extauth; if success then cache it
try_register_external_cache(User, Server, Password) ->
case try_register_extauth(User, Server, Password) of
{atomic, ok} = R ->
set_password_mnesia(User, Server, Password), R;
_ -> {error, not_allowed}
end.
%% @spec (User, AuthzId, Server, Password) -> true | false
check_password_mnesia(User, AuthzId, Server, Password) ->
ejabberd_auth_mnesia:check_password(User, AuthzId, Server,
Password).
%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
set_password_mnesia(User, Server, Password) ->
%% @spec (TimeLast, CacheTime) -> true | false
%% TimeLast = online | never | integer()
%% CacheTime = integer() | false
ejabberd_auth_mnesia:set_password(User, Server,
Password).
is_fresh_enough(TimeStampLast, CacheTime) ->
Now = p1_time_compat:system_time(seconds),
TimeStampLast + CacheTime > Now.
%% Code copied from mod_configure.erl
%% Code copied from web/ejabberd_web_admin.erl
%% TODO: Update time format to XEP-0202: Entity Time
-spec(get_last_access(User::binary(), Server::binary()) -> (online | never | mod_last_required | integer())).
get_last_access(User, Server) ->
case ejabberd_sm:get_user_resources(User, Server) of
[] ->
case get_last_info(User, Server) of
mod_last_required -> mod_last_required;
not_found -> never;
{ok, Timestamp, _Status} -> Timestamp
end;
_ -> online
end.
%% @spec (User, Server) -> {ok, Timestamp, Status} | not_found | mod_last_required
get_last_info(User, Server) ->
case get_mod_last_enabled(Server) of
mod_last -> mod_last:get_last_info(User, Server);
no_mod_last -> mod_last_required
end.
%% @spec (Server) -> mod_last | no_mod_last
get_mod_last_enabled(Server) ->
case gen_mod:is_loaded(Server, mod_last) of
true -> mod_last;
false -> no_mod_last
end.
get_mod_last_configured(Server) ->
case is_configured(Server, mod_last) of
true -> mod_last;
false -> no_mod_last
end.
is_configured(Host, Module) ->
Os = ejabberd_config:get_local_option({modules, Host},
fun(M) when is_list(M) -> M end),
lists:keymember(Module, 1, Os).
-spec opt_type(extauth_cache) -> fun((false | non_neg_integer()) ->
false | non_neg_integer());
(extauth_program) -> fun((binary()) -> string());
(atom()) -> [atom()].
opt_type(extauth_cache) ->
fun (false) -> undefined;
?WARNING_MSG("option 'extauth_cache' is deprecated and has no effect, "
"use authentication or global cache configuration "
"options: auth_use_cache, auth_cache_life_time, "
"use_cache, cache_life_time, and so on", []),
fun (false) -> false;
(I) when is_integer(I), I >= 0 -> I
end;
opt_type(extauth_program) ->
+40 -107
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -37,13 +37,9 @@
handle_cast/2, terminate/2, code_change/3]).
-export([start/1, stop/1, start_link/1, set_password/3,
check_password/4, check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, plain_password_required/0,
check_password/4, user_exists/2,
get_users/2, count_users/2,
store_type/1, plain_password_required/1,
opt_type/1]).
-include("ejabberd.hrl").
@@ -65,9 +61,9 @@
uids = [] :: [{binary()} | {binary(), binary()}],
ufilter = <<"">> :: binary(),
sfilter = <<"">> :: binary(),
lfilter :: {any(), any()},
lfilter :: {any(), any()} | undefined,
deref_aliases = never :: never | searching | finding | always,
dn_filter :: binary(),
dn_filter :: binary() | undefined,
dn_filter_attrs = [] :: [binary()]}).
handle_cast(_Request, State) -> {noreply, State}.
@@ -86,13 +82,12 @@ start(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
ChildSpec = {Proc, {?MODULE, start_link, [Host]},
transient, 1000, worker, [?MODULE]},
supervisor:start_child(ejabberd_sup, ChildSpec).
supervisor:start_child(ejabberd_backend_sup, ChildSpec).
stop(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
gen_server:call(Proc, stop),
supervisor:terminate_child(ejabberd_sup, Proc),
supervisor:delete_child(ejabberd_sup, Proc).
supervisor:terminate_child(ejabberd_backend_sup, Proc),
supervisor:delete_child(ejabberd_backend_sup, Proc).
start_link(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),
@@ -101,6 +96,7 @@ start_link(Host) ->
terminate(_Reason, _State) -> ok.
init(Host) ->
process_flag(trap_exit, true),
State = parse_options(Host),
eldap_pool:start_link(State#state.eldap_id,
State#state.servers, State#state.backups,
@@ -112,9 +108,9 @@ init(Host) ->
State#state.password, State#state.tls_options),
{ok, State}.
plain_password_required() -> true.
plain_password_required(_) -> true.
store_type() -> external.
store_type(_) -> external.
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
@@ -129,60 +125,34 @@ check_password(User, AuthzId, Server, Password) ->
end
end.
check_password(User, AuthzId, Server, Password, _Digest,
_DigestGen) ->
check_password(User, AuthzId, Server, Password).
set_password(User, Server, Password) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, State) of
false -> {error, user_not_found};
false -> {error, notfound};
DN ->
eldap_pool:modify_passwd(State#state.eldap_id, DN,
Password)
case eldap_pool:modify_passwd(State#state.eldap_id, DN,
Password) of
ok -> ok;
_Err -> {error, db_failure}
end
end.
%% @spec (User, Server, Password) -> {error, not_allowed}
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
dirty_get_registered_users() ->
Servers = ejabberd_config:get_vh_by_auth_method(ldap),
lists:flatmap(fun (Server) ->
get_vh_registered_users(Server)
end,
Servers).
get_vh_registered_users(Server) ->
case catch get_vh_registered_users_ldap(Server) of
get_users(Server, []) ->
case catch get_users_ldap(Server) of
{'EXIT', _} -> [];
Result -> Result
end.
get_vh_registered_users(Server, _) ->
get_vh_registered_users(Server).
get_vh_registered_users_number(Server) ->
length(get_vh_registered_users(Server)).
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
get_password(_User, _Server) -> false.
get_password_s(_User, _Server) -> <<"">>.
count_users(Server, Opts) ->
length(get_users(Server, Opts)).
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
case catch is_user_exists_ldap(User, Server) of
{'EXIT', Error} -> {error, Error};
user_exists(User, Server) ->
case catch user_exists_ldap(User, Server) of
{'EXIT', _Error} -> {error, db_failure};
Result -> Result
end.
remove_user(_User, _Server) -> {error, not_allowed}.
remove_user(_User, _Server, _Password) -> not_allowed.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
@@ -199,7 +169,7 @@ check_password_ldap(User, Server, Password) ->
end
end.
get_vh_registered_users_ldap(Server) ->
get_users_ldap(Server) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
UIDs = State#state.uids,
Eldap_ID = State#state.eldap_id,
@@ -248,7 +218,7 @@ get_vh_registered_users_ldap(Server) ->
_ -> []
end.
is_user_exists_ldap(User, Server) ->
user_exists_ldap(User, Server) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, State) of
false -> false;
@@ -361,27 +331,14 @@ result_attrs(#state{uids = UIDs,
%%%----------------------------------------------------------------------
parse_options(Host) ->
Cfg = eldap_utils:get_config(Host, []),
Eldap_ID = jlib:atom_to_binary(gen_mod:get_module_proc(Host, ?MODULE)),
Bind_Eldap_ID = jlib:atom_to_binary(
Eldap_ID = misc:atom_to_binary(gen_mod:get_module_proc(Host, ?MODULE)),
Bind_Eldap_ID = misc:atom_to_binary(
gen_mod:get_module_proc(Host, bind_ejabberd_auth_ldap)),
UIDsTemp = gen_mod:get_opt(
{ldap_uids, Host}, [],
fun(Us) ->
lists:map(
fun({U, P}) ->
{iolist_to_binary(U),
iolist_to_binary(P)};
({U}) ->
{iolist_to_binary(U)};
(U) ->
{iolist_to_binary(U)}
end, lists:flatten(Us))
end, [{<<"uid">>, <<"%u">>}]),
UIDsTemp = ejabberd_config:get_option(
{ldap_uids, Host}, [{<<"uid">>, <<"%u">>}]),
UIDs = eldap_utils:uids_domain_subst(Host, UIDsTemp),
SubFilter = eldap_utils:generate_subfilter(UIDs),
UserFilter = case gen_mod:get_opt(
{ldap_filter, Host}, [],
fun check_filter/1, <<"">>) of
UserFilter = case ejabberd_config:get_option({ldap_filter, Host}, <<"">>) of
<<"">> ->
SubFilter;
F ->
@@ -390,20 +347,8 @@ parse_options(Host) ->
SearchFilter = eldap_filter:do_sub(UserFilter,
[{<<"%u">>, <<"*">>}]),
{DNFilter, DNFilterAttrs} =
gen_mod:get_opt({ldap_dn_filter, Host}, [],
fun([{DNF, DNFA}]) ->
NewDNFA = case DNFA of
undefined ->
[];
_ ->
[iolist_to_binary(A)
|| A <- DNFA]
end,
NewDNF = check_filter(DNF),
{NewDNF, NewDNFA}
end, {undefined, []}),
LocalFilter = gen_mod:get_opt(
{ldap_local_filter, Host}, [], fun(V) -> V end),
ejabberd_config:get_option({ldap_dn_filter, Host}, {undefined, []}),
LocalFilter = ejabberd_config:get_option({ldap_local_filter, Host}),
#state{host = Host, eldap_id = Eldap_ID,
bind_eldap_id = Bind_Eldap_ID,
servers = Cfg#eldap_config.servers,
@@ -418,31 +363,19 @@ parse_options(Host) ->
sfilter = SearchFilter, lfilter = LocalFilter,
dn_filter = DNFilter, dn_filter_attrs = DNFilterAttrs}.
check_filter(F) ->
NewF = iolist_to_binary(F),
{ok, _} = eldap_filter:parse(NewF),
NewF.
-spec opt_type(ldap_dn_filter) -> fun(([{binary(), binary()}]) ->
[{binary(), binary()}]);
(ldap_local_filter) -> fun((any()) -> any());
(atom()) -> [atom()].
opt_type(ldap_dn_filter) ->
fun ([{DNF, DNFA}]) ->
NewDNFA = case DNFA of
undefined -> [];
_ -> [iolist_to_binary(A) || A <- DNFA]
end,
NewDNF = check_filter(DNF),
NewDNF = eldap_utils:check_filter(DNF),
{NewDNF, NewDNFA}
end;
opt_type(ldap_filter) -> fun check_filter/1;
opt_type(ldap_local_filter) -> fun (V) -> V end;
opt_type(ldap_uids) ->
fun (Us) ->
lists:map(fun ({U, P}) ->
{iolist_to_binary(U), iolist_to_binary(P)};
({U}) -> {iolist_to_binary(U)};
(U) -> {iolist_to_binary(U)}
end,
lists:flatten(Us))
end;
opt_type(_) ->
[ldap_dn_filter, ldap_filter, ldap_local_filter,
ldap_uids].
[ldap_dn_filter, ldap_local_filter].
+183 -389
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,21 +27,16 @@
-compile([{parse_transform, ejabberd_sql_pt}]).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-behaviour(ejabberd_auth).
-export([start/1, set_password/3, check_password/4,
check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2, init_db/0,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, export/1, import/2,
plain_password_required/0, opt_type/1]).
-export([start/1, stop/1, set_password/3, try_register/3,
get_users/2, init_db/0,
count_users/2, get_password/2,
remove_user/2, store_type/1, export/1, import/2,
plain_password_required/1, use_cache/1]).
-export([need_transform/1, transform/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -53,28 +48,27 @@
-record(reg_users_counter, {vhost = <<"">> :: binary(),
count = 0 :: integer() | '$1'}).
-define(SALT_LENGTH, 16).
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
init_db(),
update_table(),
update_reg_users_counter_table(Host),
maybe_alert_password_scrammed_without_option(),
ok.
stop(_Host) ->
ok.
init_db() ->
ejabberd_mnesia:create(?MODULE, passwd,
[{disc_copies, [node()]},
[{disc_only_copies, [node()]},
{attributes, record_info(fields, passwd)}]),
ejabberd_mnesia:create(?MODULE, reg_users_counter,
[{ram_copies, [node()]},
{attributes, record_info(fields, reg_users_counter)}]).
update_reg_users_counter_table(Server) ->
Set = get_vh_registered_users(Server),
Set = get_users(Server, []),
Size = length(Set),
LServer = jid:nameprep(Server),
F = fun () ->
@@ -83,395 +77,198 @@ update_reg_users_counter_table(Server) ->
end,
mnesia:sync_dirty(F).
plain_password_required() ->
is_scrammed().
store_type() ->
case is_scrammed() of
false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
true -> scram %% allows: PLAIN SCRAM
use_cache(Host) ->
case mnesia:table_info(passwd, storage_type) of
disc_only_copies ->
ejabberd_config:get_option(
{auth_use_cache, Host},
ejabberd_config:use_cache(Host));
_ ->
false
end.
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[#passwd{password = Password}] when is_binary(Password) ->
Password /= <<"">>;
[#passwd{password = Scram}] when is_record(Scram, scram) ->
is_password_scram_valid(Password, Scram);
_ -> false
end
end.
plain_password_required(Server) ->
store_type(Server) == scram.
check_password(User, AuthzId, Server, Password, Digest,
DigestGen) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[#passwd{password = Passwd}] when is_binary(Passwd) ->
DigRes = if Digest /= <<"">> ->
Digest == DigestGen(Passwd);
true -> false
end,
if DigRes -> true;
true -> (Passwd == Password) and (Password /= <<"">>)
end;
[#passwd{password = Scram}] when is_record(Scram, scram) ->
Passwd = jlib:decode_base64(Scram#scram.storedkey),
DigRes = if Digest /= <<"">> ->
Digest == DigestGen(Passwd);
true -> false
end,
if DigRes -> true;
true -> (Passwd == Password) and (Password /= <<"">>)
end;
_ -> false
end
end.
store_type(Server) ->
ejabberd_auth:password_format(Server).
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, invalid_jid}
set_password(User, Server, Password) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
if (LUser == error) or (LServer == error) ->
{error, invalid_jid};
true ->
F = fun () ->
Password2 = case is_scrammed() and is_binary(Password)
of
true -> password_to_scram(Password);
false -> Password
end,
mnesia:write(#passwd{us = US, password = Password2})
end,
{atomic, ok} = mnesia:transaction(F),
ok
end.
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {error, not_allowed} | {error, Reason}
try_register(User, Server, PasswordList) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
Password = if is_list(PasswordList); is_binary(PasswordList) ->
iolist_to_binary(PasswordList);
true -> PasswordList
end,
US = {LUser, LServer},
if (LUser == error) or (LServer == error) ->
{error, invalid_jid};
true ->
F = fun () ->
case mnesia:read({passwd, US}) of
[] ->
Password2 = case is_scrammed() and
is_binary(Password)
of
true -> password_to_scram(Password);
false -> Password
end,
mnesia:write(#passwd{us = US,
password = Password2}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, 1),
ok;
[_E] -> exists
end
end,
mnesia:transaction(F)
end.
%% Get all registered users in Mnesia
dirty_get_registered_users() ->
mnesia:dirty_all_keys(passwd).
get_vh_registered_users(Server) ->
LServer = jid:nameprep(Server),
mnesia:dirty_select(passwd,
[{#passwd{us = '$1', _ = '_'},
[{'==', {element, 2, '$1'}, LServer}], ['$1']}]).
get_vh_registered_users(Server,
[{from, Start}, {to, End}])
when is_integer(Start) and is_integer(End) ->
get_vh_registered_users(Server,
[{limit, End - Start + 1}, {offset, Start}]);
get_vh_registered_users(Server,
[{limit, Limit}, {offset, Offset}])
when is_integer(Limit) and is_integer(Offset) ->
case get_vh_registered_users(Server) of
[] -> [];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_vh_registered_users(Server, [{prefix, Prefix}])
when is_binary(Prefix) ->
Set = [{U, S}
|| {U, S} <- get_vh_registered_users(Server),
str:prefix(Prefix, U)],
lists:keysort(1, Set);
get_vh_registered_users(Server,
[{prefix, Prefix}, {from, Start}, {to, End}])
when is_binary(Prefix) and is_integer(Start) and
is_integer(End) ->
get_vh_registered_users(Server,
[{prefix, Prefix}, {limit, End - Start + 1},
{offset, Start}]);
get_vh_registered_users(Server,
[{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
when is_binary(Prefix) and is_integer(Limit) and
is_integer(Offset) ->
case [{U, S}
|| {U, S} <- get_vh_registered_users(Server),
str:prefix(Prefix, U)]
of
[] -> [];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_vh_registered_users(Server, _) ->
get_vh_registered_users(Server).
get_vh_registered_users_number(Server) ->
LServer = jid:nameprep(Server),
Query = mnesia:dirty_select(reg_users_counter,
[{#reg_users_counter{vhost = LServer,
count = '$1'},
[], ['$1']}]),
case Query of
[Count] -> Count;
_ -> 0
end.
get_vh_registered_users_number(Server,
[{prefix, Prefix}])
when is_binary(Prefix) ->
Set = [{U, S}
|| {U, S} <- get_vh_registered_users(Server),
str:prefix(Prefix, U)],
length(Set);
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
get_password(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read(passwd, US) of
[#passwd{password = Password}]
when is_binary(Password) ->
Password;
[#passwd{password = Scram}]
when is_record(Scram, scram) ->
{jlib:decode_base64(Scram#scram.storedkey),
jlib:decode_base64(Scram#scram.serverkey),
jlib:decode_base64(Scram#scram.salt),
Scram#scram.iterationcount};
_ -> false
end.
get_password_s(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read(passwd, US) of
[#passwd{password = Password}]
when is_binary(Password) ->
Password;
[#passwd{password = Scram}]
when is_record(Scram, scram) ->
<<"">>;
_ -> <<"">>
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
case catch mnesia:dirty_read({passwd, US}) of
[] -> false;
[_] -> true;
Other -> {error, Other}
end.
%% @spec (User, Server) -> ok
%% @doc Remove user.
%% Note: it returns ok even if there was some problem removing the user.
remove_user(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
US = {User, Server},
F = fun () ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter, LServer,
-1)
mnesia:write(#passwd{us = US, password = Password})
end,
mnesia:transaction(F),
ok.
case mnesia:transaction(F) of
{atomic, ok} ->
ok;
{aborted, Reason} ->
?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
{error, db_failure}
end.
%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request
%% @doc Remove user if the provided password is correct.
remove_user(User, Server, Password) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
try_register(User, Server, Password) ->
US = {User, Server},
F = fun () ->
case mnesia:read({passwd, US}) of
[#passwd{password = Password}]
when is_binary(Password) ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter, LServer,
-1),
ok;
[#passwd{password = Scram}]
when is_record(Scram, scram) ->
case is_password_scram_valid(Password, Scram) of
true ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter,
LServer, -1),
ok;
false -> not_allowed
end;
_ -> not_exists
[] ->
mnesia:write(#passwd{us = US, password = Password}),
mnesia:dirty_update_counter(reg_users_counter, Server, 1),
ok;
[_] ->
{error, exists}
end
end,
case mnesia:transaction(F) of
{atomic, ok} -> ok;
{atomic, Res} -> Res;
_ -> bad_request
{atomic, Res} ->
Res;
{aborted, Reason} ->
?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
{error, db_failure}
end.
update_table() ->
Fields = record_info(fields, passwd),
case mnesia:table_info(passwd, attributes) of
Fields ->
convert_to_binary(Fields),
maybe_scram_passwords(),
ok;
_ ->
?INFO_MSG("Recreating passwd table", []),
mnesia:transform_table(passwd, ignore, Fields)
get_users(Server, []) ->
mnesia:dirty_select(passwd,
[{#passwd{us = '$1', _ = '_'},
[{'==', {element, 2, '$1'}, Server}], ['$1']}]);
get_users(Server, [{from, Start}, {to, End}])
when is_integer(Start) and is_integer(End) ->
get_users(Server, [{limit, End - Start + 1}, {offset, Start}]);
get_users(Server, [{limit, Limit}, {offset, Offset}])
when is_integer(Limit) and is_integer(Offset) ->
case get_users(Server, []) of
[] ->
[];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_users(Server, [{prefix, Prefix}]) when is_binary(Prefix) ->
Set = [{U, S} || {U, S} <- get_users(Server, []), str:prefix(Prefix, U)],
lists:keysort(1, Set);
get_users(Server, [{prefix, Prefix}, {from, Start}, {to, End}])
when is_binary(Prefix) and is_integer(Start) and is_integer(End) ->
get_users(Server, [{prefix, Prefix}, {limit, End - Start + 1},
{offset, Start}]);
get_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
when is_binary(Prefix) and is_integer(Limit) and is_integer(Offset) ->
case [{U, S} || {U, S} <- get_users(Server, []), str:prefix(Prefix, U)] of
[] ->
[];
Users ->
Set = lists:keysort(1, Users),
L = length(Set),
Start = if Offset < 1 -> 1;
Offset > L -> L;
true -> Offset
end,
lists:sublist(Set, Start, Limit)
end;
get_users(Server, _) ->
get_users(Server, []).
count_users(Server, []) ->
case mnesia:dirty_select(
reg_users_counter,
[{#reg_users_counter{vhost = Server, count = '$1'},
[], ['$1']}]) of
[Count] -> Count;
_ -> 0
end;
count_users(Server, [{prefix, Prefix}]) when is_binary(Prefix) ->
Set = [{U, S} || {U, S} <- get_users(Server, []), str:prefix(Prefix, U)],
length(Set);
count_users(Server, _) ->
count_users(Server, []).
get_password(User, Server) ->
case mnesia:dirty_read(passwd, {User, Server}) of
[#passwd{password = Password}] ->
{ok, Password};
_ ->
error
end.
convert_to_binary(Fields) ->
ejabberd_config:convert_table_to_binary(
passwd, Fields, set,
fun(#passwd{us = {U, _}}) -> U end,
fun(#passwd{us = {U, S}, password = Pass} = R) ->
NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
NewPass = case Pass of
#scram{storedkey = StoredKey,
serverkey = ServerKey,
salt = Salt} ->
Pass#scram{
storedkey = iolist_to_binary(StoredKey),
serverkey = iolist_to_binary(ServerKey),
salt = iolist_to_binary(Salt)};
_ ->
iolist_to_binary(Pass)
end,
R#passwd{us = NewUS, password = NewPass}
end).
%%%
%%% SCRAM
%%%
%% The passwords are stored scrammed in the table either if the option says so,
%% or if at least the first password is scrammed.
is_scrammed() ->
OptionScram = is_option_scram(),
FirstElement = mnesia:dirty_read(passwd,
mnesia:dirty_first(passwd)),
case {OptionScram, FirstElement} of
{true, _} -> true;
{false, [#passwd{password = Scram}]}
when is_record(Scram, scram) ->
true;
_ -> false
remove_user(User, Server) ->
US = {User, Server},
F = fun () ->
mnesia:delete({passwd, US}),
mnesia:dirty_update_counter(reg_users_counter, Server, -1),
ok
end,
case mnesia:transaction(F) of
{atomic, ok} ->
ok;
{aborted, Reason} ->
?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
{error, db_failure}
end.
is_option_scram() ->
scram ==
ejabberd_config:get_option({auth_password_format, ?MYNAME},
fun(V) -> V end).
maybe_alert_password_scrammed_without_option() ->
case is_scrammed() andalso not is_option_scram() of
true ->
?ERROR_MSG("Some passwords were stored in the database "
"as SCRAM, but 'auth_password_format' "
"is not configured 'scram'. The option "
"will now be considered to be 'scram'.",
[]);
false -> ok
need_transform(#passwd{us = {U, S}, password = Pass}) ->
if is_binary(Pass) ->
case store_type(S) of
scram ->
?INFO_MSG("Passwords in Mnesia table 'passwd' "
"will be SCRAM'ed", []),
true;
plain ->
false
end;
is_record(Pass, scram) ->
case store_type(S) of
scram ->
false;
plain ->
?WARNING_MSG("Some passwords were stored in the database "
"as SCRAM, but 'auth_password_format' "
"is not configured as 'scram': some "
"authentication mechanisms such as DIGEST-MD5 "
"would *fail*", []),
false
end;
is_list(U) orelse is_list(S) orelse is_list(Pass) ->
?INFO_MSG("Mnesia table 'passwd' will be converted to binary", []),
true
end.
maybe_scram_passwords() ->
case is_scrammed() of
true -> scram_passwords();
false -> ok
end.
scram_passwords() ->
?INFO_MSG("Converting the stored passwords into "
"SCRAM bits",
[]),
Fun = fun (#passwd{password = Password} = P) ->
Scram = password_to_scram(Password),
P#passwd{password = Scram}
end,
Fields = record_info(fields, passwd),
mnesia:transform_table(passwd, Fun, Fields).
password_to_scram(Password) ->
password_to_scram(Password,
?SCRAM_DEFAULT_ITERATION_COUNT).
password_to_scram(Password, IterationCount) ->
Salt = randoms:bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Password, Salt,
IterationCount),
StoredKey =
scram:stored_key(scram:client_key(SaltedPassword)),
ServerKey = scram:server_key(SaltedPassword),
#scram{storedkey = jlib:encode_base64(StoredKey),
serverkey = jlib:encode_base64(ServerKey),
salt = jlib:encode_base64(Salt),
iterationcount = IterationCount}.
is_password_scram_valid(Password, Scram) ->
IterationCount = Scram#scram.iterationcount,
Salt = jlib:decode_base64(Scram#scram.salt),
SaltedPassword = scram:salted_password(Password, Salt,
IterationCount),
StoredKey =
scram:stored_key(scram:client_key(SaltedPassword)),
jlib:decode_base64(Scram#scram.storedkey) == StoredKey.
transform(#passwd{us = {U, S}, password = Pass} = R)
when is_list(U) orelse is_list(S) orelse is_list(Pass) ->
NewUS = {iolist_to_binary(U), iolist_to_binary(S)},
NewPass = case Pass of
#scram{storedkey = StoredKey,
serverkey = ServerKey,
salt = Salt} ->
Pass#scram{
storedkey = iolist_to_binary(StoredKey),
serverkey = iolist_to_binary(ServerKey),
salt = iolist_to_binary(Salt)};
_ ->
iolist_to_binary(Pass)
end,
transform(R#passwd{us = NewUS, password = NewPass});
transform(#passwd{us = {U, S}, password = Password} = P)
when is_binary(Password) ->
case store_type(S) of
scram ->
case jid:resourceprep(Password) of
error ->
?ERROR_MSG("SASLprep failed for password of user ~s@~s",
[U, S]),
P;
_ ->
Scram = ejabberd_auth:password_to_scram(Password),
P#passwd{password = Scram}
end;
plain ->
P
end;
transform(#passwd{password = Password} = P)
when is_record(Password, scram) ->
P.
export(_Server) ->
[{passwd,
@@ -499,6 +296,3 @@ export(_Server) ->
import(LServer, [LUser, Password, _TimeStamp]) ->
mnesia:dirty_write(
#passwd{us = {LUser, LServer}, password = Password}).
opt_type(auth_password_format) -> fun (V) -> V end;
opt_type(_) -> [auth_password_format].
+16 -53
View File
@@ -5,7 +5,7 @@
%%% Created : 5 Jul 2007 by Evgeniy Khramtsov <xram@jabber.ru>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -30,25 +30,15 @@
-behaviour(ejabberd_auth).
-export([start/1, set_password/3, check_password/4,
check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, plain_password_required/0,
-export([start/1, stop/1, check_password/4,
user_exists/2, store_type/1, plain_password_required/1,
opt_type/1]).
start(_Host) ->
ejabberd:start_app(p1_pam).
ejabberd:start_app(epam).
set_password(_User, _Server, _Password) ->
{error, not_allowed}.
check_password(User, AuthzId, Server, Password, _Digest,
_DigestGen) ->
check_password(User, AuthzId, Server, Password).
stop(_Host) ->
ok.
check_password(User, AuthzId, Host, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
@@ -67,26 +57,7 @@ check_password(User, AuthzId, Host, Password) ->
end
end.
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
dirty_get_registered_users() -> [].
get_vh_registered_users(_Host) -> [].
get_vh_registered_users(_Host, _) -> [].
get_vh_registered_users_number(_Host) -> 0.
get_vh_registered_users_number(_Host, _) -> 0.
get_password(_User, _Server) -> false.
get_password_s(_User, _Server) -> <<"">>.
%% @spec (User, Server) -> true | false | {error, Error}
%% TODO: Improve this function to return an error instead of 'false' when connection to PAM failed
is_user_exists(User, Host) ->
user_exists(User, Host) ->
Service = get_pam_service(Host),
UserInfo = case get_pam_userinfotype(Host) of
username -> User;
@@ -94,34 +65,26 @@ is_user_exists(User, Host) ->
end,
case catch epam:acct_mgmt(Service, UserInfo) of
true -> true;
_ -> false
false -> false;
_Err -> {error, db_failure}
end.
remove_user(_User, _Server) -> {error, not_allowed}.
plain_password_required(_) -> true.
remove_user(_User, _Server, _Password) -> not_allowed.
plain_password_required() -> true.
store_type() -> external.
store_type(_) -> external.
%%====================================================================
%% Internal functions
%%====================================================================
get_pam_service(Host) ->
ejabberd_config:get_option(
{pam_service, Host},
fun iolist_to_binary/1,
<<"ejabberd">>).
ejabberd_config:get_option({pam_service, Host}, <<"ejabberd">>).
get_pam_userinfotype(Host) ->
ejabberd_config:get_option(
{pam_userinfotype, Host},
fun(username) -> username;
(jid) -> jid
end,
username).
ejabberd_config:get_option({pam_userinfotype, Host}, username).
-spec opt_type(pam_service) -> fun((binary()) -> binary());
(pam_userinfotype) -> fun((username | jid) -> username | jid);
(atom()) -> [atom()].
opt_type(pam_service) -> fun iolist_to_binary/1;
opt_type(pam_userinfotype) ->
fun (username) -> username;
+37 -228
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Nov 2012 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,22 +27,15 @@
-compile([{parse_transform, ejabberd_sql_pt}]).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-behaviour(ejabberd_auth).
%% External exports
-export([start/1, set_password/3, check_password/4,
check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, export/1, import/2,
plain_password_required/0, opt_type/1]).
-export([start/1, stop/1, set_password/3, try_register/3,
get_users/2, count_users/2,
get_password/2, remove_user/2, store_type/1, export/1, import/2,
plain_password_required/1]).
-export([passwd_schema/0]).
-include("ejabberd.hrl").
@@ -51,246 +44,65 @@
-record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1',
password = <<"">> :: binary() | scram() | '_'}).
-define(SALT_LENGTH, 16).
start(_Host) ->
ok.
plain_password_required() ->
case is_scrammed() of
false -> false;
true -> true
end.
stop(_Host) ->
ok.
store_type() ->
case is_scrammed() of
false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
true -> scram %% allows: PLAIN SCRAM
end.
plain_password_required(Server) ->
store_type(Server) == scram.
store_type(Server) ->
ejabberd_auth:password_format(Server).
passwd_schema() ->
{record_info(fields, passwd), #passwd{}}.
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
{ok, #passwd{password = Password}} when is_binary(Password) ->
Password /= <<"">>;
{ok, #passwd{password = Scram}} when is_record(Scram, scram) ->
is_password_scram_valid(Password, Scram);
_ ->
false
end
end.
check_password(User, AuthzId, Server, Password, Digest,
DigestGen) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
{ok, #passwd{password = Passwd}} when is_binary(Passwd) ->
DigRes = if Digest /= <<"">> ->
Digest == DigestGen(Passwd);
true -> false
end,
if DigRes -> true;
true -> (Passwd == Password) and (Password /= <<"">>)
end;
{ok, #passwd{password = Scram}}
when is_record(Scram, scram) ->
Passwd = jlib:decode_base64(Scram#scram.storedkey),
DigRes = if Digest /= <<"">> ->
Digest == DigestGen(Passwd);
true -> false
end,
if DigRes -> true;
true -> (Passwd == Password) and (Password /= <<"">>)
end;
_ -> false
end
end.
set_password(User, Server, Password) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
US = {LUser, LServer},
if (LUser == error) or (LServer == error) ->
{error, invalid_jid};
true ->
Password2 = case is_scrammed() and is_binary(Password)
of
true -> password_to_scram(Password);
false -> Password
end,
ok = ejabberd_riak:put(#passwd{us = US, password = Password2},
passwd_schema(),
[{'2i', [{<<"host">>, LServer}]}])
ejabberd_riak:put(#passwd{us = {User, Server}, password = Password},
passwd_schema(),
[{'2i', [{<<"host">>, Server}]}]).
try_register(User, Server, Password) ->
US = {User, Server},
case ejabberd_riak:get(passwd, passwd_schema(), US) of
{error, notfound} ->
ejabberd_riak:put(#passwd{us = US, password = Password},
passwd_schema(),
[{'2i', [{<<"host">>, Server}]}]);
{ok, _} ->
{error, exists};
{error, _} = Err ->
Err
end.
try_register(User, Server, PasswordList) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
Password = if is_list(PasswordList); is_binary(PasswordList) ->
iolist_to_binary(PasswordList);
true -> PasswordList
end,
US = {LUser, LServer},
if (LUser == error) or (LServer == error) ->
{error, invalid_jid};
true ->
case ejabberd_riak:get(passwd, passwd_schema(), US) of
{error, notfound} ->
Password2 = case is_scrammed() and
is_binary(Password)
of
true -> password_to_scram(Password);
false -> Password
end,
{atomic, ejabberd_riak:put(
#passwd{us = US,
password = Password2},
passwd_schema(),
[{'2i', [{<<"host">>, LServer}]}])};
{ok, _} ->
exists;
Err ->
{atomic, Err}
end
end.
dirty_get_registered_users() ->
lists:flatmap(
fun(Server) ->
get_vh_registered_users(Server)
end, ejabberd_config:get_vh_by_auth_method(riak)).
get_vh_registered_users(Server) ->
LServer = jid:nameprep(Server),
case ejabberd_riak:get_keys_by_index(passwd, <<"host">>, LServer) of
get_users(Server, _) ->
case ejabberd_riak:get_keys_by_index(passwd, <<"host">>, Server) of
{ok, Users} ->
Users;
_ ->
[]
end.
get_vh_registered_users(Server, _) ->
get_vh_registered_users(Server).
get_vh_registered_users_number(Server) ->
LServer = jid:nameprep(Server),
case ejabberd_riak:count_by_index(passwd, <<"host">>, LServer) of
count_users(Server, _) ->
case ejabberd_riak:count_by_index(passwd, <<"host">>, Server) of
{ok, N} ->
N;
_ ->
0
end.
get_vh_registered_users_number(Server, _) ->
get_vh_registered_users_number(Server).
get_password(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
{ok, #passwd{password = Password}}
when is_binary(Password) ->
Password;
{ok, #passwd{password = Scram}}
when is_record(Scram, scram) ->
{jlib:decode_base64(Scram#scram.storedkey),
jlib:decode_base64(Scram#scram.serverkey),
jlib:decode_base64(Scram#scram.salt),
Scram#scram.iterationcount};
_ -> false
end.
get_password_s(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
{ok, #passwd{password = Password}}
when is_binary(Password) ->
Password;
{ok, #passwd{password = Scram}}
when is_record(Scram, scram) ->
<<"">>;
_ -> <<"">>
end.
is_user_exists(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
{error, notfound} -> false;
{ok, _} -> true;
Err -> Err
case ejabberd_riak:get(passwd, passwd_schema(), {User, Server}) of
{ok, Password} ->
{ok, Password};
{error, _} ->
error
end.
remove_user(User, Server) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
ejabberd_riak:delete(passwd, {LUser, LServer}),
ok.
remove_user(User, Server, Password) ->
LUser = jid:nodeprep(User),
LServer = jid:nameprep(Server),
case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
{ok, #passwd{password = Password}}
when is_binary(Password) ->
ejabberd_riak:delete(passwd, {LUser, LServer}),
ok;
{ok, #passwd{password = Scram}}
when is_record(Scram, scram) ->
case is_password_scram_valid(Password, Scram) of
true ->
ejabberd_riak:delete(passwd, {LUser, LServer}),
ok;
false -> not_allowed
end;
_ -> not_exists
end.
%%%
%%% SCRAM
%%%
is_scrammed() ->
scram ==
ejabberd_config:get_local_option({auth_password_format, ?MYNAME},
fun(V) -> V end).
password_to_scram(Password) ->
password_to_scram(Password,
?SCRAM_DEFAULT_ITERATION_COUNT).
password_to_scram(Password, IterationCount) ->
Salt = randoms:bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Password, Salt,
IterationCount),
StoredKey =
scram:stored_key(scram:client_key(SaltedPassword)),
ServerKey = scram:server_key(SaltedPassword),
#scram{storedkey = jlib:encode_base64(StoredKey),
serverkey = jlib:encode_base64(ServerKey),
salt = jlib:encode_base64(Salt),
iterationcount = IterationCount}.
is_password_scram_valid(Password, Scram) ->
IterationCount = Scram#scram.iterationcount,
Salt = jlib:decode_base64(Scram#scram.salt),
SaltedPassword = scram:salted_password(Password, Salt,
IterationCount),
StoredKey =
scram:stored_key(scram:client_key(SaltedPassword)),
jlib:decode_base64(Scram#scram.storedkey) == StoredKey.
ejabberd_riak:delete(passwd, {User, Server}).
export(_Server) ->
[{passwd,
@@ -306,6 +118,3 @@ export(_Server) ->
import(LServer, [LUser, Password, _TimeStamp]) ->
Passwd = #passwd{us = {LUser, LServer}, password = Password},
ejabberd_riak:put(Passwd, passwd_schema(), [{'2i', [{<<"host">>, LServer}]}]).
opt_type(auth_password_format) -> fun (V) -> V end;
opt_type(_) -> [auth_password_format].
+188 -384
View File
@@ -5,7 +5,7 @@
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2016 ProcessOne
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -27,20 +27,14 @@
-compile([{parse_transform, ejabberd_sql_pt}]).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-behaviour(ejabberd_auth).
-behaviour(ejabberd_config).
-export([start/1, set_password/3, check_password/4,
check_password/6, try_register/3,
dirty_get_registered_users/0, get_vh_registered_users/1,
get_vh_registered_users/2,
get_vh_registered_users_number/1,
get_vh_registered_users_number/2, get_password/2,
get_password_s/2, is_user_exists/2, remove_user/2,
remove_user/3, store_type/0, plain_password_required/0,
-export([start/1, stop/1, set_password/3, try_register/3,
get_users/2, count_users/2, get_password/2,
remove_user/2, store_type/1, plain_password_required/1,
convert_to_scram/1, opt_type/1]).
-include("ejabberd.hrl").
@@ -54,387 +48,88 @@
%%%----------------------------------------------------------------------
start(_Host) -> ok.
plain_password_required() ->
case is_scrammed() of
false -> false;
true -> true
end.
stop(_Host) -> ok.
store_type() ->
case is_scrammed() of
false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
true -> scram %% allows: PLAIN SCRAM
end.
plain_password_required(Server) ->
store_type(Server) == scram.
%% @spec (User, AuthzId, Server, Password) -> true | false | {error, Error}
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
false;
(LUser == <<>>) or (LServer == <<>>) ->
false;
true ->
case is_scrammed() of
true ->
try sql_queries:get_password_scram(LServer, LUser) of
{selected,
[{StoredKey, ServerKey, Salt, IterationCount}]} ->
Scram =
#scram{storedkey = StoredKey,
serverkey = ServerKey,
salt = Salt,
iterationcount = IterationCount},
is_password_scram_valid_stored(Password, Scram, LUser, LServer);
{selected, []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
end;
false ->
try sql_queries:get_password(LServer, LUser) of
{selected, [{Password}]} ->
Password /= <<"">>;
{selected, [{_Password2}]} ->
false; %% Password is not correct
{selected, []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
end
end
end
end.
store_type(Server) ->
ejabberd_auth:password_format(Server).
%% @spec (User, AuthzId, Server, Password, Digest, DigestGen) -> true | false | {error, Error}
check_password(User, AuthzId, Server, Password, Digest,
DigestGen) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
false;
(LUser == <<>>) or (LServer == <<>>) ->
false;
true ->
case is_scrammed() of
false ->
try sql_queries:get_password(LServer, LUser) of
%% Account exists, check if password is valid
{selected, [{Passwd}]} ->
DigRes = if Digest /= <<"">> ->
Digest == DigestGen(Passwd);
true -> false
end,
if DigRes -> true;
true -> (Passwd == Password) and (Password /= <<"">>)
end;
{selected, []} ->
false; %% Account does not exist
{error, _Error} ->
false %% Typical error is that table doesn't exist
catch
_:_ ->
false %% Typical error is database not accessible
end;
true ->
false
end
end
end.
%% @spec (User::string(), Server::string(), Password::string()) ->
%% ok | {error, invalid_jid}
set_password(User, Server, Password) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
{error, invalid_jid};
(LUser == <<>>) or (LServer == <<>>) ->
{error, invalid_jid};
true ->
case is_scrammed() of
true ->
Scram = password_to_scram(Password),
case catch sql_queries:set_password_scram_t(
LServer,
LUser,
Scram#scram.storedkey,
Scram#scram.serverkey,
Scram#scram.salt,
Scram#scram.iterationcount
)
of
{atomic, ok} -> ok;
Other -> {error, Other}
end;
false ->
case catch sql_queries:set_password_t(LServer,
LUser, Password)
of
{atomic, ok} -> ok;
Other -> {error, Other}
end
end
F = fun() ->
if is_record(Password, scram) ->
set_password_scram_t(
User,
Password#scram.storedkey, Password#scram.serverkey,
Password#scram.salt, Password#scram.iterationcount);
true ->
set_password_t(User, Password)
end
end,
case ejabberd_sql:sql_transaction(Server, F) of
{atomic, _} ->
ok;
{aborted, Reason} ->
?ERROR_MSG("failed to write to SQL table: ~p", [Reason]),
{error, db_failure}
end.
%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid}
try_register(User, Server, Password) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
{error, invalid_jid};
(LUser == <<>>) or (LServer == <<>>) ->
{error, invalid_jid};
true ->
case is_scrammed() of
true ->
Scram = password_to_scram(Password),
case catch sql_queries:add_user_scram(
LServer,
LUser,
Scram#scram.storedkey,
Scram#scram.serverkey,
Scram#scram.salt,
Scram#scram.iterationcount
) of
{updated, 1} -> {atomic, ok};
_ -> {atomic, exists}
end;
false ->
case catch sql_queries:add_user(LServer, LUser,
Password) of
{updated, 1} -> {atomic, ok};
_ -> {atomic, exists}
end
end
Res = if is_record(Password, scram) ->
add_user_scram(
Server, User,
Password#scram.storedkey, Password#scram.serverkey,
Password#scram.salt, Password#scram.iterationcount);
true ->
add_user(Server, User, Password)
end,
case Res of
{updated, 1} -> ok;
_ -> {error, exists}
end.
dirty_get_registered_users() ->
Servers = ejabberd_config:get_vh_by_auth_method(sql),
lists:flatmap(fun (Server) ->
get_vh_registered_users(Server)
end,
Servers).
get_vh_registered_users(Server) ->
case jid:nameprep(Server) of
error -> [];
<<>> -> [];
LServer ->
case catch sql_queries:list_users(LServer) of
{selected, Res} ->
[{U, LServer} || {U} <- Res];
_ -> []
end
get_users(Server, Opts) ->
case list_users(Server, Opts) of
{selected, Res} ->
[{U, Server} || {U} <- Res];
_ -> []
end.
get_vh_registered_users(Server, Opts) ->
case jid:nameprep(Server) of
error -> [];
<<>> -> [];
LServer ->
case catch sql_queries:list_users(LServer, Opts) of
{selected, Res} ->
[{U, LServer} || {U} <- Res];
_ -> []
end
end.
get_vh_registered_users_number(Server) ->
case jid:nameprep(Server) of
error -> 0;
<<>> -> 0;
LServer ->
case catch sql_queries:users_number(LServer) of
{selected, [{Res}]} ->
Res;
_ -> 0
end
end.
get_vh_registered_users_number(Server, Opts) ->
case jid:nameprep(Server) of
error -> 0;
<<>> -> 0;
LServer ->
case catch sql_queries:users_number(LServer, Opts) of
{selected, [{Res}]} ->
Res;
_Other -> 0
end
count_users(Server, Opts) ->
case users_number(Server, Opts) of
{selected, [{Res}]} ->
Res;
_Other -> 0
end.
get_password(User, Server) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
false;
(LUser == <<>>) or (LServer == <<>>) ->
false;
true ->
case is_scrammed() of
true ->
case catch sql_queries:get_password_scram(
LServer, LUser) of
{selected,
[{StoredKey, ServerKey, Salt, IterationCount}]} ->
{jlib:decode_base64(StoredKey),
jlib:decode_base64(ServerKey),
jlib:decode_base64(Salt),
IterationCount};
_ -> false
end;
false ->
case catch sql_queries:get_password(LServer, LUser)
of
{selected, [{Password}]} -> Password;
_ -> false
end
end
case get_password_scram(Server, User) of
{selected, [{Password, <<>>, <<>>, 0}]} ->
{ok, Password};
{selected, [{StoredKey, ServerKey, Salt, IterationCount}]} ->
{ok, #scram{storedkey = StoredKey,
serverkey = ServerKey,
salt = Salt,
iterationcount = IterationCount}};
{selected, []} ->
error;
Err ->
?ERROR_MSG("Failed to read password for user ~s@~s: ~p",
[User, Server, Err]),
error
end.
get_password_s(User, Server) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
<<"">>;
(LUser == <<>>) or (LServer == <<>>) ->
<<"">>;
true ->
case is_scrammed() of
false ->
case catch sql_queries:get_password(LServer, LUser) of
{selected, [{Password}]} -> Password;
_ -> <<"">>
end;
true -> <<"">>
end
end.
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
false;
(LUser == <<>>) or (LServer == <<>>) ->
false;
true ->
try sql_queries:get_password(LServer, LUser) of
{selected, [{_Password}]} ->
true; %% Account exists
{selected, []} ->
false; %% Account does not exist
{error, Error} -> {error, Error}
catch
_:B -> {error, B}
end
end.
%% @spec (User, Server) -> ok | error
%% @doc Remove user.
%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
error;
(LUser == <<>>) or (LServer == <<>>) ->
error;
true ->
catch sql_queries:del_user(LServer, LUser),
ok
case del_user(Server, User) of
{updated, _} ->
ok;
Err ->
?ERROR_MSG("failed to delete user ~s@~s: ~p",
[User, Server, Err]),
{error, db_failure}
end.
%% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed
%% @doc Remove user if the provided password is correct.
remove_user(User, Server, Password) ->
LServer = jid:nameprep(Server),
LUser = jid:nodeprep(User),
if (LUser == error) or (LServer == error) ->
error;
(LUser == <<>>) or (LServer == <<>>) ->
error;
true ->
case is_scrammed() of
true ->
case check_password(User, <<"">>, Server, Password) of
true ->
remove_user(User, Server),
ok;
false -> not_allowed
end;
false ->
F = fun () ->
Result = sql_queries:del_user_return_password(
LServer, LUser, Password),
case Result of
{selected, [{Password}]} -> ok;
{selected, []} -> not_exists;
_ -> not_allowed
end
end,
{atomic, Result} = sql_queries:sql_transaction(
LServer, F),
Result
end
end.
%%%
%%% SCRAM
%%%
is_scrammed() ->
scram ==
ejabberd_config:get_option({auth_password_format, ?MYNAME},
fun(V) -> V end).
password_to_scram(Password) ->
password_to_scram(Password,
?SCRAM_DEFAULT_ITERATION_COUNT).
password_to_scram(Password, IterationCount) ->
Salt = randoms:bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Password, Salt,
IterationCount),
StoredKey =
scram:stored_key(scram:client_key(SaltedPassword)),
ServerKey = scram:server_key(SaltedPassword),
#scram{storedkey = jlib:encode_base64(StoredKey),
serverkey = jlib:encode_base64(ServerKey),
salt = jlib:encode_base64(Salt),
iterationcount = IterationCount}.
is_password_scram_valid_stored(Pass, {scram,Pass,<<>>,<<>>,0}, LUser, LServer) ->
?INFO_MSG("Apparently, SQL auth method and scram password formatting are "
"enabled, but the password of user '~s' in the 'users' table is not "
"scrammed. You may want to execute this command: "
"ejabberdctl convert_to_scram ~s", [LUser, LServer]),
false;
is_password_scram_valid_stored(Password, Scram, _, _) ->
is_password_scram_valid(Password, Scram).
is_password_scram_valid(Password, Scram) ->
IterationCount = Scram#scram.iterationcount,
Salt = jlib:decode_base64(Scram#scram.salt),
SaltedPassword = scram:salted_password(Password, Salt,
IterationCount),
StoredKey =
scram:stored_key(scram:client_key(SaltedPassword)),
jlib:decode_base64(Scram#scram.storedkey) == StoredKey.
-define(BATCH_SIZE, 1000).
set_password_scram_t(LUser,
@@ -447,6 +142,105 @@ set_password_scram_t(LUser,
"salt=%(Salt)s",
"iterationcount=%(IterationCount)d"]).
set_password_t(LUser, Password) ->
?SQL_UPSERT_T(
"users",
["!username=%(LUser)s",
"password=%(Password)s"]).
get_password_scram(LServer, LUser) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(password)s, @(serverkey)s, @(salt)s, @(iterationcount)d"
" from users"
" where username=%(LUser)s")).
add_user_scram(LServer, LUser,
StoredKey, ServerKey, Salt, IterationCount) ->
ejabberd_sql:sql_query(
LServer,
?SQL("insert into users(username, password, serverkey, salt, "
"iterationcount) "
"values (%(LUser)s, %(StoredKey)s, %(ServerKey)s,"
" %(Salt)s, %(IterationCount)d)")).
add_user(LServer, LUser, Password) ->
ejabberd_sql:sql_query(
LServer,
?SQL("insert into users(username, password) "
"values (%(LUser)s, %(Password)s)")).
del_user(LServer, LUser) ->
ejabberd_sql:sql_query(
LServer,
?SQL("delete from users where username=%(LUser)s")).
list_users(LServer, []) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users"));
list_users(LServer, [{from, Start}, {to, End}])
when is_integer(Start) and is_integer(End) ->
list_users(LServer,
[{limit, End - Start + 1}, {offset, Start - 1}]);
list_users(LServer,
[{prefix, Prefix}, {from, Start}, {to, End}])
when is_binary(Prefix) and is_integer(Start) and
is_integer(End) ->
list_users(LServer,
[{prefix, Prefix}, {limit, End - Start + 1},
{offset, Start - 1}]);
list_users(LServer, [{limit, Limit}, {offset, Offset}])
when is_integer(Limit) and is_integer(Offset) ->
ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users "
"order by username "
"limit %(Limit)d offset %(Offset)d"));
list_users(LServer,
[{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
when is_binary(Prefix) and is_integer(Limit) and
is_integer(Offset) ->
SPrefix = ejabberd_sql:escape_like_arg_circumflex(Prefix),
SPrefix2 = <<SPrefix/binary, $%>>,
ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users "
"where username like %(SPrefix2)s escape '^' "
"order by username "
"limit %(Limit)d offset %(Offset)d")).
users_number(LServer) ->
ejabberd_sql:sql_query(
LServer,
fun(pgsql, _) ->
case
ejabberd_config:get_option(
{pgsql_users_number_estimate, LServer}, false) of
true ->
ejabberd_sql:sql_query_t(
?SQL("select @(reltuples :: bigint)d from pg_class"
" where oid = 'users'::regclass::oid"));
_ ->
ejabberd_sql:sql_query_t(
?SQL("select @(count(*))d from users"))
end;
(_Type, _) ->
ejabberd_sql:sql_query_t(
?SQL("select @(count(*))d from users"))
end).
users_number(LServer, [{prefix, Prefix}])
when is_binary(Prefix) ->
SPrefix = ejabberd_sql:escape_like_arg_circumflex(Prefix),
SPrefix2 = <<SPrefix/binary, $%>>,
ejabberd_sql:sql_query(
LServer,
?SQL("select @(count(*))d from users "
"where username like %(SPrefix2)s escape '^'"));
users_number(LServer, []) ->
users_number(LServer).
convert_to_scram(Server) ->
LServer = jid:nameprep(Server),
if
@@ -466,20 +260,27 @@ convert_to_scram(Server) ->
{selected, Rs} ->
lists:foreach(
fun({LUser, Password}) ->
Scram = password_to_scram(Password),
set_password_scram_t(
LUser,
Scram#scram.storedkey,
Scram#scram.serverkey,
Scram#scram.salt,
Scram#scram.iterationcount
)
case jid:resourceprep(Password) of
error ->
?ERROR_MSG(
"SASLprep failed for "
"password of user ~s@~s",
[LUser, LServer]);
_ ->
Scram = ejabberd_auth:password_to_scram(Password),
set_password_scram_t(
LUser,
Scram#scram.storedkey,
Scram#scram.serverkey,
Scram#scram.salt,
Scram#scram.iterationcount)
end
end, Rs),
continue;
Err -> {bad_reply, Err}
end
end,
case sql_queries:sql_transaction(LServer, F) of
case ejabberd_sql:sql_transaction(LServer, F) of
{atomic, ok} -> ok;
{atomic, continue} -> convert_to_scram(Server);
{atomic, Error} -> {error, Error};
@@ -487,5 +288,8 @@ convert_to_scram(Server) ->
end
end.
opt_type(auth_password_format) -> fun (V) -> V end;
opt_type(_) -> [auth_password_format].
-spec opt_type(pgsql_users_number_estimate) -> fun((boolean()) -> boolean());
(atom()) -> [atom()].
opt_type(pgsql_users_number_estimate) ->
fun (V) when is_boolean(V) -> V end;
opt_type(_) -> [pgsql_users_number_estimate].
+46
View File
@@ -0,0 +1,46 @@
%%%-------------------------------------------------------------------
%%% Created : 24 Feb 2017 by Evgeny Khramtsov <ekhramtsov@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2017 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%-------------------------------------------------------------------
-module(ejabberd_backend_sup).
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
%%%===================================================================
%%% API functions
%%%===================================================================
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%%%===================================================================
%%% Supervisor callbacks
%%%===================================================================
init([]) ->
{ok, {{one_for_one, 10, 1}, []}}.
%%%===================================================================
%%% Internal functions
%%%===================================================================

Some files were not shown because too many files have changed in this diff Show More