Compare commits

...

281 Commits

Author SHA1 Message Date
Paweł Chmielowski b72ed7afa4 Update mix.lock 2018-09-26 15:01:27 +02:00
Christophe Romain c109d3eff0 Add odbc connection robustness (#2428) 2018-09-25 16:59:49 +02:00
Paweł Chmielowski 0d743da595 Update xmpp 2018-09-25 16:18:16 +02:00
Paweł Chmielowski ef57067edc Update deps in mix.lock 2018-09-25 14:31:22 +02:00
Badlop e054c2800b Allow a subscribed owner/admin to kick lower-affiliation moderator 2018-09-25 10:55:57 +02:00
Badlop 49f1b4a691 Allow an occupant owner/admin to kick lower-affiliation moderator 2018-09-25 10:55:56 +02:00
Badlop 8b61c7fe4b Allow a subscribed owner/admin to kick participants and visitors 2018-09-25 10:55:54 +02:00
Badlop 9bac2fa185 Allow a subscribed owner/admin to change participant<->visitor 2018-09-25 10:55:51 +02:00
Paweł Chmielowski c3f62c037d Update deps once more 2018-09-24 15:49:26 +02:00
Paweł Chmielowski 4ddee2d89b Increase validity of generated test ca cert and regenerate all certs 2018-09-24 15:19:19 +02:00
Paweł Chmielowski 054426072e Update deps 2018-09-24 14:37:54 +02:00
Evgeny Khramtsov f28200b6de Update ISSUE_TEMPLATE 2018-09-21 19:20:23 +03:00
Evgeny Khramtsov 8c16400332 Update ISSUE_TEMPLATE 2018-09-21 19:02:14 +03:00
Paweł Chmielowski 0394baaa7a Allow changing invitation message from muc_invite hook 2018-09-21 16:37:52 +02:00
Paweł Chmielowski 1b3a6dd54a Recognize more fields that aren't atom in format_room_option 2018-09-20 18:02:47 +02:00
Evgeny Khramtsov 6d1ea222c0 Remove forgotten debug line 2018-09-19 23:17:04 +03:00
Evgeny Khramtsov 08f3d066b1 Switch more log message to warning level
The commit is supposed to improve logging at loglevel 3, which
is the recommended level for high loaded ejabberd servers
2018-09-19 23:12:14 +03:00
Evgeny Khramtsov ddca2e8b4a Switch mod_fail2ban log messages to warning level 2018-09-19 19:33:33 +03:00
Evgeny Khramtsov a2b2a27bb6 Resize SQL pool on configuration reload
Fixes #2541
2018-09-19 11:55:40 +03:00
Evgeny Khramtsov d60d72d7bf Don't hide 'undef' exceptions during config validation 2018-09-19 01:00:50 +03:00
Evgeny Khramtsov 7ff5f2d3fa Fail early when loading unavailable SIP or STUN modules 2018-09-18 18:19:42 +03:00
Evgeny Khramtsov 1866b56e3b Report real address of a listener 2018-09-18 14:51:42 +03:00
Evgeny Khramtsov e96bfbdbfa Remove useless type specs 2018-09-18 13:24:06 +03:00
Evgeny Khramtsov 3cc964fbcc Fix listeners child specs creation 2018-09-18 13:22:34 +03:00
Evgeny Khramtsov 29f6c43ae3 Remove forgotten debug line 2018-09-18 12:58:29 +03:00
Evgeny Khramtsov 03de853e4f Refactor ejabberd_listener 2018-09-18 12:53:36 +03:00
Paweł Chmielowski fb367469d4 Add ability to configure test to use new sql schema 2018-09-18 09:44:54 +02:00
Holger Weiss d2cdfa66f9 mod_http_upload: Log error if 'put_url' is reused
Log a proper [error] message if a single 'put_url' is used for multiple
virtual hosts.
2018-09-17 21:46:37 +02:00
Badlop d5c1174385 Revert "New option tombstone_expiry locks recent room creation after destroy (#2546)"
This reverts commit efb4fd0d10.
2018-09-17 12:28:39 +02:00
Evgeny Khramtsov dd888f90ec Improve error formatting 2018-09-17 12:08:04 +03:00
Badlop bb9593dd12 Remove unused variables 2018-09-17 10:42:29 +02:00
Evgeny Khramtsov de385591d0 Refactor ejabberd listener API 2018-09-17 11:21:02 +03:00
Paweł Chmielowski 78dae4036e Reintroduce change removed by mistake in 'Improve match macro' 2018-09-17 09:34:15 +02:00
Holger Weiss dafea66c0f Increase 'max_stanza_size' limit for c2s listener
Specify a larger 'max_stanza_size' limit for c2s connections in the
default configuration in order to reduce the risk of this limit being
hit by legitimate traffic (such as avatar uploads).
2018-09-17 00:18:38 +02:00
Holger Weiss c851f9608a Set a 'max_stanza_size' for incoming s2s listener
Specify a 'max_stanza_size' limit for incoming s2s connections in the
example configuration, but use a relatively large value in order to
minimize the risk of this limit being hit by legitimate traffic.
2018-09-16 23:57:44 +02:00
Holger Weiss 3367c5b120 MySQL: Use MEDIUMTEXT for MAM/offline messages
Let MySQL/MariaDB accept message stanzas with a size of up to 16 MiB,
rather than truncating at 64 KiB.
2018-09-16 20:42:37 +02:00
Paweł Chmielowski d4579d2a20 [test] Improve match macro 2018-09-14 20:27:59 +02:00
Paweł Chmielowski 410ac9b966 [tests] Update stream_id from stream:stream after auth 2018-09-14 20:27:33 +02:00
Holger Weiss adf0d7de91 mod_muc_room: Fix the room's CAPS hash
Don't forget the room's xdata when calculating the CAPS hash.
2018-09-14 00:18:17 +02:00
Evgeny Khramtsov 8c03427c25 Merge pull request #2605 from af8a524db1/remove_unused_error
mod_register: Remove unused error 'too_many_users'
2018-09-13 22:36:59 +03:00
Marc Schink c156eabb24 mod_register: Remove unused error 'too_many_users' 2018-09-13 21:34:12 +02:00
Badlop 1d6cbd2561 Trigger hook for user_send_packet in send_message command (#2604) 2018-09-13 18:21:30 +02:00
Evgeny Khramtsov a7a1e7be94 Merge pull request #2602 from aquarhead/expect-mnesia-up
Expect mnesia_up event when joining cluster
2018-09-12 17:15:04 +03:00
AquarHEAD Lou 8673d2926d Expect mnesia_up event when joining cluster 2018-09-12 11:01:05 +00:00
Evgeny Khramtsov 2d246f61dd Fix some dialyzer warnings 2018-09-09 09:59:08 +03:00
Evgeny Khramtsov 9de2ca4568 Merge pull request #2597 from dmitryDemchenko/master
fix for freetds UTF-8 corruption
2018-09-07 22:50:16 +03:00
root b545301f63 fix for freetds UTF-8 corruption 2018-09-07 19:56:39 +03:00
Evgeny Khramtsov 145c0116bf Bump lager version
This is needed for OTP-21 compatibility
2018-09-07 18:03:36 +03:00
Paweł Chmielowski 79c511a441 Add information about real sender to mucsub message meta 2018-09-06 13:36:59 +02:00
Paweł Chmielowski 90b22da880 Use newere fast_tls 2018-09-05 11:14:19 +02:00
Paweł Chmielowski 57936bfa4e Don't stop sending pings when receiving timeout for timeout_action=none 2018-09-04 09:52:41 +02:00
Evgeniy Khramtsov 5c931d7004 Correctly handle empty result with RSM
Fixes #2588
2018-09-02 00:37:07 +03:00
Evgeniy Khramtsov 88d0b71d58 Get stacktrace out of lager context
Calling erlang:get_stacktrace() inside lager functions produces
stacktraces of the logging function itself, not the function which has failed.
2018-09-01 19:37:26 +03:00
Evgeniy Khramtsov b416527e4f Don't set termination reason into presence-unavailable status
Fixes https://github.com/processone/xmpp/issues/35
2018-09-01 17:39:39 +03:00
Holger Weiss 8c8c480477 ejabberd_s2s_in: Log message on connection close
Log a message when an incoming s2s connection is closed, analogous to
the message on outgoing s2s connection close.
2018-08-29 16:23:56 +02:00
Paweł Chmielowski 66132353df Sign certs used by tests with sha256
Seems that openssl1.1.1 (at least debian version) rejects certs signed with
md5 or sha1, so lets use something that works.
2018-08-28 11:27:44 +02:00
Evgeniy Khramtsov b30a9f2f75 Better formatting of unexpected return from Module:start/2 2018-08-28 10:41:57 +03:00
Badlop 0cbd41fbdc Fix max_user_conferences in Mnesia to consider only one MUC service (#2556) 2018-08-20 15:47:53 +02:00
Evgeniy Khramtsov 5b055d7eec Use "localhost" as a default host 2018-08-17 18:42:09 +03:00
Evgeniy Khramtsov 01a1f929b4 Bump xmpp version 2018-08-17 18:16:14 +03:00
Evgeniy Khramtsov f0f3ec211e Disable cache for anonymous auth backend
Fixes #2566
2018-08-17 17:56:23 +03:00
Paweł Chmielowski fd76bc9242 Update xmpp 2018-08-16 11:59:26 +02:00
Badlop 6cd70947be Third attempt to fix the typo! 2018-08-15 12:56:41 +02:00
Badlop 8cefe58a89 Fix typo from commit 0bf93eefc 2018-08-15 12:40:39 +02:00
Badlop c3361bab95 Handle get_presence(Pid) when session doesn't exist (#2547) 2018-08-15 12:16:01 +02:00
Badlop f3f3b1586e Fix typo in command description 2018-08-13 16:42:16 +02:00
Badlop 0bf93eefcb Try to update tests to handle recent MUC subscriptions change (#2272) 2018-08-13 15:26:40 +02:00
Badlop 10e01b7bfc Return human error messages when calling export2sql with wrong path (#2480) 2018-08-13 13:56:29 +02:00
Badlop 8f0e066135 In response with list of room subscriptions include also events (#2272) 2018-08-13 12:52:33 +02:00
Badlop dfd96b6037 Remove num_active_users as it uses calls to last_activity mnesia table (#2448) 2018-08-08 14:18:49 +02:00
Badlop 5b373470ac Remove direct calls to muc_room mnesia table in mod_muc_admin (#2448) 2018-08-08 14:18:34 +02:00
Badlop 0146189b65 Add markdown options as specified in the docs git repo 2018-08-07 16:59:26 +02:00
Badlop 4c4c82897c Add import_prosody explanation from docs git repo 2018-08-07 16:58:53 +02:00
Badlop 5509e648ad Allow acme and oauth commands to be read by gen_markdown_doc_for_commands 2018-08-07 16:58:48 +02:00
Badlop c9ba0e83d2 Handle ejabberd_captcha error reports in mod_register_web (#2553) 2018-08-02 18:36:41 +02:00
Evgeny Khramtsov b56c012407 Merge pull request #2551 from MarcelWaldvogel/configurable-extauth-pool
Make it possible to join extauth pools
2018-07-31 07:52:06 +03:00
Marcel Waldvogel 9b48dc9cc3 Make it possible to join extauth pools 2018-07-30 22:49:18 +02:00
Badlop efb4fd0d10 New option tombstone_expiry locks recent room creation after destroy (#2546)
Setting the new mod_muc option tombstone_expiry to a positive integer
will make that any room destroyed gets replaced with a room tombstone.
That tombstone cannot be joined, so it blocks accessing the old room JID
until the expiry seconds have passed.
The default value is 0 seconds, so tombstones are not created.
2018-07-30 19:24:35 +02:00
Holger Weiss 83e2462853 mod_mam: Don't strip offline message stanza IDs
As mod_offline currently doesn't preserve metadata, add an explicit
check for messages retrieved from offline storage to avoid stripping
their stanza IDs.

Thanks to Zuglufttier for spotting this.
2018-07-27 00:27:10 +02:00
Holger Weiss cdfd0cce7b mod_mam: Make sure stanza IDs aren't reused
Strip the stanza ID from the metadata of outgoing messages to make sure
it's not reused for the (local) recipient's MAM archive.
2018-07-27 00:14:48 +02:00
Holger Weiss 2d45832a39 ejabberd_auth: Restore lost case clause
Let check_password_with_authmodule/6 handle the case where
validate_credentials/2 returns an error.  This got lost in commit
4f8af723c6.
2018-07-26 22:37:25 +02:00
Paweł Chmielowski 1af2cf37ea Wait for more data than just <stream:stream> before sending in bosh
This fixes issue #2545
2018-07-26 18:56:05 +02:00
Paweł Chmielowski ca022b6d1f Make sure that we always start inactivity timer from drop_holding_receiver 2018-07-26 17:29:35 +02:00
Paweł Chmielowski e54f1a8485 Set wait_timer to undefined when timer was triggered 2018-07-26 17:29:35 +02:00
Badlop 1be2112634 Fix search for User in vjud
See https://stackoverflow.com/questions/51478247/ejabberd-search-module-failed-to-handle-the-query
2018-07-24 20:01:22 +02:00
Paweł Chmielowski 6dc452e7f5 Update xmpp 2018-07-23 17:23:11 +02:00
Holger Weiss 57a3512dcc mod_http_upload: Adjust default value of 'put_url'
Let the default 'put_url' point to the HTTPS listener specified in the
new default configuration.
2018-07-18 19:44:56 +02:00
Evgeny Khramtsov 1de69174ef Merge pull request #2538 from weiss/tls-by-default
Enable TLS by default (and require it for c2s)
2018-07-18 19:38:13 +03:00
Holger Weiss 26b9d25f32 Enable TLS by default (and require it for c2s) 2018-07-18 18:22:24 +02:00
Holger Weiss 8ad6afd652 mod_http_upload: Deprecate 'service_url' option
Users should migrate to the 'external_secret' interface.
2018-07-18 18:16:42 +02:00
Evgeny Khramtsov 7fed5a3eb6 Merge pull request #2537 from rouen-sk/patch-1
Update mssql.sql
2018-07-18 18:37:30 +03:00
rouen-sk b199b68380 Update mssql.sql
Fixed:
- conflicting clustered indexes on 2 tables
- semicolon type
- Azure SQL incompatibility
2018-07-18 17:12:17 +02:00
Holger Weiss e433a63105 mod_http_upload: Avoid function-like macros 2018-07-17 22:28:31 +02:00
Holger Weiss 68c9328a9c Move cancel_timer/1 function into 'misc' module 2018-07-17 20:50:58 +02:00
Holger Weiss 6601f182c4 mod_http_upload: Add "Allow" to OPTIONS response
RFC 2616 says: "A 200 response SHOULD include any header fields that
indicate optional features implemented by the server and applicable to
that resource (e.g., Allow) [...]."
2018-07-17 19:42:57 +02:00
Holger Weiss 326db5535c mod_muc: Don't set default for muc#roomconfig_lang
For the muc#roomconfig_lang setting, no default is preferable over a
possibly incorrect default value.
2018-07-16 15:15:36 +02:00
Holger Weiss 2539be1a04 mod_http_upload: Avoid timers from timer module
Use erlang:start_timer/3 instead of timer:send_after/2, as the former is
more efficient.
2018-07-16 00:17:11 +02:00
Holger Weiss 4e9930597d mod_http_upload: Don't store "external" slots
Don't store requested upload slots if an 'external_secret' is
configured.
2018-07-15 21:53:50 +02:00
Evgeniy Khramtsov 2dfb5a6a5c Note about Redis requirement in the test suite README 2018-07-15 10:14:47 +03:00
Evgeniy Khramtsov 8faa6afa67 Require Redis version >= 3.2.0
Since we now use Lua scripting for cleaning up c2s sessions
the minimum supported Redis version is 3.2.0 or above because
we need to work correctly with Redis replication mechanism.

****** BACKWARD INCOMPATIBILITY WARNING *******
** THIS SHOULD BE ADDED TO THE RELEASE NOTES **
*** PACKAGE MAINTAINERS SHOULD BE INFORMED  ***
***********************************************
2018-07-15 09:52:03 +03:00
Holger Weiss 12e537c43f Avoid "ejabberdctl status" crash 2018-07-14 20:27:30 +02:00
Evgeniy Khramtsov 4394ec38b6 Don't forget to remove Lua scripts on uninstall 2018-07-14 18:02:50 +03:00
Evgeniy Khramtsov 420e05fa0d Clean up contributed code for Redis SM 2018-07-14 17:53:00 +03:00
Evgeny Khramtsov e2fb154fe9 Merge pull request #2525 from satish-olx/master
Use lua scripting to clear redis sessions.
2018-07-14 16:53:45 +03:00
Evgeniy Khramtsov e9f219a0ac Improve wording 2018-07-14 16:52:09 +03:00
Evgeny Khramtsov 711c5c0d54 Merge pull request #2526 from nosnilmot/enforce-pubsub-option-attributes
Enforce pubsub option required/rejected attributes
2018-07-14 16:42:15 +03:00
Stu Tomlinson f9ed34db4d Enforce pubsub option required/rejected attributes
XEP-0060 states that 'node' and 'jid' attributes to <options> element MUST NOT
be included when <options> are specified at same time as <subscribe> :

https://xmpp.org/extensions/xep-0060.html#subscriber-configure-subandconfig

mod_pubsub will require 'node' and 'jid' attributes on standalone pubsub
options requests, and reject subscribe requests that have options that include
either 'node' or 'jid'
2018-07-14 11:55:38 +01:00
Evgeny Khramtsov 9a895058e7 Merge pull request #2522 from weiss/bump-max-user-conferences
mod_muc: Increase default 'max_user_conferences' value
2018-07-14 08:51:11 +03:00
Paweł Chmielowski e76a57e144 Ensure that returned priority in a number in mod_admin_extra 2018-07-13 09:51:19 +02:00
satish-olx 6fc6bdefc2 Update ejabberd_sm_redis.erl 2018-07-12 16:14:26 +05:30
satish-olx 96e35a3248 Lua script for cleaning redis sessions
Changes:
1. Added extra keys for tracking node -> session mapping
2. Lua script for clearing the sessions in redis itself.
2018-07-12 16:10:24 +05:30
Paweł Chmielowski 48be8e7b1e Adopt code that uses parse_listener_portip after result change 2018-07-11 14:07:24 +02:00
Badlop f40f3a9da7 Fix piefxis import of privacy lists (thanks to crosser)(#2412) 2018-07-11 12:56:57 +02:00
Badlop f81b49fe44 Fix piefxis import of vCard elements (#2514) 2018-07-11 12:56:38 +02:00
Evgeniy Khramtsov 395d2e86bc Improve listener errors formatting 2018-07-11 09:29:55 +03:00
Holger Weiss 5b3af9d4cd Fix compiler warnings regarding test cases 2018-07-11 00:07:57 +02:00
Holger Weiss 7e5d766a02 pubsub_tests: Fix race condition 2018-07-10 21:25:06 +02:00
Holger Weiss c5dd1bdd9d mod_http_upload_quota: Fix process name lookup
Fix mod_http_upload_quota's process name lookup for the case where a
slot is requested by a JID whose domain part is not the virtual host the
mod_http_upload_quota process is running on.
2018-07-10 21:19:15 +02:00
Evgeniy Khramtsov d03432a956 Fix regression: list SASL EXTERNAL mechanism for inbound s2s 2018-07-10 10:14:08 +03:00
Holger Weiss 4b747c2c78 mod_muc: Increase 'max_user_conferences' default
Let up to 100 clients of a given account join MUC rooms by default.  The
old default value can be too small, e.g., when users join many (private)
rooms with multiple devices.
2018-07-10 01:00:06 +02:00
Holger Weiss 3a566e3cdf mod_stream_mgmt: Remove dead case clauses 2018-07-10 00:52:27 +02:00
Holger Weiss b915469f5e mod_stream_mgmt: Add descriptive text to errors
Closes #2485.
2018-07-10 00:46:48 +02:00
Evgeniy Khramtsov 8b9166d067 Improve value formatting 2018-07-09 20:32:01 +03:00
Paweł Chmielowski dc6861eb73 Use ejabberd_config:get_version in ejabberdctl status 2018-07-09 17:11:40 +02:00
Evgeny Khramtsov 90a4aafec0 Merge pull request #2516 from licaon-kter/patch-6
Remove vcard search default value
2018-07-09 10:08:00 +03:00
Licaon_Kter 4c06f13d18 Remove vcard search default value 2018-07-08 23:48:08 +00:00
Evgeniy Khramtsov 8c796ed027 Better format invalid values when logging them 2018-07-08 20:42:53 +03:00
Evgeniy Khramtsov 68d12017cc Better detection of duplicated routes/hosts 2018-07-08 20:28:11 +03:00
Evgeniy Khramtsov 491993d401 Reload internal room's configuration when mod_muc is reloaded
Fixes #2513
2018-07-08 14:52:12 +03:00
Evgeny Khramtsov a981bf9a59 Merge pull request #2511 from licaon-kter/patch-5
Remove stats and time from template
2018-07-08 10:43:25 +03:00
Evgeny Khramtsov 920e4512b6 Merge pull request #2515 from ChaosKid42/fix_HMAC_in_http_upload
fix generation of HMAC for external_secret
2018-07-08 10:42:55 +03:00
Christoph Scholz fbdcc44fd9 fix HMAC for external_secret 2018-07-07 17:01:39 +02:00
Paweł Chmielowski b2b29269ec Remove cyrsasl elixir tests, we no longer have it 2018-07-06 09:49:30 +02:00
Evgeniy Khramtsov 11811e5f48 Only lookup FQDN at configuration (re)loading 2018-07-06 09:18:27 +03:00
Licaon_Kter b7f62a4fa7 Remove stats and time from template
Are these important for a new admin?
2018-07-06 01:33:41 +00:00
Evgeniy Khramtsov 0bb14d16c7 Move XMPP stream and SASL processing to xmpp repo 2018-07-06 01:07:36 +03:00
Evgeniy Khramtsov 59f5a098b5 Use p1_rand in the test suite 2018-07-05 11:53:04 +03:00
Evgeniy Khramtsov ed1ee6061e Move move randoms module to p1_utils repo 2018-07-05 11:51:49 +03:00
Evgeniy Khramtsov 50b645aa92 Move shaper to p1_utils repo 2018-07-05 09:31:55 +03:00
Evgeniy Khramtsov 52f2a7de4b Set 'from' attribute for client connections when it is absent 2018-07-04 08:59:14 +03:00
Evgeniy Khramtsov bce8922e5d Don't set from/to attributes in resource binding iq 2018-07-04 08:57:28 +03:00
Evgeniy Khramtsov 86236431b9 mod_http_upload: Treat file and network errors differently 2018-07-04 08:55:52 +03:00
badlop c0d4d31b5b Merge pull request #2495 from rodrigues/update_ptbr
Update pt-br translations
2018-07-03 16:50:29 +02:00
Evgeniy Khramtsov 295bec8551 Don't ignore send() result 2018-07-03 13:44:58 +03:00
Evgeniy Khramtsov b341a3cef3 Increase default buffer size for mod_proxy65 2018-07-03 13:38:49 +03:00
Evgeniy Khramtsov fface33d54 HTTP Upload: introduce new option 'external_secret'
The option makes it possible to offload all HTTP Upload processing
to a separate HTTP server. Both ejabberd and the HTTP server
should share this secret and behave exactly as described at
at https://modules.prosody.im/mod_http_upload_external.html
in the 'Implementation' section. Example configuration:

modules:
  ...
  mod_http_upload:
    ...
    put_url: "http://separate.http.server/upload"
    external_secret: "foo bar baz"
  ...
2018-07-02 16:53:44 +03:00
Evgeniy Khramtsov fbf6ba2738 Merge branch 'master' of github.com:processone/ejabberd 2018-07-02 01:08:09 +03:00
Evgeniy Khramtsov 38ec3f66c7 Enable Roster Versioning in the default config file 2018-07-02 01:08:02 +03:00
Evgeny Khramtsov 56dc625f9a Merge pull request #2502 from licaon-kter/patch-4
Default config example fix reversed text
2018-07-02 00:20:46 +03:00
Licaon_Kter 7c5ee93c88 Default config example fix reversed text
...in enable OMEMO
2018-07-01 21:18:18 +00:00
Evgeniy Khramtsov 77163c43d2 Simplify the default configuration file
After some discussion with the community it was decided to
clean the configuration file from excessive comments and
explicitly configured default values. Also, mod_mam and
mod_http_upload have been added.

The rationale for this is to have a clean and not bloated
configuration file which doesn't scare away newcomers and
which has all features from the Compliance Suite 2018 (XEP-0387)
enabled by default.

For further configuration an admin is encouraged to read the
documentation at https://docs.ejabberd.im/admin/configuration
2018-07-01 23:57:27 +03:00
Victor Rodrigues d1d02e2f26 Update pt-br translations 2018-07-01 15:15:41 +02:00
Evgeniy Khramtsov 6b8bc811ac Don't crash on most common gen_server:call errors 2018-07-01 14:26:49 +03:00
Evgeniy Khramtsov b662ec2a78 Accept IP address as a return value from resolve/2 callback 2018-06-30 10:19:58 +03:00
Paweł Chmielowski 8ca035496e Update fast_xml and xmpp in mix.lock 2018-06-29 15:41:37 +02:00
Evgeniy Khramtsov a463f5a25a Replace hardcoded disco features with macros 2018-06-29 14:48:07 +03:00
Paweł Chmielowski dce4e4de6d Add check for files missing in hex packaging 2018-06-29 12:51:20 +02:00
Paweł Chmielowski 9b70177fd5 Update xmpp 2018-06-29 12:50:57 +02:00
Paweł Chmielowski 1fbb36c34a Fix misc:try_url for erlang < R20 2018-06-29 11:13:29 +02:00
Christophe Romain 46abf7cfab Rename obsolete type in comments 2018-06-29 11:10:35 +02:00
Paweł Chmielowski 62cb398734 Convert test that used moka, and drop that dependancy 2018-06-29 10:52:47 +02:00
Evgeniy Khramtsov dff940b89e Support both filenames and URLs in 'cssfile' option of mod_muc_log
If filename is provided, its content is inserted into the HTML page.
If URL is provided, it's used as a value of 'href' HTML attribute.
2018-06-29 11:34:53 +03:00
Evgeniy Khramtsov 66591b1c0d Improve URLs validation 2018-06-29 11:06:24 +03:00
Evgeniy Khramtsov b094ce8ea5 HTTP Upload: increase gen_server call timeout 2018-06-29 10:32:53 +03:00
Evgeniy Khramtsov 9c82c2f6d0 HTTP Upload: put more info in log messages 2018-06-29 09:58:33 +03:00
Evgeniy Khramtsov 0a40ab93c8 Don't crash when encoding {xmlcdata, _}
Fixes #2493
2018-06-28 15:04:46 +03:00
Paweł Chmielowski c526b0e8ff Update mix.lock 2018-06-28 12:11:44 +02:00
Paweł Chmielowski 35136f47ed Bump version in mix.exs 2018-06-28 10:57:09 +02:00
Paweł Chmielowski 8f2233eff7 Update deps 2018-06-28 10:56:59 +02:00
Evgeniy Khramtsov 8879d1d533 Avoid code duplication when checking presence subscription 2018-06-28 10:37:20 +03:00
Evgeniy Khramtsov 71ae7e9fd9 Work-around against public_key incompatibility introduced in OTP21
The commit introduced the incompatility is
https://github.com/erlang/otp/commit/304dd8f81e28ed04cde9f6f7ac1f79870da1c2cd

Thanks to Stu Tomlinson for spotting the issue.

Fixes #2488
2018-06-27 19:40:03 +03:00
Evgeniy Khramtsov 644873dae9 Don't check packets sent to self 2018-06-27 15:02:03 +03:00
Evgeniy Khramtsov 9a11db91f9 Use lists:foldl/3 2018-06-27 13:36:58 +03:00
Evgeniy Khramtsov af8c6d2428 Generate HTTP Upload form using xdata codec 2018-06-27 13:29:38 +03:00
Evgeniy Khramtsov 87357c700f Do not ignore a certificate containing no domain names
Log a warning instead and assign it to an "empty" domain
2018-06-27 11:27:39 +03:00
Evgeniy Khramtsov 7881c5670c Don't replace valid certificates with invalid ones
When building the certificates chains, if several certificates
are found matching the same domain their validity is checked:

* the invalid one is ignored and the valid one is picked
* if both are valid or both are invalid, then the one with
  sooner expiration is ignored.

Fixes #2454
2018-06-27 10:55:37 +03:00
Evgeniy Khramtsov 881e02632b Improve error formatting in mod_http_upload 2018-06-26 19:32:29 +03:00
Evgeniy Khramtsov 47d117c1bf Support SASL PLAIN by xmpp_stream_out
Also, SASL mechanisms chaining is now supported:
if several mechanisms are supported and authentication
fails, next mechanism in the list is picked, until the
list is exhausted. In the case of a failure, the latest
SASL failure reason is returned within handle_auth_failure/3
callback.
2018-06-25 19:16:33 +03:00
Evgeniy Khramtsov cf6f540d53 Don't pass sockmod to xmpp_stream_out 2018-06-25 15:28:02 +03:00
Evgeniy Khramtsov 557e6ecdd0 Introduce resolve/2 and connect_options/3 callbacks for xmpp_stream_out 2018-06-25 15:19:49 +03:00
Evgeniy Khramtsov 5dd3f4c22b Allow gen_server process registration 2018-06-25 14:55:33 +03:00
Evgeniy Khramtsov e7c3b57b8b Allow reconnecting from disconnected state 2018-06-25 14:52:33 +03:00
Evgeniy Khramtsov c907915695 Intercept EXIT signal 2018-06-25 14:46:31 +03:00
Evgeniy Khramtsov 911ed4a7ca Add Resource Binding support to xmpp_stream_out 2018-06-25 13:50:35 +03:00
Evgeniy Khramtsov 499ae96254 Don't use 'unsupported-version' inside SM <failed/> element
This error condition is defined within stream errors, however,
XEP-0198 says:

> This element SHOULD contain an error condition, which MUST
> be one of the **stanza** error conditions defined in RFC 6120.
2018-06-25 09:56:44 +03:00
Evgeniy Khramtsov ac31c85866 Use error formatting functions from xmpp library 2018-06-25 09:45:45 +03:00
Evgeniy Khramtsov c4c91cc956 Generate SASL failures on unencrypted connections only for s2s 2018-06-23 20:31:01 +03:00
Evgeniy Khramtsov d809aafba0 Fix Erlang limits in ejabberdctl.cfg.example to reflect current situation 2018-06-23 20:01:21 +03:00
Evgeniy Khramtsov 6ffb120fce Fix typo 2018-06-21 15:14:19 +03:00
Evgeniy Khramtsov 55f8aa1b22 Add new options for OOM watchdog
* oom_watermark: 1..100
  Start OOM watchdog only when system memory usage exceeds
  this value in percents. When the usage drops below the value,
  OOM watchdog is stopped. The default is 80 (percents).
  Note that once OOM watchdog is started, it performs full garbage
  collection periodically: this can be seen as spikes in CPU
  utilization and drops in RAM usage. If your system is permanently
  above the watermark, it may cause significant CPU overhead.

* oom_queue: positive integer
  Only trigger OOM killer when total amount of messages in all queues
  of all Erlang processes is above this value. The default is 10000.
  Note that this value only takes effect when `oom_killer` is set
  to `true` (this is the default). Otherwise, only a warning will
  be logged.
2018-06-21 14:35:19 +03:00
Paweł Chmielowski 274e9fe7b5 Guard against pres_last=undefined in mod_offline 2018-06-20 12:16:10 +02:00
Evgeniy Khramtsov f465742f2c Remove lowercased duplicates from ejabberd.pot 2018-06-20 13:02:06 +03:00
Evgeniy Khramtsov 9e83c45b3c Restore forgotten translations from previous commit 2018-06-20 12:50:36 +03:00
Evgeniy Khramtsov 446e6e6f3b Update ejabberd.pot 2018-06-20 12:32:10 +03:00
Evgeniy Khramtsov 3a5d2dbed8 Move mod_irc to ejabberd-contrib 2018-06-20 12:27:44 +03:00
Holger Weiss aea6166efe Omit summary form for push tests 2018-06-20 00:15:56 +02:00
Holger Weiss 23cc0f8c3c mod_push: Include a static body text by default
Set the 'include_body' option to a static text by default.  Some app
servers check for the presence of a 'last-message-body' field to
distinguish between notifications generated for actual chat messages and
notifications triggered by other types of traffic.
2018-06-19 23:12:27 +02:00
Holger Weiss 81f4dd0e6a mod_push_keepalive: Increase default timeout
Set the default session timeout to three days.  This way, sessions will
survive a weekend without traffic, for example.
2018-06-19 22:26:08 +02:00
Paweł Chmielowski dee3081df1 Fix reset_stream in websocket using pre-rfc protocol 2018-06-19 17:51:09 +02:00
Evgeniy Khramtsov 6acac7c93f Render roomname, allowinvites and allowpm in room disco#info 2018-06-19 14:02:45 +03:00
Holger Weiss c2f664f941 mod_push_mnesia: Simplify record matching
Omit record fields that aren't used for matching.
2018-06-18 23:12:27 +02:00
Holger Weiss 75127a0deb mod_push_mnesia: Fix lookup of all host sessions 2018-06-18 23:05:08 +02:00
Holger Weiss bb76da03ea mod_mam: Don't replace existing stanza ID
Preserve the original stanza ID for resent messages.  This avoids
storing duplicates in the MAM archive.
2018-06-16 00:43:22 +02:00
Paweł Chmielowski 3099702039 New shaper implementation 2018-06-15 11:56:46 +02:00
Badlop 3ec623f329 Make connected_users_info and user_sessions_info DB-agnostic (#2448)
The result returned by connected_users_info command has changed,
and is now similar to the result of user_sessions_info.

Notice that num_active_users and process_rosteritems still require Mnesia.
2018-06-15 11:28:57 +02:00
Evgeniy Khramtsov 6c323b729b Improve type spec 2018-06-14 19:51:50 +03:00
Evgeniy Khramtsov 17b05ff4b7 Get rid of all calls to jlib.erl module 2018-06-14 19:49:27 +03:00
Evgeniy Khramtsov 7bd5c7fe59 Update mod_muc_room.hrl 2018-06-14 19:19:09 +03:00
Evgeniy Khramtsov 7b04a625be Get rid of jlib.hrl/jlib.erl 2018-06-14 19:11:43 +03:00
Evgeniy Khramtsov 49b08949b1 Do not check for deprecated types
Since we support only Erlang >= OTP-17.5, the check for old-style
dict/queue/etc types is no longer needed
2018-06-14 18:58:35 +03:00
Evgeniy Khramtsov 141be53c21 Get rid of ejabberd.hrl reference from the test suite 2018-06-14 14:24:15 +03:00
Evgeniy Khramtsov fd8e07af47 Get rid of ejabberd.hrl header
The header consisted of too many unrelated stuff and macros misuse.
Some stuff is moved into scram.hrl and type_compat.hrl.
All macros have been replaced with the corresponding function calls.

TODO: probably type_compat.hrl is not even needed anymore since
we support only Erlang >= OTP 17.5
2018-06-14 14:00:47 +03:00
Evgeniy Khramtsov c3c75affa9 Log modules startup 2018-06-14 10:18:10 +03:00
Holger Weiss 85f09b365f mod_push: Omit summary for outgoing messages
Don't include a urn:xmpp:push:summary form in push notifications that
are triggered by outgoing messages.  App servers might use the form
fields to generate user-visible notifications directly (as opposed to
just waking the client app).  This is usually not desired for outgoing
messages.
2018-06-13 21:43:40 +02:00
Evgeniy Khramtsov 645f11d79d Advertise disco#info and disco#items features in mod_disco
Fixes #2470
2018-06-13 14:55:06 +03:00
Holger Weiss 0a20e45690 mod_push: Further improve handling of carbons
Also check for carbon-copied messages (with a body) in the queue of
unacknowledged stanzas.
2018-06-13 00:25:14 +02:00
Holger Weiss 0a9f522222 mod_push: Also include sender/body for carbons
If the 'include_sender' and/or 'include_body' options are specified,
also include a urn:xmpp:push:summary form in push notifications that are
generated for carbon-copied messages (with a body).
2018-06-12 22:47:23 +02:00
Christophe Romain 4f293751f0 Update mix deps 2018-06-11 14:21:35 +02:00
Evgeniy Khramtsov 6f481e3ceb Avoid lager crash on external authentication failure
Fixes #2463
2018-06-08 09:51:26 +03:00
Holger Weiss 00534d4566 Increase start-up/stop timeout in systemd unit
On slow systems, it can take quite a while for "ejabberdctl started"
and/or "ejabberdctl stopped" to return.
2018-06-07 17:40:05 +02:00
Paweł Chmielowski 40185b6bd3 Add ability to modify version string 2018-06-07 15:38:33 +02:00
Evgeny Khramtsov 1de407c420 Merge pull request #2460 from imShara/patch-1
OMEMO enable HOWTO added
2018-06-06 20:05:42 +03:00
imShara 815b95c623 OMEMO enable HOWTO added
Depend on #2425
2018-06-06 20:03:42 +03:00
Holger Weiss 8e1a13b259 upload_tests: Make size error check stricter 2018-06-04 23:29:24 +02:00
Holger Weiss a4049d9418 Omit 'xmlns' field from 'feature_csi' record
The 'xmpp' library has been updated to omit the 'xmlns' field from the
'feature_csi' record.
2018-06-04 23:05:11 +02:00
Holger Weiss ba30ac8ce8 Return detailed error if HTTP upload is too large
If the file size specified in an HTTP upload slot request exceeds the
the configured maximum size, include the limit with the stanza error.
2018-06-04 22:18:56 +02:00
Evgeniy Khramtsov 43c3134f55 Also format gracefully errors returned during module reload 2018-06-03 18:53:30 +03:00
Paweł Chmielowski 67fc2015de Fix problem in commit 548ef7b835 2018-06-01 18:36:39 +02:00
Paweł Chmielowski 548ef7b835 Don't crash in bosh when we receive request with RID < prev_rid 2018-06-01 16:12:22 +02:00
Evgeniy Khramtsov 4337300fce Always display room's xdata in disco#info 2018-06-01 09:07:16 +03:00
Evgeniy Khramtsov cab8005bf3 Display muc#roomconfig_changesubject in room's disco#info
Fixes #2449
2018-06-01 08:56:56 +03:00
Evgeniy Khramtsov 4fc8d1c4a4 Send trailer and close socket explicitly on stream end 2018-06-01 07:58:03 +03:00
Evgeniy Khramtsov 1261502f6a Improve indentation 2018-05-30 22:53:34 +03:00
Holger Weiss dacba3ec00 Merge remote-tracking branch 'processone/pr/2446'
* processone/pr/2446:
  Fix authentication for usernames containing uppercase characters
2018-05-30 20:53:11 +02:00
Stu Tomlinson 4f8af723c6 Fix authentication for usernames containing uppercase characters
Applies to authentication methods that compare User (normalized)
and AuthzId (was not being normalized). These are external, ldap & pam.

Fixes #2280
2018-05-30 18:43:26 +01:00
Evgeniy Khramtsov 5e446d50a8 Get rid of direct calls to 'session' Mnesia table
Fixes #2439
2018-05-30 19:21:56 +03:00
Evgeniy Khramtsov 22d76659c0 Bump xmpp version in order to support language tags validation 2018-05-30 09:54:26 +03:00
Evgeniy Khramtsov 0f9db50c8d Support for roomconfig_lang/roominfo_lang
Now room owners are able to set a preferred language
for the discussions in the room, so other users can
discover rooms based on the language they wish to talk.

TODO: the language format should conform to RFC 5646.
      This check should be implemented in 'xmpp' library.

Fixes #2436
2018-05-30 08:11:58 +03:00
Evgeniy Khramtsov 52b8226671 Use 'list-multi' type for XEP-0157 xdata fields
Thanks to Jonas Wielicki for spotting this
2018-05-29 19:37:24 +03:00
Evgeny Khramtsov 3b9e6eaa95 Merge pull request #2438 from licaon-kter/patch-3
Add default_db in the example config
2018-05-28 16:22:30 +03:00
Licaon_Kter 2c18f89d5b Add default_db in the example config
I only found it in the docs after setting up per module db_
2018-05-28 13:19:59 +00:00
Evgeniy Khramtsov 0381ce1e75 Better report errors of module startup 2018-05-28 09:19:49 +03:00
Evgeniy Khramtsov fc77051b68 Don't call Mod:function() in xmpp_stream callbacks
If a callback function is not defined by the `Mod` then
a call to code_server process is performed. Under heavy load
this may cause code_server to get overloaded. We now avoid this.
2018-05-26 09:06:24 +03:00
Holger Weiss bfe2545c01 mod_muc_sql: Fix export to SQL
The "host" column is supposed to hold the MUC host name.
2018-05-24 01:28:29 +02:00
Holger Weiss c6a9c30f1c mod_push_mnesia: Apply cosmetic changes
Improve the readability of the 'max_user_sessions' check.
2018-05-23 21:40:54 +02:00
Holger Weiss 508f3ef88d mod_push_sql: Check 'max_user_sessions' limit
Remove the oldest push session(s) of a user if the number of enabled
sessions exceeds the 'max_user_sessions' limit.
2018-05-23 20:02:52 +02:00
Paweł Chmielowski 97f7d99007 Handle "Expect: 100-continue" request header in ejabberd_http 2018-05-23 14:52:47 +02:00
Evgeny Khramtsov 2bbfc0b79e Merge pull request #2431 from yokomizor/fix-xmpp-commit
Missing #block_item{} record building with mix
2018-05-22 17:45:53 +03:00
Evgeny Khramtsov 10a5a5eb01 Merge pull request #2430 from yokomizor/ext_mod-export-add_sources_1
Export ext_mod:add_sources/1
2018-05-22 17:39:27 +03:00
Rogério da Silva Yokomizo 2e529f5826 Missing #block_item{} record building with mix
Ref: #638f2d2
2018-05-22 16:37:39 +02:00
Rogério da Silva Yokomizo 4a4cc32650 Export ext_mod:add_sources/1 2018-05-22 16:16:13 +02:00
Evgeniy Khramtsov d2114be6f3 Correctly calculate remaining bytes on file upload 2018-05-19 18:29:33 +03:00
Christophe Romain db51d522e8 Add support for REST API custom headers
ext_api_headers can be defined as a single string. Headers are separated
by comma. Definition MUST NOT contain spaces. Example
"X-MyHead:test,X-Token:082748"
2018-05-17 14:47:21 +02:00
Evgeniy Khramtsov 82c42051c3 Correctly resolve upload.localhost for the test suite 2018-05-17 13:24:23 +03:00
Evgeniy Khramtsov e4c106e0dd Add tests for mod_http_upload 2018-05-17 12:02:00 +03:00
Evgeniy Khramtsov b64e1d95d2 Fix typo file:read() -> file:open() 2018-05-17 12:00:06 +03:00
Paweł Chmielowski c41bab9ca0 Clean state between requests in ejabberd_http 2018-05-15 14:25:19 +02:00
Evgeniy Khramtsov 063737e4f5 Optimize HTTP requests memory usage
Due to historical reasons, ejabberd loads the whole file/data
into the memory when serving an HTTP request. This is now improved:

1) For GET requests ejabberd uses sendfile(2) if the underlying
   connection is HTTP and falls back to read/write loop with 64kb
   buffer for HTTPS connections. This type of requests are handled
   by mod_http_fileserver, mod_http_upload, ejabberd_captcha, etc
2) POST requests are now limited to 20Mb and are fully downloaded
   into the memory for further processing (by ejabberd_web_admin,
   mod_bosh, etc)
3) PUT requests (e.g. for mod_http_upload) are handled by read/write
   loop with 64kb buffer
2018-05-14 19:39:58 +03:00
Badlop cb3bb710bd Handle muc_register_nick success correctly (#2415) 2018-05-14 12:24:56 +02:00
Evgeniy Khramtsov c30715e67b Disable thumbnails creation by default 2018-05-11 18:56:31 +03:00
Evgeniy Khramtsov 27594db029 Support IPv6 connections for PostgreSQL, MySQL and LDAP
Fixes #2411
2018-05-11 16:43:49 +03:00
Paweł Chmielowski 6ac8f6eaee Relax check for valid command name in access_persmissions 2018-05-11 12:24:00 +02:00
Paweł Chmielowski 338d27b45b Use never version of moka 2018-05-09 10:58:00 +02:00
Evgeniy Khramtsov 35a076c251 Stop ejabberd initialization on invalid/unknown options
Since now, ejabberd doesn't ignore unknown options and doesn't
allow to have options with malformed values. The rationale for
this is to avoid unexpected behaviour during runtime, i.e. to
conform to "fail early" approach. Note that it's safe to reload
a configuration with potentialy invalid and/or unknown options:
this will not halt ejabberd, but will only prevent the configuration
from loading.

***NOTE FOR PACKAGE BUILDERS***
This new behaviour should be documented in the upgrade notes.
2018-05-09 11:44:24 +03:00
Evgeniy Khramtsov 680384c342 Reduce IQ handler code copying 2018-05-09 10:30:00 +03:00
Evgeniy Khramtsov 11ff2a1ccf Fix a typo 2018-05-09 09:44:26 +03:00
Evgeniy Khramtsov 3ac1675919 Option watchdog_admins has no effect anymore 2018-05-08 23:47:37 +03:00
Badlop de85c1718e Bypass account creation error when password is empty, caused by extauth 2018-05-08 18:19:07 +02:00
Evgeniy Khramtsov 46f47db512 Get rid of unused rebar instructions 2018-05-08 16:17:07 +03:00
Paweł Chmielowski 6811b92a80 Don't use warnings_as_errors in samerlib 2018-05-08 11:37:20 +02:00
Evgeniy Khramtsov 8766854870 Get rid of ?FUNCTION_NAME macro (it's OTP19+ feature) 2018-05-08 12:06:58 +03:00
Evgeniy Khramtsov 61ae0ff02c Improve logging of external authentication failures 2018-05-08 09:36:34 +03:00
Evgeniy Khramtsov 5522403e8e Don't stop on out-of-date requests 2018-05-07 22:43:01 +03:00
Evgeniy Khramtsov b23d5754e8 Improve robustness of external authentication backends
Now all external ports are attached to supervising processes
and requests are balanced in round-robin manner until the pool
is exhausted.

The commit also deprecates `extauth_instances` option and introduces
`extauth_pool_size` option instead, with the default value of a number
of logical processors (i.e. CPU cores).

Fixes #2403
2018-05-07 19:27:18 +03:00
Paweł Chmielowski b1a03cc346 Make trusted_proxied ejabberd_http option accept ip masks 2018-05-04 09:53:07 +02:00
Paweł Chmielowski ca94cbfd31 Teach acl ip matching about ipv4 mapped ipv6 addresses 2018-05-04 09:52:06 +02:00
Holger Weiss 410db89167 ejabberd_auth: Don't use cache if it's disabled
Don't let the check whether a user exists use the cache if caching was
disabled in the configuration.
2018-05-03 00:31:33 +02:00
Holger Weiss 638f2d2e67 mod_blocking: Use #block_item{} record 2018-05-02 22:17:32 +02:00
Evgeniy Khramtsov 56ee6f0518 Ignore any policy when signing a certificate for the test suite 2018-05-02 10:52:46 +03:00
Evgeniy Khramtsov 4e83fc41d4 Also generate CA certificates for the test suite 2018-05-02 10:28:22 +03:00
Evgeniy Khramtsov 4ea481d1dd Add validator for 'accept_interval' listening option 2018-04-30 11:52:00 +03:00
246 changed files with 6526 additions and 14674 deletions
+18 -12
View File
@@ -1,15 +1,21 @@
> What version of ejabberd are you using?
Environment
-----------
- ejabberd version: 18.06
- Erlang version: `erl +V`
- OS: Linux (Debian)
- Installed from: source | distro package | official deb/rpm | official binary installer | other
Configuration (only if needed): grep -Ev '^$|^\s*#' ejabberd.yml
---------------------------------------------------------------------------
```yaml
loglevel: 4
...
```
Errors from error.log/crash.log
-------------------------------
No errors
> What operating system (version) are you using?
> How did you install ejabberd (source, package, distribution)?
> What did not work as expected? Are there error messages in the log? What
> was the unexpected behavior? What was the expected result?
Bug description
---------------
Nothing works, plz halp :(
+5
View File
@@ -58,6 +58,9 @@ JSDIR = $(PRIVDIR)/js
# /usr/lib/ejabberd/priv/sql
SQLDIR = $(PRIVDIR)/sql
# /usr/lib/ejabberd/priv/lua
LUADIR = $(PRIVDIR)/lua
# /var/lib/ejabberd/
SPOOLDIR = $(DESTDIR)@localstatedir@/lib/ejabberd
@@ -283,6 +286,8 @@ uninstall-binary:
rm -fr $(JSDIR)
rm -f $(SQLDIR)/*.sql
rm -fr $(SQLDIR)
rm -fr $(LUADIR)/*.lua
rm -fr $(LUADIR)
rm -fr $(PRIVDIR)
rm -fr $(EJABBERDDIR)
-3
View File
@@ -93,7 +93,6 @@ Moreover, ejabberd comes with a wide range of other state-of-the-art features:
- Users Directory based on users vCards.
- Publish-Subscribe component with support for Personal Eventing.
- Support for web clients: HTTP Polling and HTTP Binding (BOSH).
- IRC transport.
- Component support: interface with networks such as AIM, ICQ and MSN.
@@ -112,8 +111,6 @@ To compile ejabberd you need:
- OpenSSL 1.0.0 or higher, for STARTTLS, SASL and SSL encryption.
- Zlib 1.2.3 or higher, for Stream Compression support (XEP-0138). Optional.
- PAM library. Optional. For Pluggable Authentication Modules (PAM).
- GNU Iconv 1.8 or higher, for the IRC Transport (mod_irc). Optional. Not
needed on systems with GNU Libc.
- ImageMagick's Convert program. Optional. For CAPTCHA challenges.
If your system splits packages in libraries and development headers, you must
-14
View File
@@ -1,14 +0,0 @@
XmppAddr { iso(1) identified-organization(3)
dod(6) internet(1) security(5) mechanisms(5) pkix(7)
id-on(8) id-on-xmppAddr(5) }
DEFINITIONS EXPLICIT TAGS ::=
BEGIN
id-on-xmppAddr OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
dod(6) internet(1) security(5) mechanisms(5) pkix(7)
id-on(8) 5 }
XmppAddr ::= UTF8String
END
-3
View File
@@ -94,9 +94,6 @@ defmodule Ejabberd.ConfigFile do
module :mod_disco do
end
module :mod_irc do
end
module :mod_http_bind do
end
-1
View File
@@ -565,7 +565,6 @@ modules:
mod_configure: {} # requires mod_adhoc
mod_disco: {}
## mod_echo: {}
mod_irc: {}
mod_http_bind: {}
## mod_http_fileserver:
## docroot: "/var/www"
+2 -4
View File
@@ -197,12 +197,12 @@ AC_ARG_ENABLE(elixir,
esac],[if test "x$elixir" = "x"; then elixir=false; fi])
AC_ARG_ENABLE(iconv,
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: yes)])],
[AC_HELP_STRING([--enable-iconv], [enable iconv support (default: no)])],
[case "${enableval}" in
yes) iconv=true ;;
no) iconv=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-iconv) ;;
esac],[if test "x$iconv" = "x"; then iconv=true; fi])
esac],[if test "x$iconv" = "x"; then iconv=false; fi])
AC_ARG_ENABLE(debug,
[AC_HELP_STRING([--enable-debug], [enable debug information (default: yes)])],
@@ -275,8 +275,6 @@ if test "$ENABLEGROUP" != ""; then
AC_SUBST([INSTALLGROUP], [$ENABLEGROUP])
fi
ERLANG_DEPRECATED_TYPES_CHECK
if test "$sqlite" = "true"; then
AX_LIB_SQLITE3([3.6.19])
if test "x$SQLITE3_VERSION" = "x"; then
+1
View File
@@ -13,6 +13,7 @@ ExecStart=/bin/sh -c '@ctlscriptpath@/ejabberdctl start && @ctlscriptpath@/ejabb
ExecStop=/bin/sh -c '@ctlscriptpath@/ejabberdctl stop && @ctlscriptpath@/ejabberdctl stopped'
ExecReload=@ctlscriptpath@/ejabberdctl reload_config
PrivateDevices=true
TimeoutSec=300
[Install]
WantedBy=multi-user.target
+76 -731
View File
@@ -1,15 +1,16 @@
###
###' ejabberd configuration file
### ejabberd configuration file
###
### The parameters used in this configuration file are explained at
###
### https://docs.ejabberd.im/admin/configuration
###
### The parameters used in this configuration file are explained in more detail
### in the ejabberd Installation and Operation Guide.
### Please consult the Guide in case of doubts, it is included with
### your copy of ejabberd, and is also available online at
### http://www.process-one.net/en/ejabberd/docs/
### The configuration file is written in YAML.
### *******************************************************
### ******* !!! WARNING !!! *******
### ******* YAML IS INDENTATION SENSITIVE *******
### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY *******
### *******************************************************
### Refer to http://en.wikipedia.org/wiki/YAML for the brief description.
### However, ejabberd treats different literals as different types:
###
@@ -23,590 +24,77 @@
### Example of folded string:
### > Art thou not Romeo,
### and a Montague?
###
###. =======
###' LOGGING
##
## loglevel: Verbosity of log files generated by ejabberd.
## 0: No ejabberd log at all (not recommended)
## 1: Critical
## 2: Error
## 3: Warning
## 4: Info
## 5: Debug
##
loglevel: 4
##
## rotation: Describe how to rotate logs. Either size and/or date can trigger
## log rotation. Setting count to N keeps N rotated logs. Setting count to 0
## does not disable rotation, it instead rotates the file and keeps no previous
## versions around. Setting size to X rotate log when it reaches X bytes.
## To disable rotation set the size to 0 and the date to ""
## Date syntax is taken from the syntax newsyslog uses in newsyslog.conf.
## Some examples:
## $D0 rotate every night at midnight
## $D23 rotate every day at 23:00 hr
## $W0D23 rotate every week on Sunday at 23:00 hr
## $W5D16 rotate every week on Friday at 16:00 hr
## $M1D0 rotate on the first day of every month at midnight
## $M5D6 rotate on every 5th day of the month at 6:00 hr
##
log_rotate_size: 10485760
log_rotate_date: ""
log_rotate_count: 1
##
## overload protection: If you want to limit the number of messages per second
## allowed from error_logger, which is a good idea if you want to avoid a flood
## of messages when system is overloaded, you can set a limit.
## 100 is ejabberd's default.
log_rate_limit: 100
##
## watchdog_admins: Only useful for developers: if an ejabberd process
## consumes a lot of memory, send live notifications to these XMPP
## accounts.
##
## watchdog_admins:
## - "bob@example.com"
###. ===============
###' NODE PARAMETERS
##
## net_ticktime: Specifies net_kernel tick time in seconds. This options must have
## identical value on all nodes, and in most cases shouldn't be changed at all from
## default value.
##
## net_ticktime: 60
###. ================
###' SERVED HOSTNAMES
##
## hosts: Domains served by ejabberd.
## You can define one or several, for example:
## hosts:
## - "example.net"
## - "example.com"
## - "example.org"
##
hosts:
- "localhost"
##
## route_subdomains: Delegate subdomains to other XMPP servers.
## For example, if this ejabberd serves example.org and you want
## to allow communication with an XMPP server called im.example.org.
##
## route_subdomains: s2s
loglevel: 4
log_rotate_size: 10485760
log_rotate_date: ""
log_rotate_count: 1
log_rate_limit: 100
###. ============
###' Certificates
certfiles:
- "/etc/letsencrypt/live/*/*.pem"
## List all available PEM files containing certificates for your domains,
## chains of certificates or certificate keys. Full chains will be built
## automatically by ejabberd.
##
## certfiles:
## - "/etc/letsencrypt/live/example.org/*.pem"
## - "/etc/letsencrypt/live/example.com/*.pem"
##
## If your system provides only a single CA file (CentOS/FreeBSD):
## ca_file: "/etc/ssl/certs/ca-bundle.pem"
###. =================
###' TLS configuration
## Note that the following configuration is the default
## configuration of the TLS driver, so you don't need to
## uncomment it.
##
## define_macro:
## 'TLS_CIPHERS': "HIGH:!aNULL:!eNULL:!3DES:@STRENGTH"
## 'TLS_OPTIONS':
## - "no_sslv3"
## - "cipher_server_preference"
## - "no_compression"
## 'DH_FILE': "/path/to/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 2048
##
## c2s_dhfile: 'DH_FILE'
## s2s_dhfile: 'DH_FILE'
## c2s_ciphers: 'TLS_CIPHERS'
## s2s_ciphers: 'TLS_CIPHERS'
## c2s_protocol_options: 'TLS_OPTIONS'
## s2s_protocol_options: 'TLS_OPTIONS'
###. ===============
###' LISTENING PORTS
##
## listen: The ports ejabberd will listen on, which service each is handled
## by and what options to start it with.
##
listen:
-
port: 5222
ip: "::"
module: ejabberd_c2s
##
## If TLS is compiled in and you installed a SSL
## certificate, uncomment this line:
##
## starttls: true
##
## To enforce TLS encryption for client connections,
## use this instead of the "starttls" option:
##
## starttls_required: true
##
## Stream compression
##
## zlib: true
##
max_stanza_size: 65536
max_stanza_size: 262144
shaper: c2s_shaper
access: c2s
##
## Direct-TLS for C2S (XEP-0368). A good practice is to forward
## traffic from port 443 to this port, possibly multiplexing it
## with HTTP using e.g. sslh [https://wiki.xmpp.org/web/Tech_pages/XEP-0368],
## so modern clients can bypass restrictive firewalls (in airports, hotels, etc.).
##
## -
## port: 5223
## ip: "::"
## module: ejabberd_c2s
## tls: true
## max_stanza_size: 65536
## shaper: c2s_shaper
## access: c2s
starttls_required: true
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
max_stanza_size: 524288
-
port: 5280
port: 5443
ip: "::"
module: ejabberd_http
request_handlers:
"/ws": ejabberd_http_ws
"/bosh": mod_bosh
"/api": mod_http_api
## "/pub/archive": mod_http_fileserver
"/bosh": mod_bosh
"/upload": mod_http_upload
"/ws": ejabberd_http_ws
web_admin: true
## register: true
captcha: true
tls: true
##
## ejabberd_service: Interact with external components (transports, ...)
##
## -
## port: 8888
## ip: "::"
## module: ejabberd_service
## access: all
## shaper_rule: fast
## ip: "127.0.0.1"
## privilege_access:
## roster: "both"
## message: "outgoing"
## presence: "roster"
## delegations:
## "urn:xmpp:mam:1":
## filtering: ["node"]
## "http://jabber.org/protocol/pubsub":
## filtering: []
## hosts:
## "icq.example.org":
## password: "secret"
## "sms.example.org":
## password: "secret"
s2s_use_starttls: optional
##
## ejabberd_stun: Handles STUN Binding requests
##
## -
## port: 3478
## transport: udp
## module: ejabberd_stun
##
## To handle XML-RPC requests that provide admin credentials:
##
## -
## port: 4560
## ip: "::"
## module: ejabberd_xmlrpc
## maxsessions: 10
## timeout: 5000
## access_commands:
## admin:
## commands: all
## options: []
##
## To enable secure http upload
##
## -
## port: 5444
## ip: "::"
## module: ejabberd_http
## request_handlers:
## "": mod_http_upload
## tls: true
## protocol_options: 'TLS_OPTIONS'
## dhfile: 'DH_FILE'
## ciphers: 'TLS_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 for S2S connections.
## Allowed values are: false, optional or required
## You must specify 'certfiles' option
##
## s2s_use_starttls: optional
##
## S2S whitelist or blacklist
##
## Default s2s policy for undefined hosts.
##
## s2s_access: s2s
##
## Outgoing S2S options
##
## Preferred address families (which to try first) and connect timeout
## in seconds.
##
## outgoing_s2s_families:
## - ipv4
## - ipv6
## outgoing_s2s_timeout: 190
###. ==============
###' AUTHENTICATION
##
## auth_method: Method used to authenticate the users.
## The default method is the internal.
## If you want to use a different method,
## comment this line and enable the correct ones.
##
auth_method: internal
##
## Store the plain passwords or hashed for SCRAM:
## auth_password_format: plain
## auth_password_format: scram
##
## Define the FQDN if ejabberd doesn't detect it:
## fqdn: "server3.example.com"
##
## Authentication using external script
## Make sure the script is executable by ejabberd.
##
## auth_method: external
## extauth_program: "/path/to/authentication/script"
##
## Authentication using SQL
## Remember to setup a database in the next section.
##
## auth_method: sql
##
## Authentication using PAM
##
## auth_method: pam
## pam_service: "pamservicename"
##
## Authentication using LDAP
##
## auth_method: ldap
##
## List of LDAP servers:
## ldap_servers:
## - "localhost"
##
## Encryption of connection to LDAP servers:
## ldap_encrypt: none
## ldap_encrypt: tls
##
## Port to connect to on LDAP servers:
## ldap_port: 389
## ldap_port: 636
##
## LDAP manager:
## ldap_rootdn: "dc=example,dc=com"
##
## Password of LDAP manager:
## ldap_password: "******"
##
## Search base of LDAP directory:
## ldap_base: "dc=example,dc=com"
##
## LDAP attribute that holds user ID:
## ldap_uids:
## - "mail": "%u@mail.example.org"
##
## LDAP filter:
## ldap_filter: "(objectClass=shadowAccount)"
##
## Anonymous login support:
## auth_method: anonymous
## anonymous_protocol: sasl_anon | login_anon | both
## allow_multiple_connections: true | false
##
## host_config:
## "public.example.org":
## auth_method: anonymous
## allow_multiple_connections: false
## anonymous_protocol: sasl_anon
##
## To use both anonymous and internal authentication:
##
## host_config:
## "public.example.org":
## auth_method:
## - internal
## - anonymous
###. ==============
###' DATABASE SETUP
## ejabberd by default uses the internal Mnesia database,
## so you do not necessarily need this section.
## This section provides configuration examples in case
## you want to use other database backends.
## Please consult the ejabberd Guide for details on database creation.
##
## MySQL server:
##
## sql_type: mysql
## sql_server: "server"
## sql_database: "database"
## sql_username: "username"
## sql_password: "password"
##
## If you want to specify the port:
## sql_port: 1234
##
## PostgreSQL server:
##
## sql_type: pgsql
## sql_server: "server"
## sql_database: "database"
## sql_username: "username"
## sql_password: "password"
##
## If you want to specify the port:
## sql_port: 1234
##
## If you use PostgreSQL, have a large database, and need a
## faster but inexact replacement for "select count(*) from users"
##
## pgsql_users_number_estimate: true
##
## SQLite:
##
## sql_type: sqlite
## sql_database: "/path/to/database.db"
##
## ODBC compatible or MSSQL server:
##
## sql_type: odbc
## sql_server: "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"
##
## Number of connections to open to the database for each virtual host
##
## sql_pool_size: 10
##
## Interval to make a dummy SQL request to keep the connections to the
## database alive. Specify in seconds: for example 28800 means 8 hours
##
## sql_keepalive_interval: undefined
##
## Use the new SQL schema
##
## new_sql_schema: true
###. ===============
###' TRAFFIC SHAPERS
shaper:
##
## The "normal" shaper limits traffic speed to 1000 B/s
##
normal: 1000
##
## The "fast" shaper limits traffic speed to 50000 B/s
##
fast: 50000
##
## This option specifies the maximum number of elements in the queue
## of the FSM. Refer to the documentation for details.
##
max_fsm_queue: 10000
###. ====================
###' ACCESS CONTROL LISTS
acl:
##
## The 'admin' ACL grants administrative privileges to XMPP accounts.
## You can put here as many accounts as you want.
##
## admin:
## user:
## - "aleksey@localhost"
## - "ermine@example.org"
##
## Blocked users
##
## blocked:
## user:
## - "baduser@example.org"
## - "test"
## Local users: don't modify this.
##
local:
user_regexp: ""
##
## More examples of ACLs
##
## jabberorg:
## server:
## - "jabber.org"
## aleksey:
## user:
## - "aleksey@jabber.ru"
## test:
## user_regexp: "^test"
## user_glob: "test*"
##
## Loopback network
##
loopback:
ip:
- "127.0.0.0/8"
- "::1/128"
- "::FFFF:127.0.0.1/128"
##
## Bad XMPP servers
##
## bad_servers:
## server:
## - "xmpp.zombie.org"
## - "xmpp.spam.com"
##
## Define specific ACLs in a virtual host.
##
## host_config:
## "localhost":
## acl:
## admin:
## user:
## - "bob-local@localhost"
###. ============
###' SHAPER RULES
shaper_rules:
## Maximum number of simultaneous sessions allowed for a single user:
max_user_sessions: 10
## Maximum number of offline messages that users can have:
max_user_offline_messages:
- 5000: admin
- 100
## For C2S connections, all users except admins use the "normal" shaper
c2s_shaper:
- none: admin
- normal
## All S2S connections use the "fast" shaper
s2s_shaper: fast
###. ============
###' ACCESS RULES
access_rules:
## This rule allows access only for local users:
local:
- allow: local
## Only non-blocked users can use c2s connections:
c2s:
- deny: blocked
- allow
## Only admins can send announcement messages:
announce:
- allow: admin
## Only admins can use the configuration interface:
configure:
- allow: admin
## Only accounts of the local ejabberd server can create rooms:
muc_create:
- allow: local
## Only accounts on the local ejabberd server can create Pubsub nodes:
pubsub_createnode:
- allow: local
## In-band registration allows registration of any possible username.
## To disable in-band registration, replace 'allow' with 'deny'.
register:
- allow
## Only allow to register from localhost
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"
## - deny:
## - 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:
@@ -636,154 +124,68 @@ api_permissions:
- "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
##
## Define specific Access Rules in a virtual host.
##
## host_config:
## "localhost":
## access:
## c2s:
## - allow: admin
## - deny
## register:
## - deny
shaper:
normal: 1000
fast: 50000
###. ================
###' DEFAULT LANGUAGE
shaper_rules:
max_user_sessions: 10
max_user_offline_messages:
- 5000: admin
- 100
c2s_shaper:
- none: admin
- normal
s2s_shaper: fast
##
## language: Default language used for server messages.
##
language: "en"
##
## Set a different default language in a virtual host.
##
## host_config:
## "localhost":
## language: "ru"
###. =======
###' CAPTCHA
##
## Full path to a script that generates the image.
##
## captcha_cmd: "/lib/ejabberd/priv/bin/captcha.sh"
##
## Host for the URL and port where ejabberd listens for CAPTCHA requests.
##
## captcha_host: "example.org:5280"
##
## Limit CAPTCHA calls per minute for JID/IP to avoid DoS.
##
## captcha_limit: 5
###. ====
###' ACME
##
## In order to use the acme certificate acquiring through "Let's Encrypt"
## an http listener has to be configured to listen to port 80 so that
## the authorization challenges posed by "Let's Encrypt" can be solved.
##
## A simple way of doing this would be to add the following in the listening
## section and to configure port forwarding from 80 to 5280 either via NAT
## (for ipv4 only) or using frontends such as haproxy/nginx/sslh/etc.
## -
## port: 5280
## ip: "::"
## module: ejabberd_http
acme:
## A contact mail that the ACME Certificate Authority can contact in case of
## an authorization issue, such as a server-initiated certificate revocation.
## It is not mandatory to provide an email address but it is highly suggested.
contact: "mailto:example-admin@example.com"
## The ACME Certificate Authority URL.
## This could either be:
## - https://acme-v01.api.letsencrypt.org - (Default) for the production CA
## - https://acme-staging.api.letsencrypt.org - for the staging CA
## - http://localhost:4000 - for a local version of the CA
ca_url: "https://acme-v01.api.letsencrypt.org"
###. =======
###' MODULES
##
## Modules enabled in all ejabberd virtual hosts.
##
modules:
mod_adhoc: {}
mod_admin_extra: {}
mod_announce: # recommends mod_adhoc
mod_announce:
access: announce
mod_blocking: {} # requires mod_privacy
mod_avatar: {}
mod_blocking: {}
mod_bosh: {}
mod_caps: {}
mod_carboncopy: {}
mod_client_state: {}
mod_configure: {} # requires mod_adhoc
## mod_delegation: {} # for xep0356
mod_configure: {}
mod_disco: {}
mod_echo: {}
mod_irc: {}
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 ejabberd to be compiled with libgd support
## mod_http_upload_quota:
## max_days: 30
mod_fail2ban: {}
mod_http_api: {}
mod_http_upload:
put_url: "https://@HOST@:5443/upload"
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_mam:
## Mnesia is limited to 2GB, better to use an SQL backend
## For small servers SQLite is a good fit and is very easy
## to configure. Uncomment this when you have SQL configured:
## db_type: sql
assume_mam_usage: true
default: always
mod_muc:
## host: "conference.@HOST@"
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
default_room_options:
mam: true
mod_muc_admin: {}
## mod_muc_log: {}
## mod_multicast: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
## mod_pres_counter:
## count: 5
## interval: 60
mod_privacy: {}
mod_private: {}
## mod_proxy65: {}
mod_pubsub:
access_createnode: pubsub_createnode
## reduces resource comsumption, but XEP incompliant
ignore_pep_from_offline: true
## XEP compliant, but increases resource comsumption
## ignore_pep_from_offline: false
last_item_cache: false
plugins:
- "flat"
- "hometree"
- "pep" # pep requires mod_caps
- "pep"
force_node_config:
## Avoid using OMEMO by default because it
## introduces a lot of hard-to-track problems
## Comment out the following lines to enable OMEMO support
## See https://github.com/processone/ejabberd/issues/2425
"eu.siacs.conversations.axolotl.*":
access_model: whitelist
## Avoid buggy clients to make their bookmarks public
@@ -791,82 +193,25 @@ modules:
access_model: whitelist
mod_push: {}
mod_push_keepalive: {}
## mod_register:
##
## Protect In-Band account registrations with CAPTCHA.
##
## captcha_protected: true
##
## Set the minimum informational entropy for passwords.
##
## password_strength: 32
##
## After successful registration, the user receives
## a message with this subject and body.
##
## welcome_message:
## subject: "Welcome!"
## body: |-
## Hi.
## Welcome to this XMPP server.
##
## When a user registers, send a notification to
## these XMPP accounts.
##
## registration_watchers:
## - "admin1@example.org"
##
## Only clients in the server machine can register accounts
##
## ip_access: trusted_network
##
## Local c2s or remote s2s users cannot register accounts
##
## access_from: deny
## access: register
mod_roster: {}
mod_shared_roster: {}
mod_stats: {}
mod_time: {}
mod_vcard:
search: false
mod_vcard_xupdate: {}
mod_avatar: {}
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://check.messaging.one/
mod_register:
## Only accept registration requests from the "trusted"
## network (see access_rules section above).
## Think twice before enabling registration from any
## address. See the Jabber SPAM Manifesto for details:
## https://github.com/ge0rg/jabber-spam-fighting-manifesto
ip_access: trusted_network
mod_roster:
versioning: true
mod_s2s_dialback: {}
mod_http_api: {}
mod_fail2ban: {}
mod_shared_roster: {}
mod_stream_mgmt:
resend_on_timeout: if_offline
mod_vcard: {}
mod_vcard_xupdate: {}
mod_version:
show_os: false
##
## Enable modules with custom options in a specific virtual host
##
## host_config:
## "localhost":
## modules:
## mod_echo:
## host: "mirror.localhost"
##
## Enable modules management via ejabberdctl for installation and
## uninstallation of public/private contributed modules
## (enabled by default)
##
allow_contrib_modules: true
###.
###'
### Local Variables:
### mode: yaml
### End:
### vim: set filetype=yaml tabstop=8 foldmarker=###',###. foldmethod=marker:
### vim: set filetype=yaml tabstop=8
+6 -6
View File
@@ -33,10 +33,10 @@
# from a client or from another Jabber server. So take this into
# account when setting this limit.
#
# Default: 32000
# Default: 65536 (or 8196 on Windows)
# Maximum: 268435456
#
#ERL_MAX_PORTS=32000
#ERL_MAX_PORTS=65536
#.
#' FIREWALL_WINDOW: Range of allowed ports to pass through a firewall
@@ -85,10 +85,10 @@
# Erlang, and therefore not related to the operating system processes, you do
# not have to worry about allowing a huge number of them.
#
# Default: 250000
# Default: 262144
# Maximum: 268435456
#
#ERL_PROCESSES=250000
#ERL_PROCESSES=262144
#.
#' ERL_MAX_ETS_TABLES: Maximum number of ETS and Mnesia tables
@@ -99,9 +99,9 @@
# You can safely increase this limit when starting ejabberd. It impacts memory
# consumption but the difference will be quite small.
#
# Default: 1400
# Default: 2053
#
#ERL_MAX_ETS_TABLES=1400
#ERL_MAX_ETS_TABLES=2053
#.
#' ERL_OPTIONS: Additional Erlang options
+1 -1
View File
@@ -70,7 +70,7 @@ done
echo '7. compile ejabberd'
gmake
for A in mod_irc mod_muc mod_pubsub; do
for A in mod_muc mod_pubsub; do
(cd $A; gmake)
done
-1
View File
@@ -51,7 +51,6 @@ override_acls.
{mod_offline, []},
{mod_echo, [{host, "echo.jabber.dbc.mtview.ca.us"}]},
{mod_private, []},
% {mod_irc, []},
{mod_muc, []},
{mod_pubsub, []},
{mod_time, []},
-72
View File
@@ -1,72 +0,0 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-ifndef(EJABBERD_HRL).
-define(EJABBERD_HRL, true).
-define(VERSION, ejabberd_config:get_version()).
-define(MYHOSTS, ejabberd_config:get_myhosts()).
-define(MYNAME, hd(ejabberd_config:get_myhosts())).
-define(MYLANG, ejabberd_config:get_mylang()).
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
-define(SQL_DIR, filename:join(["priv", "sql"])).
-define(CONFIG_PATH, <<"ejabberd.yml">>).
-define(LOG_PATH, "ejabberd.log").
-define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>).
-define(COPYRIGHT, "Copyright (c) ProcessOne").
%%-define(DBGFSM, true).
-record(scram,
{storedkey = <<"">>,
serverkey = <<"">>,
salt = <<"">>,
iterationcount = 0 :: integer()}).
-type scram() :: #scram{}.
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
-ifdef(ERL_DEPRECATED_TYPES).
-define(TDICT, dict()).
-define(TGB_TREE, gb_tree()).
-define(TGB_SET, gb_set()).
-define(TQUEUE, queue()).
-else.
-define(TDICT, dict:dict()).
-define(TGB_TREE, gb_trees:tree()).
-define(TGB_SET, gb_sets:set()).
-define(TQUEUE, queue:queue()).
-endif.
-endif.
+4 -1
View File
@@ -31,7 +31,10 @@
port = 5280 :: inet:port_number(),
opts = [] :: list(),
tp = http :: protocol(),
headers = [] :: [{atom() | binary(), binary()}]}).
headers = [] :: [{atom() | binary(), binary()}],
length = 0 :: non_neg_integer(),
sockmod :: gen_tcp | fast_tls,
socket :: inet:socket() | fast_tls:tls_socket()}).
-record(ws,
{socket :: inet:socket() | fast_tls:tls_socket(),
-501
View File
@@ -1,501 +0,0 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-include("ns.hrl").
-include("fxml.hrl").
-define(STANZA_ERROR(Code, Type, Condition),
#xmlel{name = <<"error">>,
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
children = []}]}).
-define(ERR_BAD_FORMAT,
?STANZA_ERROR(<<"406">>, <<"modify">>,
<<"bad-format">>)).
-define(ERR_BAD_REQUEST,
?STANZA_ERROR(<<"400">>, <<"modify">>,
<<"bad-request">>)).
-define(ERR_CONFLICT,
?STANZA_ERROR(<<"409">>, <<"cancel">>, <<"conflict">>)).
-define(ERR_FEATURE_NOT_IMPLEMENTED,
?STANZA_ERROR(<<"501">>, <<"cancel">>,
<<"feature-not-implemented">>)).
-define(ERR_FORBIDDEN,
?STANZA_ERROR(<<"403">>, <<"auth">>, <<"forbidden">>)).
-define(ERR_GONE,
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"gone">>)).
-define(ERR_INTERNAL_SERVER_ERROR,
?STANZA_ERROR(<<"500">>, <<"wait">>,
<<"internal-server-error">>)).
-define(ERR_ITEM_NOT_FOUND,
?STANZA_ERROR(<<"404">>, <<"cancel">>,
<<"item-not-found">>)).
-define(ERR_JID_MALFORMED,
?STANZA_ERROR(<<"400">>, <<"modify">>,
<<"jid-malformed">>)).
-define(ERR_NOT_ACCEPTABLE,
?STANZA_ERROR(<<"406">>, <<"modify">>,
<<"not-acceptable">>)).
-define(ERR_NOT_ALLOWED,
?STANZA_ERROR(<<"405">>, <<"cancel">>,
<<"not-allowed">>)).
-define(ERR_NOT_AUTHORIZED,
?STANZA_ERROR(<<"401">>, <<"auth">>,
<<"not-authorized">>)).
-define(ERR_PAYMENT_REQUIRED,
?STANZA_ERROR(<<"402">>, <<"auth">>,
<<"payment-required">>)).
-define(ERR_RECIPIENT_UNAVAILABLE,
?STANZA_ERROR(<<"404">>, <<"wait">>,
<<"recipient-unavailable">>)).
-define(ERR_REDIRECT,
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"redirect">>)).
-define(ERR_REGISTRATION_REQUIRED,
?STANZA_ERROR(<<"407">>, <<"auth">>,
<<"registration-required">>)).
-define(ERR_REMOTE_SERVER_NOT_FOUND,
?STANZA_ERROR(<<"404">>, <<"cancel">>,
<<"remote-server-not-found">>)).
-define(ERR_REMOTE_SERVER_TIMEOUT,
?STANZA_ERROR(<<"504">>, <<"wait">>,
<<"remote-server-timeout">>)).
-define(ERR_RESOURCE_CONSTRAINT,
?STANZA_ERROR(<<"500">>, <<"wait">>,
<<"resource-constraint">>)).
-define(ERR_SERVICE_UNAVAILABLE,
?STANZA_ERROR(<<"503">>, <<"cancel">>,
<<"service-unavailable">>)).
-define(ERR_SUBSCRIPTION_REQUIRED,
?STANZA_ERROR(<<"407">>, <<"auth">>,
<<"subscription-required">>)).
-define(ERR_UNEXPECTED_REQUEST,
?STANZA_ERROR(<<"400">>, <<"wait">>,
<<"unexpected-request">>)).
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
?STANZA_ERROR(<<"401">>, <<"cancel">>,
<<"unexpected-request">>)).
%-define(ERR_,
% ?STANZA_ERROR("", "", "")).
-define(STANZA_ERRORT(Code, Type, Condition, Lang,
Text),
#xmlel{name = <<"error">>,
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
#xmlel{name = <<"text">>,
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
children =
[{xmlcdata,
translate:translate(Lang, Text)}]}]}).
-define(ERRT_BAD_FORMAT(Lang, Text),
?STANZA_ERRORT(<<"406">>, <<"modify">>,
<<"bad-format">>, Lang, Text)).
-define(ERRT_BAD_REQUEST(Lang, Text),
?STANZA_ERRORT(<<"400">>, <<"modify">>,
<<"bad-request">>, Lang, Text)).
-define(ERRT_CONFLICT(Lang, Text),
?STANZA_ERRORT(<<"409">>, <<"cancel">>, <<"conflict">>,
Lang, Text)).
-define(ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Text),
?STANZA_ERRORT(<<"501">>, <<"cancel">>,
<<"feature-not-implemented">>, Lang, Text)).
-define(ERRT_FORBIDDEN(Lang, Text),
?STANZA_ERRORT(<<"403">>, <<"auth">>, <<"forbidden">>,
Lang, Text)).
-define(ERRT_GONE(Lang, Text),
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"gone">>,
Lang, Text)).
-define(ERRT_INTERNAL_SERVER_ERROR(Lang, Text),
?STANZA_ERRORT(<<"500">>, <<"wait">>,
<<"internal-server-error">>, Lang, Text)).
-define(ERRT_ITEM_NOT_FOUND(Lang, Text),
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
<<"item-not-found">>, Lang, Text)).
-define(ERRT_JID_MALFORMED(Lang, Text),
?STANZA_ERRORT(<<"400">>, <<"modify">>,
<<"jid-malformed">>, Lang, Text)).
-define(ERRT_NOT_ACCEPTABLE(Lang, Text),
?STANZA_ERRORT(<<"406">>, <<"modify">>,
<<"not-acceptable">>, Lang, Text)).
-define(ERRT_NOT_ALLOWED(Lang, Text),
?STANZA_ERRORT(<<"405">>, <<"cancel">>,
<<"not-allowed">>, Lang, Text)).
-define(ERRT_NOT_AUTHORIZED(Lang, Text),
?STANZA_ERRORT(<<"401">>, <<"auth">>,
<<"not-authorized">>, Lang, Text)).
-define(ERRT_PAYMENT_REQUIRED(Lang, Text),
?STANZA_ERRORT(<<"402">>, <<"auth">>,
<<"payment-required">>, Lang, Text)).
-define(ERRT_RECIPIENT_UNAVAILABLE(Lang, Text),
?STANZA_ERRORT(<<"404">>, <<"wait">>,
<<"recipient-unavailable">>, Lang, Text)).
-define(ERRT_REDIRECT(Lang, Text),
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"redirect">>,
Lang, Text)).
-define(ERRT_REGISTRATION_REQUIRED(Lang, Text),
?STANZA_ERRORT(<<"407">>, <<"auth">>,
<<"registration-required">>, Lang, Text)).
-define(ERRT_REMOTE_SERVER_NOT_FOUND(Lang, Text),
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
<<"remote-server-not-found">>, Lang, Text)).
-define(ERRT_REMOTE_SERVER_TIMEOUT(Lang, Text),
?STANZA_ERRORT(<<"504">>, <<"wait">>,
<<"remote-server-timeout">>, Lang, Text)).
-define(ERRT_RESOURCE_CONSTRAINT(Lang, Text),
?STANZA_ERRORT(<<"500">>, <<"wait">>,
<<"resource-constraint">>, Lang, Text)).
-define(ERRT_SERVICE_UNAVAILABLE(Lang, Text),
?STANZA_ERRORT(<<"503">>, <<"cancel">>,
<<"service-unavailable">>, Lang, Text)).
-define(ERRT_SUBSCRIPTION_REQUIRED(Lang, Text),
?STANZA_ERRORT(<<"407">>, <<"auth">>,
<<"subscription-required">>, Lang, Text)).
-define(ERRT_UNEXPECTED_REQUEST(Lang, Text),
?STANZA_ERRORT(<<"400">>, <<"wait">>,
<<"unexpected-request">>, Lang, Text)).
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
?ERRT_NOT_ACCEPTABLE(Lang, <<"No resource provided">>)).
-define(ERR_AUTH_BAD_RESOURCE_FORMAT(Lang),
?ERRT_NOT_ACCEPTABLE(Lang,
<<"Illegal resource format">>)).
-define(ERR_AUTH_RESOURCE_CONFLICT(Lang),
?ERRT_CONFLICT(Lang, <<"Resource conflict">>)).
-define(STREAM_ERROR(Condition, Cdata),
#xmlel{name = <<"stream:error">>, attrs = [],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
children = [{xmlcdata, Cdata}]}]}).
-define(SERR_BAD_FORMAT,
?STREAM_ERROR(<<"bad-format">>, <<"">>)).
-define(SERR_BAD_NAMESPACE_PREFIX,
?STREAM_ERROR(<<"bad-namespace-prefix">>, <<"">>)).
-define(SERR_CONFLICT,
?STREAM_ERROR(<<"conflict">>, <<"">>)).
-define(SERR_CONNECTION_TIMEOUT,
?STREAM_ERROR(<<"connection-timeout">>, <<"">>)).
-define(SERR_HOST_GONE,
?STREAM_ERROR(<<"host-gone">>, <<"">>)).
-define(SERR_HOST_UNKNOWN,
?STREAM_ERROR(<<"host-unknown">>, <<"">>)).
-define(SERR_IMPROPER_ADDRESSING,
?STREAM_ERROR(<<"improper-addressing">>, <<"">>)).
-define(SERR_INTERNAL_SERVER_ERROR,
?STREAM_ERROR(<<"internal-server-error">>, <<"">>)).
-define(SERR_INVALID_FROM,
?STREAM_ERROR(<<"invalid-from">>, <<"">>)).
-define(SERR_INVALID_ID,
?STREAM_ERROR(<<"invalid-id">>, <<"">>)).
-define(SERR_INVALID_NAMESPACE,
?STREAM_ERROR(<<"invalid-namespace">>, <<"">>)).
-define(SERR_INVALID_XML,
?STREAM_ERROR(<<"invalid-xml">>, <<"">>)).
-define(SERR_NOT_AUTHORIZED,
?STREAM_ERROR(<<"not-authorized">>, <<"">>)).
-define(SERR_POLICY_VIOLATION,
?STREAM_ERROR(<<"policy-violation">>, <<"">>)).
-define(SERR_REMOTE_CONNECTION_FAILED,
?STREAM_ERROR(<<"remote-connection-failed">>, <<"">>)).
-define(SERR_RESOURSE_CONSTRAINT,
?STREAM_ERROR(<<"resource-constraint">>, <<"">>)).
-define(SERR_RESTRICTED_XML,
?STREAM_ERROR(<<"restricted-xml">>, <<"">>)).
-define(SERR_SEE_OTHER_HOST(Host),
?STREAM_ERROR(<<"see-other-host">>, Host)).
-define(SERR_SYSTEM_SHUTDOWN,
?STREAM_ERROR(<<"system-shutdown">>, <<"">>)).
-define(SERR_UNSUPPORTED_ENCODING,
?STREAM_ERROR(<<"unsupported-encoding">>, <<"">>)).
-define(SERR_UNSUPPORTED_STANZA_TYPE,
?STREAM_ERROR(<<"unsupported-stanza-type">>, <<"">>)).
-define(SERR_UNSUPPORTED_VERSION,
?STREAM_ERROR(<<"unsupported-version">>, <<"">>)).
-define(SERR_XML_NOT_WELL_FORMED,
?STREAM_ERROR(<<"xml-not-well-formed">>, <<"">>)).
%-define(SERR_,
% ?STREAM_ERROR("", "")).
-define(STREAM_ERRORT(Condition, Cdata, Lang, Text),
#xmlel{name = <<"stream:error">>, attrs = [],
children =
[#xmlel{name = Condition,
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
children = [{xmlcdata, Cdata}]},
#xmlel{name = <<"text">>,
attrs =
[{<<"xml:lang">>, Lang},
{<<"xmlns">>, ?NS_STREAMS}],
children =
[{xmlcdata,
translate:translate(Lang, Text)}]}]}).
-define(SERRT_BAD_FORMAT(Lang, Text),
?STREAM_ERRORT(<<"bad-format">>, <<"">>, Lang, Text)).
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
?STREAM_ERRORT(<<"bad-namespace-prefix">>, <<"">>, Lang,
Text)).
-define(SERRT_CONFLICT(Lang, Text),
?STREAM_ERRORT(<<"conflict">>, <<"">>, Lang, Text)).
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
?STREAM_ERRORT(<<"connection-timeout">>, <<"">>, Lang,
Text)).
-define(SERRT_HOST_GONE(Lang, Text),
?STREAM_ERRORT(<<"host-gone">>, <<"">>, Lang, Text)).
-define(SERRT_HOST_UNKNOWN(Lang, Text),
?STREAM_ERRORT(<<"host-unknown">>, <<"">>, Lang, Text)).
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
?STREAM_ERRORT(<<"improper-addressing">>, <<"">>, Lang,
Text)).
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
?STREAM_ERRORT(<<"internal-server-error">>, <<"">>,
Lang, Text)).
-define(SERRT_INVALID_FROM(Lang, Text),
?STREAM_ERRORT(<<"invalid-from">>, <<"">>, Lang, Text)).
-define(SERRT_INVALID_ID(Lang, Text),
?STREAM_ERRORT(<<"invalid-id">>, <<"">>, Lang, Text)).
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
?STREAM_ERRORT(<<"invalid-namespace">>, <<"">>, Lang,
Text)).
-define(SERRT_INVALID_XML(Lang, Text),
?STREAM_ERRORT(<<"invalid-xml">>, <<"">>, Lang, Text)).
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
?STREAM_ERRORT(<<"not-authorized">>, <<"">>, Lang,
Text)).
-define(SERRT_POLICY_VIOLATION(Lang, Text),
?STREAM_ERRORT(<<"policy-violation">>, <<"">>, Lang,
Text)).
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
?STREAM_ERRORT(<<"remote-connection-failed">>, <<"">>,
Lang, Text)).
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
?STREAM_ERRORT(<<"resource-constraint">>, <<"">>, Lang,
Text)).
-define(SERRT_RESTRICTED_XML(Lang, Text),
?STREAM_ERRORT(<<"restricted-xml">>, <<"">>, Lang,
Text)).
-define(SERRT_SEE_OTHER_HOST(Host, Lang, Text),
?STREAM_ERRORT(<<"see-other-host">>, Host, Lang, Text)).
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
?STREAM_ERRORT(<<"system-shutdown">>, <<"">>, Lang,
Text)).
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
?STREAM_ERRORT(<<"unsupported-encoding">>, <<"">>, Lang,
Text)).
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
?STREAM_ERRORT(<<"unsupported-stanza-type">>, <<"">>,
Lang, Text)).
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
?STREAM_ERRORT(<<"unsupported-version">>, <<"">>, Lang,
Text)).
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
?STREAM_ERRORT(<<"xml-not-well-formed">>, <<"">>, Lang,
Text)).
-record(jid, {user = <<"">> :: binary(),
server = <<"">> :: binary(),
resource = <<"">> :: binary(),
luser = <<"">> :: binary(),
lserver = <<"">> :: binary(),
lresource = <<"">> :: binary()}).
-type(jid() :: #jid{}).
-type(ljid() :: {binary(), binary(), binary()}).
-record(iq, {id = <<"">> :: binary(),
type = get :: get | set | result | error,
xmlns = <<"">> :: binary(),
lang = <<"">> :: binary(),
sub_el = #xmlel{} :: xmlel() | [xmlel()]}).
-type(iq_get()
:: #iq{
id :: binary(),
type :: get,
xmlns :: binary(),
lang :: binary(),
sub_el :: xmlel()
}
).
-type(iq_set()
:: #iq{
id :: binary(),
type :: set,
xmlns :: binary(),
lang :: binary(),
sub_el :: xmlel()
}
).
-type iq_request() :: iq_get() | iq_set().
-type(iq_result()
:: #iq{
id :: binary(),
type :: result,
xmlns :: binary(),
lang :: binary(),
sub_el :: [xmlel()]
}
).
-type(iq_error()
:: #iq{
id :: binary(),
type :: error,
xmlns :: binary(),
lang :: binary(),
sub_el :: [xmlel()]
}
).
-type iq_reply() :: iq_result() | iq_error() .
-type(iq() :: iq_request() | iq_reply()).
-record(rsm_in, {max :: integer() | error | undefined,
direction :: before | aft | undefined,
id :: binary() | undefined,
index :: integer() | error | undefined}).
-record(rsm_out, {count :: integer() | undefined,
index :: integer() | undefined,
first :: binary() | undefined,
last :: binary() | undefined}).
-type(rsm_in() :: #rsm_in{}).
-type(rsm_out() :: #rsm_out{}).
-type broadcast() :: {broadcast, broadcast_data()}.
-type broadcast_data() ::
{rebind, pid(), binary()} | %% ejabberd_c2s
{item, ljid(), mod_roster:subscription()} | %% mod_roster/mod_shared_roster
{exit, binary()} | %% mod_roster/mod_shared_roster
{privacy_list, mod_privacy:userlist(), binary()} | %% mod_privacy
{blocking, unblock_all | {block | unblock, [ljid()]}}. %% mod_blocking
-record(xmlelement, {name = "" :: string(),
attrs = [] :: [{string(), string()}],
children = [] :: [{xmlcdata, iodata()} | xmlelement()]}).
-type xmlelement() :: #xmlelement{}.
+3
View File
@@ -42,3 +42,6 @@
false -> ok;
_ -> 'Elixir.Logger':bare_log(error, io_lib:format(Format, Args), [?MODULE])
end).
%% Uncomment if you want to debug p1_fsm/gen_fsm
%%-define(DBGFSM, true).
-35
View File
@@ -1,35 +0,0 @@
%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-type conn_param() :: {binary(), binary(), inet:port_number(), binary()} |
{binary(), binary(), inet:port_number()} |
{binary(), binary()} |
{binary()}.
-type irc_data() :: [{username, binary()} | {connections_params, [conn_param()]}].
-record(irc_connection,
{jid_server_host = {#jid{}, <<"">>, <<"">>} :: {jid(), binary(), binary()},
pid = self() :: pid()}).
-record(irc_custom,
{us_host = {{<<"">>, <<"">>}, <<"">>} :: {{binary(), binary()},
binary()},
data = [] :: irc_data()}).
+9 -10
View File
@@ -18,8 +18,6 @@
%%%
%%%----------------------------------------------------------------------
-include("ejabberd.hrl").
-define(MAX_USERS_DEFAULT, 200).
-define(SETS, gb_sets).
@@ -64,9 +62,10 @@
logging = false :: boolean(),
vcard = <<"">> :: binary(),
vcard_xupdate = undefined :: undefined | external | binary(),
captcha_whitelist = (?SETS):empty() :: ?TGB_SET,
captcha_whitelist = (?SETS):empty() :: gb_sets:set(),
mam = false :: boolean(),
pubsub = <<"">> :: binary()
pubsub = <<"">> :: binary(),
lang = ejabberd_config:get_mylang() :: binary()
}).
-type config() :: #config{}.
@@ -106,13 +105,13 @@
access = {none,none,none,none} :: {atom(), atom(), atom(), atom()},
jid = #jid{} :: jid(),
config = #config{} :: config(),
users = (?DICT):new() :: ?TDICT,
subscribers = (?DICT):new() :: ?TDICT,
subscriber_nicks = (?DICT):new() :: ?TDICT,
users = (?DICT):new() :: dict:dict(),
subscribers = (?DICT):new() :: dict:dict(),
subscriber_nicks = (?DICT):new() :: dict:dict(),
last_voice_request_time = treap:empty() :: treap:treap(),
robots = (?DICT):new() :: ?TDICT,
nicks = (?DICT):new() :: ?TDICT,
affiliations = (?DICT):new() :: ?TDICT,
robots = (?DICT):new() :: dict:dict(),
nicks = (?DICT):new() :: dict:dict(),
affiliations = (?DICT):new() :: dict:dict(),
history :: lqueue(),
subject = [] :: [text()],
subject_author = <<"">> :: binary(),
+5 -7
View File
@@ -18,8 +18,6 @@
%%%
%%%----------------------------------------------------------------------
-include("ejabberd.hrl").
%% -------------------------------
%% Pubsub constants
-define(ERR_EXTENDED(E, C), mod_pubsub:extended_error(E, C)).
@@ -131,13 +129,13 @@
id ,% :: mod_pubsub:nodeIdx(),
parents = [] ,% :: [mod_pubsub:nodeId(),...],
type = <<"flat">>,% :: binary(),
owners = [] ,% :: [jlib:ljid(),...],
owners = [] ,% :: [jid:ljid(),...],
options = [] % :: mod_pubsub:nodeOptions()
}).
-record(pubsub_state,
{
stateid ,% :: {jlib:ljid(), mod_pubsub:nodeIdx()},
stateid ,% :: {jid:ljid(), mod_pubsub:nodeIdx()},
nodeidx ,% :: mod_pubsub:nodeIdx(),
items = [] ,% :: [mod_pubsub:itemId(),...],
affiliation = 'none',% :: mod_pubsub:affiliation(),
@@ -148,8 +146,8 @@
{
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()},
creation = {unknown, unknown},% :: {erlang:timestamp(), jid:ljid()},
modification = {unknown, unknown},% :: {erlang:timestamp(), jid:ljid()},
payload = [] % :: mod_pubsub:payload()
}).
@@ -163,7 +161,7 @@
{
nodeid ,% :: {binary(), mod_pubsub:nodeIdx()},
itemid ,% :: mod_pubsub:itemId(),
creation ,% :: {erlang:timestamp(), jlib:ljid()},
creation ,% :: {erlang:timestamp(), jid:ljid()},
payload % :: mod_pubsub:payload()
}).
-17
View File
@@ -84,20 +84,3 @@ EOF
AC_MSG_RESULT([ok])
fi
]) dnl ERLANG_VERSION_CHECK
AC_DEFUN([ERLANG_DEPRECATED_TYPES_CHECK],
[ AC_MSG_CHECKING([whether Erlang is using deprecated types])
cat > conftest.erl <<EOF
-module(conftest).
-record(state, {host = dict:new() :: dict:dict()}).
EOF
if $ERLC conftest.erl > /dev/null 2>&1; then
AC_MSG_RESULT([no])
AC_SUBST(erlang_deprecated_types, false)
else
AC_MSG_RESULT([yes])
AC_SUBST(erlang_deprecated_types, true)
fi
])
+3 -3
View File
@@ -3,7 +3,7 @@ defmodule Ejabberd.Mixfile do
def project do
[app: :ejabberd,
version: "18.4.0",
version: "18.6.0",
description: description(),
elixir: "~> 1.4",
elixirc_paths: ["lib"],
@@ -61,7 +61,7 @@ defmodule Ejabberd.Mixfile do
[{:lager, "~> 3.4.0"},
{:p1_utils, "~> 1.0"},
{:fast_xml, "~> 1.1"},
{:xmpp, "~> 1.1"},
{:xmpp, "~> 1.2"},
{:cache_tab, "~> 1.0"},
{:stringprep, "~> 1.0"},
{:fast_yaml, "~> 1.0"},
@@ -125,7 +125,7 @@ defmodule Ejabberd.Mixfile do
defp vars do
case :file.consult("vars.config") do
{:ok,config} -> config
_ -> [zlib: true, iconv: true]
_ -> [zlib: true, iconv: false]
end
end
+17 -17
View File
@@ -1,35 +1,35 @@
%{
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"cache_tab": {:hex, :cache_tab, "1.0.13", "e09857af9b7ba89428227d3801256852cb0d51a4de47e4edcb160d96cc96f8eb", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"distillery": {:hex, :distillery, "1.5.2", "eec18b2d37b55b0bcb670cf2bcf64228ed38ce8b046bb30a9b636a6f5a4c0080", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"},
"eimp": {:hex, :eimp, "1.0.3", "e40108d622d672cf6003d279d98fc46a98df182dbe8756857896ffd28883090d", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"cache_tab": {:hex, :cache_tab, "1.0.16", "0223820e5071d3252b9921db9dcc74a09ec8a660120271fdb47c3c40b6b52bee", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"distillery": {:hex, :distillery, "1.5.3", "b2f4fc34ec71ab4f1202a796f9290e068883b042319aa8c9aa45377ecac8597a", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.5", "4d21980d5d2862a2e13ec3c49ad9ad783ffc7ca5769cf6ff891a4553fbaae761", [:mix], [], "hexpm"},
"eimp": {:hex, :eimp, "1.0.9", "daf0d2904be3ef5e4128d946e158113cdb4d52555023746d29b83ce86b531f3c", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"epam": {:hex, :epam, "1.0.4", "2a5e40cbf9b2cf41df515782894c3b33c81b8ad32fff2fc847c3f725071dfaed", [:rebar3], [], "hexpm"},
"eredis": {:hex, :eredis, "1.1.0", "8d8d74496f35216679b97726b75fb1c8715e99dd7f3ef9f9824a2264c3e0aac0", [:rebar3], [], "hexpm"},
"esip": {:hex, :esip, "1.0.22", "3e387312614762fb84d3f77ba4f17650faf52510482521300b3d98ecdcbec21d", [:rebar3], [{:fast_tls, "1.0.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.21", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm"},
"esip": {:hex, :esip, "1.0.26", "b50c92f8ac3e8e8ba901f0a6cc7e0e47fdc832b0f3044eddb6032ca26845cf97", [:rebar3], [{:fast_tls, "1.0.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stun, "1.0.25", [hex: :stun, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"ezlib": {:hex, :ezlib, "1.0.4", "2434e4bb549cb060d5ac02261ba48fbe1a69b2ae4e1bf7485a3b27b3f3ec618d", [:rebar3], [], "hexpm"},
"fast_tls": {:hex, :fast_tls, "1.0.21", "7005fe030c0472643314c9c31e7627bb296dcb96a9ce0b5dd8ccb34273f4c1ff", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_xml": {:hex, :fast_xml, "1.1.29", "c6356d28f0f76ffefc68b5eb65916f0b8ca513bab71db8ad95bd8577c47e30e2", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_yaml": {:hex, :fast_yaml, "1.0.13", "adcb8db20bb96d4e56b63b48c75d47ca15a6bd409da0200ffbd32db382131e22", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_tls": {:hex, :fast_tls, "1.0.25", "cbf875fe709d6fd03d3266c920bfe15f4d22736535d73421300cebf9d86bd851", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_xml": {:hex, :fast_xml, "1.1.34", "d76fc639d3607a44c4f0fb2dfdee1067b6c37b02b39706d8f067cb77eb2f6016", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"fast_yaml": {:hex, :fast_yaml, "1.0.17", "e945ef64e0cb7c311c7b42804dbe32a24e13a2afc0ffe249b7e0f9f9ac08e176", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"},
"hamcrest": {:hex, :basho_hamcrest, "0.4.1", "fb7b2c92d252a1e9db936750b86089addaebeb8f87967fb4bbdda61e8863338e", [:make, :mix, :rebar3], [], "hexpm"},
"iconv": {:hex, :iconv, "1.0.7", "f81eb6b8c977b1fd078515937fdce64292d64c6102353fbbfe57db580f4689d1", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"iconv": {:hex, :iconv, "1.0.10", "fc7de75c0a1fbc1e4ed0c68637ae7464a5dd9eee81710fff26321922d144ecea", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"jiffy": {:hex, :jiffy, "0.14.13", "225a9a35e26417832c611526567194b4d3adc4f0dfa5f2f7008f4684076f2a01", [:rebar3], [], "hexpm"},
"jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
"lager": {:hex, :lager, "3.4.2", "150b9a17b23ae6d3265cc10dc360747621cf217b7a22b8cddf03b2909dbf7aa5", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
"luerl": {:hex, :luerl, "0.3.1", "5412807630aac1aaf59ffe5a1bc09259c447b4faeb1d3fe2d4ef41b87676cb04", [:rebar3], [], "hexpm"},
"meck": {:hex, :meck, "0.8.9", "64c5c0bd8bcca3a180b44196265c8ed7594e16bcc845d0698ec6b4e577f48188", [:rebar3], [], "hexpm"},
"meck": {:hex, :meck, "0.8.10", "455aaef8403be46752272206613e7a15467c014d40994b22fb54cde4d1ff7075", [:rebar3], [], "hexpm"},
"moka": {:git, "https://github.com/processone/moka.git", "3eed3a6dd7dedb70a6cd18f86c7561a18626eb3b", [tag: "1.0.5c"]},
"p1_mysql": {:hex, :p1_mysql, "1.0.5", "2a9644d27050a6aa9e7eb70a0620043f93655212b15f3620dc12f2fbd1a8c43a", [:rebar3], [], "hexpm"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.2", "cc381038920e3d34ef32aa10ba7eb637bdff38a946748c4fd99329ff484a3889", [:rebar3], [], "hexpm"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.5", "1e1bef6e6d906e10552a608b9fe5ef39b3099caf0f44c07d3d9e18ac4dee34d1", [:rebar3], [], "hexpm"},
"p1_utils": {:hex, :p1_utils, "1.0.11", "a471f80644d4b464fa67572affddda7e95df5d4b099624b8907f5726e8a1769c", [:rebar3], [], "hexpm"},
"p1_mysql": {:hex, :p1_mysql, "1.0.7", "9fbadf8fa283ae8657faa4f6bbe13f2e3b9da0cdcfbc699cfc120d0905282056", [:rebar3], [], "hexpm"},
"p1_oauth2": {:hex, :p1_oauth2, "0.6.3", "fbd91ba86bd7f03d2a4f6e62affa86bab9930abfd6b473d61eefb148f246cd46", [:rebar3], [], "hexpm"},
"p1_pgsql": {:hex, :p1_pgsql, "1.1.6", "631004602b06ca6f55d759001f180185685c7097e583f3b0f7dd9b8e05ba5db1", [:rebar3], [], "hexpm"},
"p1_utils": {:hex, :p1_utils, "1.0.13", "176577cafb54a8c2fdc0a7fc62b9a21ab0f66588f4062792cd9e65f3e500bfdb", [:rebar3], [], "hexpm"},
"riak_pb": {:hex, :riak_pb, "2.3.2", "48ffbf66dbb3f136ab9a7134bac4e496754baa5ef58c4f50a61326736d996390", [:make, :mix, :rebar3], [{:hamcrest, "~> 0.4.1", [hex: :basho_hamcrest, repo: "hexpm", optional: false]}], "hexpm"},
"riakc": {:hex, :riakc, "2.5.3", "6132d9e687a0dfd314b2b24c4594302ca8b55568a5d733c491d8fb6cd4004763", [:make, :mix, :rebar3], [{:riak_pb, "~> 2.3", [hex: :riak_pb, repo: "hexpm", optional: false]}], "hexpm"},
"samerlib": {:git, "https://github.com/processone/samerlib", "fbbba035b1548ac4e681df00d61bf609645333a0", [tag: "0.8.0c"]},
"sqlite3": {:hex, :sqlite3, "1.1.6", "4ea71af0b45908b5f02c9b09e4c87177039ef404f20accb35049cd8924cc417c", [:rebar3], [], "hexpm"},
"stringprep": {:hex, :stringprep, "1.0.11", "002e6972ab36c35f3dd88c11725014e62608c45a00399c083681879973fa8026", [:rebar3], [{:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"stun": {:hex, :stun, "1.0.21", "087fb20497081927690ef9d70b5bd6f9f4bea256ad758c500842722c0b6bb6ab", [:rebar3], [{:fast_tls, "1.0.21", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"xmpp": {:hex, :xmpp, "1.1.20", "33ddcc698518061f5051b98a6f731eef9342799f0c276a9debdfffe85c32fe6d", [:rebar3], [{:fast_xml, "1.1.29", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.11", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.11", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
"stringprep": {:hex, :stringprep, "1.0.14", "230a2d1c576bba168749d653fd6681166d02431ef07161a918444f3edb478ad0", [:rebar3], [{:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"stun": {:hex, :stun, "1.0.25", "e324c94c28d636578db79eb26979cd07140f0dabcdc0d5b197650ba0bc44a31a", [:rebar3], [{:fast_tls, "1.0.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"xmpp": {:hex, :xmpp, "1.2.5", "98ae86706013e51349e962b67c30293d14672603b5c7d782b2c79b52ceaa659f", [:rebar3], [{:ezlib, "1.0.4", [hex: :ezlib, repo: "hexpm", optional: false]}, {:fast_tls, "1.0.25", [hex: :fast_tls, repo: "hexpm", optional: false]}, {:fast_xml, "1.1.34", [hex: :fast_xml, repo: "hexpm", optional: false]}, {:p1_utils, "1.0.13", [hex: :p1_utils, repo: "hexpm", optional: false]}, {:stringprep, "1.0.14", [hex: :stringprep, repo: "hexpm", optional: false]}], "hexpm"},
}
+16
View File
@@ -0,0 +1,16 @@
redis.replicate_commands()
local cursor = redis.call('GET', KEYS[3]) or 0
local scan_result = redis.call('HSCAN', KEYS[1], cursor, 'COUNT', ARGV[1])
local newcursor = scan_result[1]
local cursor = redis.call('SET', KEYS[3], newcursor)
redis.call('EXPIRE', KEYS[3], 30)
for key,value in ipairs(scan_result[2]) do
local uskey, sidkey = string.match(value, '(.*)||(.*)')
if uskey and sidkey then
redis.call('HDEL', uskey, sidkey)
redis.call('HDEL', KEYS[1], value)
else
redis.call('HDEL', KEYS[2], value)
end
end
return newcursor
+1707 -1251
View File
File diff suppressed because it is too large Load Diff
+123 -121
View File
@@ -152,7 +152,7 @@ msgstr "Agosto"
#: mod_pubsub:1842
msgid "Automatic node creation is not enabled"
msgstr ""
msgstr "Criação automatizada de nós está desabilitada"
#: ejabberd_web_admin:1867 mod_configure:148 mod_configure:617
msgid "Backup"
@@ -185,11 +185,11 @@ msgstr "Aniversário"
#: mod_legacy_auth:102
msgid "Both the username and the resource are required"
msgstr ""
msgstr "Nome de usuário e recurso são necessários"
#: mod_proxy65_service:226
msgid "Bytestream already activated"
msgstr ""
msgstr "Bytestream já foi ativado"
#: ejabberd_captcha:135
msgid "CAPTCHA web page"
@@ -201,11 +201,11 @@ msgstr "Tempo de CPU"
#: mod_privacy:334
msgid "Cannot remove active list"
msgstr ""
msgstr "Não é possível remover uma lista ativa"
#: mod_privacy:341
msgid "Cannot remove default list"
msgstr ""
msgstr "Não é possível remover uma lista padrão"
#: ejabberd_web_admin:1679 mod_register_web:194 mod_register_web:353
#: mod_register_web:361 mod_register_web:386
@@ -383,7 +383,7 @@ msgstr "Exportar para arquivo texto"
#: mod_roster:180
msgid "Duplicated groups are not allowed by RFC6121"
msgstr ""
msgstr "Grupos duplicados não são permitidos pela RFC6121"
#: mod_configure:1776
msgid "Edit Properties"
@@ -413,7 +413,7 @@ msgstr "Permitir criação de logs"
#: mod_push:252
msgid "Enabling push without 'node' attribute is not supported"
msgstr ""
msgstr "Abilitar push sem o atributo 'node' não é suportado"
#: mod_irc:834
msgid "Encoding for server ~b"
@@ -503,15 +503,15 @@ msgstr ""
#: mod_delegation:275
msgid "External component failure"
msgstr ""
msgstr "Falha de componente externo"
#: mod_delegation:283
msgid "External component timeout"
msgstr ""
msgstr "Tempo esgotado à espera de componente externo"
#: mod_proxy65_service:218
msgid "Failed to activate bytestream"
msgstr ""
msgstr "Falha ao ativar bytestream"
#: mod_muc_room:910
msgid "Failed to extract JID from your voice request approval"
@@ -519,19 +519,19 @@ msgstr "Não foi possível extrair o JID (Jabber ID) da requisição de voz"
#: mod_delegation:257
msgid "Failed to map delegated namespace to external component"
msgstr ""
msgstr "Falha ao mapear namespace delegado ao componente externo"
#: mod_http_upload:602
msgid "Failed to parse HTTP response"
msgstr ""
msgstr "Falha ao analisar resposta HTTP"
#: mod_irc:426
msgid "Failed to parse chanserv"
msgstr ""
msgstr "Falha ao analisar chanserv"
#: mod_muc_room:3297
msgid "Failed to process option '~s'"
msgstr ""
msgstr "Falha ao processar opção '~s'"
#: mod_vcard_ldap:332 mod_vcard_ldap:345 mod_vcard_mnesia:103
#: mod_vcard_mnesia:117 mod_vcard_sql:158 mod_vcard_sql:172
@@ -544,7 +544,7 @@ msgstr "Fevereiro"
#: mod_http_upload:555
msgid "File larger than ~w bytes"
msgstr ""
msgstr "Arquivo maior que ~w bytes"
#: mod_vcard:437
msgid ""
@@ -610,7 +610,7 @@ msgstr "Máquina"
#: mod_s2s_dialback:325
msgid "Host unknown"
msgstr ""
msgstr "Máquina desconhecida"
#: ejabberd_web_admin:2463
msgid "IP"
@@ -699,15 +699,15 @@ msgstr "Importar dados dos usuários de um diretório-fila jabberd14:"
#: xmpp_stream_in:983
msgid "Improper 'from' attribute"
msgstr ""
msgstr "Atributo 'from' incorreto"
#: xmpp_stream_in:477
msgid "Improper 'to' attribute"
msgstr ""
msgstr "Atributo 'to' incorreto"
#: ejabberd_service:189
msgid "Improper domain part of 'from' attribute"
msgstr ""
msgstr "Atributo 'from' contém domínio incorreto"
#: mod_muc_room:260
msgid "Improper message type"
@@ -715,11 +715,11 @@ msgstr "Tipo de mensagem incorreto"
#: ejabberd_web_admin:1586
msgid "Incoming s2s Connections:"
msgstr "Conexões que entram de s2s"
msgstr "Conexões s2s de Entrada:"
#: mod_muc_room:3669 mod_register:187
msgid "Incorrect CAPTCHA submit"
msgstr ""
msgstr "CAPTCHA submetido incorretamente"
#: mod_muc:772 mod_muc_room:3052 mod_pubsub:1194 mod_register:183 mod_vcard:256
#, fuzzy
@@ -732,41 +732,41 @@ msgstr "Senha incorreta"
#: mod_irc:585
msgid "Incorrect value in data form"
msgstr ""
msgstr "Valor incorreto em formulário de dados"
#: mod_adhoc:276
msgid "Incorrect value of 'action' attribute"
msgstr ""
msgstr "Valor incorreto do atributo 'action'"
#: mod_configure:1806
msgid "Incorrect value of 'action' in data form"
msgstr ""
msgstr "Valor incorreto de 'action' no formulário de dados"
#: mod_configure:1335 mod_configure:1367 mod_configure:1399 mod_configure:1419
#: mod_configure:1439
msgid "Incorrect value of 'path' in data form"
msgstr ""
msgstr "Valor incorreto de 'path' no formulário de dados"
#: mod_irc:331
msgid "Incorrect value of 'type' attribute"
msgstr ""
msgstr "Valor incorreto do atributo 'type'"
#: mod_privilege:100
msgid "Insufficient privilege"
msgstr ""
msgstr "Privilégio insuficiente"
#: mod_privilege:286
msgid "Invalid 'from' attribute in forwarded message"
msgstr ""
msgstr "Atributo 'from' inválido na mensagem reenviada"
#: mod_privilege:300
msgid "Invalid <forwarded/> element"
msgstr ""
msgstr "Elemento <forwarded/> inválido"
#: mod_muc_room:3926
#, fuzzy
msgid "Invitations are not allowed in this conference"
msgstr "Requisições de voz estão desabilitadas nesta conferência"
msgstr "Convites estão desabilitados nesta sala de conferência"
#: mod_muc_room:233 mod_muc_room:375 mod_muc_room:1046
msgid ""
@@ -786,11 +786,11 @@ msgstr "Não é permitido enviar mensagens privadas do tipo \"groupchat\""
#: mod_muc_room:244
msgid "It is not allowed to send private messages to the conference"
msgstr "Impedir o envio de mensagens privadas para a sala"
msgstr "Não é permitido enviar mensagens privadas para a sala de conferência"
#: mod_register_web:181 mod_register_web:189
msgid "Jabber Account Registration"
msgstr "Registros de Contas Jabber"
msgstr "Registro de Contas Jabber"
#: mod_configure:1122 mod_configure:1139 mod_configure:1149 mod_configure:1159
#: mod_configure:1169 mod_configure:1183 mod_configure:1192 mod_configure:1600
@@ -805,11 +805,11 @@ msgstr "Janeiro"
#: mod_irc:665
msgid "Join IRC channel"
msgstr "Juntar-se ao canal IRC"
msgstr "Entrar no canal IRC"
#: mod_irc:689
msgid "Join the IRC channel here."
msgstr "Aqui! Juntar-se ao canal IRC."
msgstr "Entre no canal IRC aqui."
#: mod_irc:690
msgid "Join the IRC channel in this Jabber ID: ~s"
@@ -890,7 +890,7 @@ msgstr "Tornar sala pública possível de ser encontrada"
#: mod_register:317
#, fuzzy
msgid "Malformed username"
msgstr "Usuário IRC"
msgstr "Nome de usuário inválido"
#: mod_muc_log:475
msgid "March"
@@ -910,7 +910,7 @@ msgstr "Membros:"
#: mod_muc_room:1833
msgid "Membership is required to enter this room"
msgstr "Necessitas ser membro desta sala para poder entrar"
msgstr "É necessário ser membro desta sala para poder entrar"
#: mod_register_web:262
msgid ""
@@ -918,9 +918,9 @@ msgid ""
"Jabber there isn't an automated way to recover your password if you forget "
"it."
msgstr ""
"Memorize a sua senha, ou escreva-a em um papel e guarde-o em um lugar "
"seguro. Jabber não é uma maneira automatizada para recuperar a sua senha, se "
"você a esquecer eventualmente."
"Memorize a sua senha, ou anote-a em um papel, guardado em um local seguro. "
"No Jabber, não uma maneira automatizada de recuperar a sua senha, "
"caso a esqueça."
#: ejabberd_web_admin:1954
msgid "Memory"
@@ -932,7 +932,7 @@ msgstr "Corpo da mensagem"
#: mod_privilege:291
msgid "Message not found in forwarded payload"
msgstr ""
msgstr "Mensagem não encontrada em conteúdo encaminhado"
#: mod_vcard_ldap:331 mod_vcard_ldap:344 mod_vcard_mnesia:102
#: mod_vcard_mnesia:116 mod_vcard_sql:157 mod_vcard_sql:171
@@ -941,15 +941,15 @@ msgstr "Nome do meio"
#: mod_irc:704
msgid "Missing 'channel' or 'server' in the data form"
msgstr ""
msgstr "Faltando 'channel' ou 'server' no formulário de dados"
#: xmpp_stream_in:990
msgid "Missing 'from' attribute"
msgstr ""
msgstr "Faltando atributo 'from'"
#: xmpp_stream_in:472 xmpp_stream_in:993
msgid "Missing 'to' attribute"
msgstr ""
msgstr "Faltando atributo 'to'"
#: mod_muc_room:2536 mod_muc_room:3721 mod_muc_room:3765 mod_muc_room:3798
msgid "Moderator privileges required"
@@ -965,7 +965,7 @@ msgstr "Módulo"
#: gen_iq_handler:153
msgid "Module failed to handle the query"
msgstr ""
msgstr "Módulo falhou ao processar a consulta"
#: ejabberd_web_admin:1885 mod_configure:582 mod_configure:595
msgid "Modules"
@@ -989,7 +989,7 @@ msgstr "Multicast"
#: mod_roster:195
msgid "Multiple <item/> elements are not allowed by RFC6121"
msgstr ""
msgstr "Vários elementos <item/> não são permitidos pela RFC6121"
#: ejabberd_web_admin:1951 mod_vcard_mnesia:101 mod_vcard_mnesia:115
#: mod_vcard_sql:156 mod_vcard_sql:170
@@ -1002,11 +1002,11 @@ msgstr "Nome:"
#: mod_muc_room:2696
msgid "Neither 'jid' nor 'nick' attribute found"
msgstr ""
msgstr "Nem o atributo 'jid' nem 'nick' foram encontrados"
#: mod_muc_room:2518 mod_muc_room:2701
msgid "Neither 'role' nor 'affiliation' attribute found"
msgstr ""
msgstr "Nem o atributo 'role' nem 'affiliation' foram encontrados"
#: ejabberd_web_admin:1506 ejabberd_web_admin:1687 mod_configure:1629
msgid "Never"
@@ -1031,41 +1031,41 @@ msgstr "O apelido ~s não existe na sala"
#: mod_configure:1496
msgid "No 'access' found in data form"
msgstr ""
msgstr "'access' não foi encontrado em formulário de dados"
#: mod_configure:1455
msgid "No 'acls' found in data form"
msgstr ""
msgstr "'acls' não foi encontrado em formulário de dados"
#: mod_muc_room:3075
msgid "No 'affiliation' attribute found"
msgstr ""
msgstr "Atributo 'affiliation' não foi encontrado"
#: mod_muc_room:2505
#, fuzzy
msgid "No 'item' element found"
msgstr "Nó não encontrado"
msgstr "Elemento 'item' não foi encontrado"
#: mod_configure:1280
msgid "No 'modules' found in data form"
msgstr ""
msgstr "'modules' não foi encontrado em formulário de dados"
#: mod_configure:1799
msgid "No 'password' found in data form"
msgstr ""
msgstr "'password' não foi encontrado em formulário de dados"
#: mod_register:148
msgid "No 'password' found in this query"
msgstr ""
msgstr "'password' não foi encontrado nesta consulta"
#: mod_configure:1319 mod_configure:1350 mod_configure:1382 mod_configure:1413
#: mod_configure:1433
msgid "No 'path' found in data form"
msgstr ""
msgstr "'path' não foi encontrado em formulário de dados"
#: mod_muc_room:3922
msgid "No 'to' attribute found in the invitation"
msgstr ""
msgstr "Atributo 'to' não foi encontrado no convite"
#: ejabberd_web_admin:1767
msgid "No Data"
@@ -1073,7 +1073,7 @@ msgstr "Nenhum dado"
#: ejabberd_local:181
msgid "No available resource found"
msgstr ""
msgstr "Nenhum recurso disponível foi encontrado"
#: mod_announce:575
msgid "No body provided for announce message"
@@ -1082,45 +1082,45 @@ msgstr "Nenhum corpo de texto fornecido para anunciar mensagem"
#: mod_irc:335 mod_pubsub:1183 mod_pubsub:3289
#, fuzzy
msgid "No data form found"
msgstr "Nó não encontrado"
msgstr "Formulário de dados não foi encontrado"
#: mod_disco:224 mod_vcard:282
msgid "No features available"
msgstr ""
msgstr "Nenhuma funcionalidade disponível"
#: mod_adhoc:239
msgid "No hook has processed this command"
msgstr ""
msgstr "Nenhum hook processou este comando"
#: mod_last:218
msgid "No info about last activity found"
msgstr ""
msgstr "Não foi encontrada informação sobre última atividade"
#: mod_blocking:99
msgid "No items found in this query"
msgstr ""
msgstr "Nenhum item encontrado nesta consulta"
#: ejabberd_local:90 ejabberd_sm:863 mod_blocking:92 mod_blocking:110
#: mod_http_upload:513 mod_muc:482 mod_muc:534 mod_muc:556 mod_muc:580
#: mod_offline:303 mod_privacy:168 mod_privacy:285 mod_roster:207
msgid "No module is handling this query"
msgstr ""
msgstr "Nenhum módulo está processando esta consulta"
#: mod_pubsub:1541
msgid "No node specified"
msgstr ""
msgstr "Nenhum nó especificado"
#: mod_pubsub:1426
msgid "No pending subscriptions found"
msgstr ""
msgstr "Não foram encontradas subscrições"
#: mod_privacy:201 mod_privacy:295 mod_privacy:311 mod_privacy:344
msgid "No privacy list with this name found"
msgstr ""
msgstr "Nenhuma lista de privacidade encontrada com este nome"
#: mod_private:96
msgid "No private data found in this query"
msgstr ""
msgstr "Nenhum dado privado encontrado nesta consulta"
#: mod_configure:869 mod_configure:908 mod_configure:1222 mod_configure:1254
#: mod_configure:1275 mod_configure:1314 mod_configure:1345 mod_configure:1377
@@ -1131,15 +1131,15 @@ msgstr "Nó não encontrado"
#: mod_disco:252 mod_vcard:265
msgid "No services available"
msgstr ""
msgstr "Não há serviços disponíveis"
#: mod_stats:101
msgid "No statistics found for this item"
msgstr ""
msgstr "Não foram encontradas estatísticas para este item"
#: nodetree_dag:72 nodetree_tree:181 nodetree_tree_sql:255
msgid "Node already exists"
msgstr ""
msgstr "Nó já existe"
#: nodetree_tree_sql:99
#, fuzzy
@@ -1159,7 +1159,7 @@ msgstr "Nó ~p"
#: mod_vcard:385
msgid "Nodeprep has failed"
msgstr ""
msgstr "Processo de identificação de nó falhou (nodeprep)"
#: ejabberd_web_admin:1837
msgid "Nodes"
@@ -1176,7 +1176,7 @@ msgstr "Não encontrado"
#: mod_disco:296 mod_disco:370 mod_last:159
msgid "Not subscribed"
msgstr ""
msgstr "Não subscrito"
#: mod_muc_log:483
msgid "November"
@@ -1227,11 +1227,11 @@ msgstr "Usuários online"
#: mod_carboncopy:141
msgid "Only <enable/> or <disable/> tags are allowed"
msgstr ""
msgstr "Apenas tags <enable/> ou <disable/> são permitidas"
#: mod_privacy:154
msgid "Only <list/> element is allowed in this query"
msgstr ""
msgstr "Apenas elemento <list/> é permitido nesta consulta"
#: mod_mam:379
msgid "Only members may query archives of this room"
@@ -1255,11 +1255,11 @@ msgstr "Somente moderadores podem aprovar requisições de voz"
#: mod_muc_room:424 mod_muc_room:792 mod_muc_room:3989
msgid "Only occupants are allowed to send messages to the conference"
msgstr "Somente os ocupantes podem enviar mensagens à sala"
msgstr "Somente os ocupantes podem enviar mensagens à sala de conferência"
#: mod_muc_room:457
msgid "Only occupants are allowed to send queries to the conference"
msgstr "Somente os ocupantes podem enviar consultas à sala"
msgstr "Somente os ocupantes podem enviar consultas à sala de conferência"
#: mod_muc:422
msgid "Only service administrators are allowed to send service messages"
@@ -1282,11 +1282,11 @@ msgstr "Departamento/Unidade"
#: mod_configure:508
msgid "Outgoing s2s Connections"
msgstr "Conexões que partam de s2s"
msgstr "Conexões s2s de Saída"
#: ejabberd_web_admin:1583
msgid "Outgoing s2s Connections:"
msgstr "Conexões que partem de s2s"
msgstr "Conexões s2s de Saída"
#: mod_muc_room:3023 mod_muc_room:3067 mod_muc_room:3697 mod_pubsub:1302
#: mod_pubsub:1394 mod_pubsub:1553 mod_pubsub:2118 mod_pubsub:2184
@@ -1300,11 +1300,11 @@ msgstr "Pacote"
#: mod_irc:578
msgid "Parse error"
msgstr ""
msgstr "Erro de análise de dados"
#: mod_configure:1299 mod_configure:1468 mod_configure:1513
msgid "Parse failed"
msgstr ""
msgstr "Análise de dados falhou"
#: ejabberd_oauth:431 ejabberd_web_admin:1435 mod_configure:1126
#: mod_configure:1173 mod_configure:1602 mod_configure:1781 mod_muc_log:1036
@@ -1384,7 +1384,7 @@ msgstr "Porta ~b"
#: mod_roster:173
msgid "Possessing 'ask' attribute is not allowed by RFC6121"
msgstr ""
msgstr "Possuir atributo 'ask' não é permitido pela RFC6121"
#: ejabberd_web_admin:2464
msgid "Protocol"
@@ -1400,16 +1400,16 @@ msgstr "Publicação de Tópico"
#: node_dag:81
msgid "Publishing items to collection node is not allowed"
msgstr ""
msgstr "Publicar items em um nó de coleção não é permitido"
#: mod_muc_room:462
msgid "Queries to the conference members are not allowed in this room"
msgstr "Nesta sala não se permite consultas aos membros da sala"
msgstr "Nesta sala de conferência, consultas aos membros não são permitidas"
#: mod_blocking:85 mod_disco:325 mod_disco:393 mod_offline:270 mod_privacy:146
#: mod_private:118 mod_roster:163 mod_sic:90
msgid "Query to another users is forbidden"
msgstr ""
msgstr "Consultar a outro usuário é proibido"
#: mod_configure:889
msgid "RAM and disc copy"
@@ -1540,7 +1540,7 @@ msgstr "Lista de contatos"
#: mod_roster:334
msgid "Roster module has failed"
msgstr ""
msgstr "O módulo Roster falhou"
#: mod_roster:968
msgid "Roster of "
@@ -1556,7 +1556,7 @@ msgstr "Nós em execução"
#: xmpp_stream_in:541 xmpp_stream_in:549
msgid "SASL negotiation is not allowed in this state"
msgstr ""
msgstr "Negociação SASL não é permitida neste estado"
#: mod_muc_log:468
msgid "Saturday"
@@ -1564,12 +1564,12 @@ msgstr "Sábado"
#: mod_irc:582
msgid "Scan error"
msgstr ""
msgstr "Erro de escaneamento"
#: mod_configure:1303 mod_configure:1472 mod_configure:1517
#, fuzzy
msgid "Scan failed"
msgstr "O CAPTCHA é inválido."
msgstr "O escaneamento falhou"
#: ejabberd_web_admin:2282
msgid "Script check"
@@ -1605,11 +1605,11 @@ msgstr "Setembro"
#: mod_irc_connection:648
msgid "Server Connect Failed"
msgstr ""
msgstr "Conexão ao servidor falhou"
#: ejabberd_s2s:369
msgid "Server connections to local subdomains are forbidden"
msgstr ""
msgstr "Conexões de servidor a subdomínios locais estão proibidas"
#: mod_irc:842
msgid "Server ~b"
@@ -1724,7 +1724,7 @@ msgstr "Subscrição"
#: mod_muc_room:3708
msgid "Subscriptions are not allowed"
msgstr ""
msgstr "Subscrições não estão permitidas"
#: mod_muc_log:469
msgid "Sunday"
@@ -1748,15 +1748,15 @@ msgstr "A verificação do CAPTCHA falhou"
#: mod_muc_room:302
msgid "The feature requested is not supported by the conference"
msgstr ""
msgstr "A funcionalidade solicitada não é suportada pela sala de conferência"
#: mod_register:308 mod_register:366
msgid "The password contains unacceptable characters"
msgstr ""
msgstr "A senha contém caracteres proibidos"
#: mod_register:311 mod_register:370
msgid "The password is too weak"
msgstr "Senha considerada fraca'"
msgstr "Senha considerada muito fraca"
#: mod_register_web:141
msgid "The password of your Jabber account was successfully changed."
@@ -1764,17 +1764,19 @@ msgstr "A senha da sua conta Jabber foi mudada com sucesso."
#: mod_register:160 mod_vcard:219
msgid "The query is only allowed from local users"
msgstr ""
msgstr "Esta consulta só é permitida a partir de usuários locais"
#: mod_roster:203
msgid "The query must not contain <item/> elements"
msgstr ""
msgstr "A consulta não pode conter elementos <item/>"
#: mod_privacy:280
msgid ""
"The stanza MUST contain only one <active/> element, one <default/> element, "
"or one <list/> element"
msgstr ""
"A instância DEVE conter apenas um elemento <active/>, um elemento <default/>, "
"ou um elemento <list/>"
#: mod_register_web:146
msgid "There was an error changing the password: "
@@ -1830,7 +1832,7 @@ msgstr "Para"
#: mod_register:215
msgid "To register, visit ~s"
msgstr ""
msgstr "Para registrar, visite ~s"
#: mod_configure:709
msgid "To ~s"
@@ -1838,19 +1840,19 @@ msgstr "Para ~s"
#: ejabberd_oauth:439
msgid "Token TTL"
msgstr ""
msgstr "Token TTL"
#: xmpp_stream_in:463
msgid "Too long value of 'xml:lang' attribute"
msgstr ""
msgstr "Valor do atributo 'xml:lang' é demasiado longo"
#: mod_muc_room:2541 mod_muc_room:3081
msgid "Too many <item/> elements"
msgstr ""
msgstr "Número excessivo de elementos <item/>"
#: mod_privacy:164
msgid "Too many <list/> elements"
msgstr ""
msgstr "Número excessivo de elementos <list/>"
#: mod_muc_room:1924 mod_register:240
msgid "Too many CAPTCHA requests"
@@ -1859,20 +1861,20 @@ msgstr "Número excessivo de requisições para o CAPTCHA"
#: mod_proxy65_service:223
#, fuzzy
msgid "Too many active bytestreams"
msgstr "número excessivo de instâncias sem confirmação"
msgstr "Número excessivo de bytestreams ativos"
#: mod_stream_mgmt:205
msgid "Too many unacked stanzas"
msgstr "número excessivo de instâncias sem confirmação"
msgstr "Número excessivo de instâncias sem confirmação"
#: mod_muc_room:1802
#, fuzzy
msgid "Too many users in this conference"
msgstr "Requisições de voz estão desabilitadas nesta conferência"
msgstr "Número excessivo de usuários nesta sala de conferência"
#: mod_register:355
msgid "Too many users registered"
msgstr ""
msgstr "Número excessivo de usuários registrados"
#: mod_muc_admin:368
msgid "Total rooms"
@@ -1908,7 +1910,7 @@ msgstr "Impossível gerar um CAPTCHA"
#: ejabberd_service:120
msgid "Unable to register route on existing local domain"
msgstr ""
msgstr "Não foi possível registrar rota no domínio local existente"
#: ejabberd_web_admin:209 ejabberd_web_admin:221 ejabberd_web_admin:241
#: ejabberd_web_admin:253
@@ -1917,7 +1919,7 @@ msgstr "Não Autorizado"
#: mod_announce:485 mod_configure:830 mod_configure:1758
msgid "Unexpected action"
msgstr ""
msgstr "Ação inesperada"
#: mod_register_web:488
msgid "Unregister"
@@ -1929,11 +1931,11 @@ msgstr "Deletar conta Jabber"
#: mod_mam:526
msgid "Unsupported <index/> element"
msgstr ""
msgstr "Elemento <index/> não suportado"
#: mod_mix:119
msgid "Unsupported MIX query"
msgstr ""
msgstr "Consula MIX não suportada"
#: ejabberd_web_admin:1872 ejabberd_web_admin:2285
msgid "Update"
@@ -1979,7 +1981,7 @@ msgstr "Usuário"
#: ejabberd_oauth:428
msgid "User (jid)"
msgstr ""
msgstr "Usuário (jid)"
#: mod_configure:308 mod_configure:505
msgid "User Management"
@@ -1987,11 +1989,11 @@ msgstr "Gerenciamento de Usuários"
#: mod_register:345
msgid "User already exists"
msgstr ""
msgstr "Usuário já existe"
#: mod_echo:138
msgid "User part of JID in 'from' is empty"
msgstr ""
msgstr "Parte do usuário do JID em 'from' está vazia"
#: ejabberd_sm:193 ejabberd_sm:662 ejabberd_sm:687 mod_sic:106
#, fuzzy
@@ -2000,7 +2002,7 @@ msgstr "Nó não encontrado"
#: mod_stream_mgmt:561 mod_stream_mgmt:583
msgid "User session terminated"
msgstr ""
msgstr "Sessão de usuário terminada"
#: ejabberd_web_admin:1700
msgid "User ~s"
@@ -2029,7 +2031,7 @@ msgstr "Validar"
#: mod_carboncopy:144 mod_irc:345 mod_muc_room:3662 mod_muc_room:3802
#: mod_pubsub:895 mod_push:249
msgid "Value 'get' of 'type' attribute is not allowed"
msgstr ""
msgstr "Valor 'get' não permitido para atributo 'type'"
#: mod_disco:159 mod_disco:175 mod_disco:279 mod_disco:346 mod_irc:270
#: mod_irc:285 mod_irc:339 mod_last:118 mod_last:140 mod_muc:479 mod_muc:504
@@ -2038,20 +2040,20 @@ msgstr ""
#: mod_pubsub:821 mod_pubsub:839 mod_pubsub:877 mod_sic:81 mod_sic:93
#: mod_stats:55 mod_time:62 mod_vcard:198 mod_vcard:236 mod_version:62
msgid "Value 'set' of 'type' attribute is not allowed"
msgstr ""
msgstr "Valor 'set' não permitido para atributo 'type'"
#: pubsub_subscription:237 pubsub_subscription_sql:202
msgid "Value of '~s' should be boolean"
msgstr ""
msgstr "Value de '~s' deveria ser um booleano"
#: pubsub_subscription:215 pubsub_subscription_sql:180
msgid "Value of '~s' should be datetime string"
msgstr ""
msgstr "Valor de '~s' deveria ser data e hora"
#: pubsub_subscription:209 pubsub_subscription:227 pubsub_subscription_sql:174
#: pubsub_subscription_sql:192
msgid "Value of '~s' should be integer"
msgstr ""
msgstr "Valor de '~s' deveria ser um inteiro"
#: ejabberd_web_admin:950
msgid "Virtual Hosts"
@@ -2071,7 +2073,7 @@ msgstr "Requisição de voz"
#: mod_muc_room:885
msgid "Voice requests are disabled in this conference"
msgstr "Requisições de voz estão desabilitadas nesta conferência"
msgstr "Requisições de voz estão desabilitadas nesta sala de conferência"
#: mod_muc_log:465
msgid "Wednesday"
@@ -2087,7 +2089,7 @@ msgstr "Você foi banido desta sala"
#: mod_muc_room:1811
msgid "You have joined too many conferences"
msgstr ""
msgstr "Você entrou em um número excessivo de salas de conferência"
#: mod_muc:777
msgid "You must fill in field \"Nickname\" in the form"
@@ -2379,7 +2381,7 @@ msgstr "~s's Fila de Mensagens Offline"
#~ msgstr "Preencha campos para buscar usuários Jabber que concordem"
#~ msgid "Outgoing s2s Servers:"
#~ msgstr "Servidores que partem de s2s"
#~ msgstr "Servidores s2s de Saída"
#~ msgid "Delete"
#~ msgstr "Eliminar"
+15 -21
View File
@@ -19,24 +19,24 @@
%%%----------------------------------------------------------------------
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager",
{tag, {if_version_above, "17", "3.4.2", "3.2.1"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.11"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.13"}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.22"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.11"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.30"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.1.21"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.14"}}},
{tag, {if_version_above, "17", "3.6.5", "3.2.1"}}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.13"}}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.16"}}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.25"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.14"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.34"}}},
{xmpp, ".*", {git, "https://github.com/processone/xmpp", {tag, "1.2.5"}}},
{fast_yaml, ".*", {git, "https://github.com/processone/fast_yaml", {tag, "1.0.17"}}},
{jiffy, ".*", {git, "https://github.com/davisp/jiffy", {tag, "0.14.8"}}},
{p1_oauth2, ".*", {git, "https://github.com/processone/p1_oauth2", {tag, "0.6.3"}}},
{jose, ".*", {git, "https://github.com/potatosalad/erlang-jose", {tag, "1.8.4"}}},
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.5"}}},
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.22"}}}},
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.23"}}}},
{eimp, ".*", {git, "https://github.com/processone/eimp", {tag, "1.0.8"}}},
{if_var_true, stun, {stun, ".*", {git, "https://github.com/processone/stun", {tag, "1.0.25"}}}},
{if_var_true, sip, {esip, ".*", {git, "https://github.com/processone/esip", {tag, "1.0.26"}}}},
{if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
{tag, "1.0.5"}}}},
{tag, "1.0.7"}}}},
{if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
{tag, "1.1.5"}}}},
{tag, "1.1.6"}}}},
{if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
{tag, "1.1.6"}}}},
{if_var_true, pam, {epam, ".*", {git, "https://github.com/processone/epam",
@@ -52,13 +52,11 @@
{if_not_rebar3, {if_var_true, elixir, {rebar_elixir_plugin, ".*",
{git, "https://github.com/processone/rebar_elixir_plugin", "0.1.0"}}}},
{if_var_true, iconv, {iconv, ".*", {git, "https://github.com/processone/iconv",
{tag, "1.0.7"}}}},
{tag, "1.0.10"}}}},
{if_var_true, tools, {luerl, ".*", {git, "https://github.com/rvirding/luerl",
{tag, "v0.3"}}}},
{if_var_true, tools, {meck, "0.8.*", {git, "https://github.com/eproxus/meck",
{tag, "0.8.4"}}}},
{if_var_true, tools, {moka, ".*", {git, "https://github.com/processone/moka",
{tag, "1.0.5c"}}}},
{if_var_true, redis, {eredis, ".*", {git, "https://github.com/wooga/eredis",
{tag, "v1.0.8"}}}}]}.
@@ -96,14 +94,13 @@
{if_var_true, roster_gateway_workaround, {d, 'ROSTER_GATWAY_WORKAROUND'}},
{if_var_match, db_type, mssql, {d, 'mssql'}},
{if_var_true, elixir, {d, 'ELIXIR_ENABLED'}},
{if_var_true, erlang_deprecated_types, {d, 'ERL_DEPRECATED_TYPES'}},
{if_have_fun, {crypto, strong_rand_bytes, 1}, {d, 'STRONG_RAND_BYTES'}},
{if_have_fun, {rand, uniform, 1}, {d, 'RAND_UNIFORM'}},
{if_have_fun, {gb_sets, iterator_from, 2}, {d, 'GB_SETS_ITERATOR_FROM'}},
{if_have_fun, {public_key, short_name_hash, 1}, {d, 'SHORT_NAME_HASH'}},
{if_var_true, new_sql_schema, {d, 'NEW_SQL_SCHEMA'}},
{if_var_true, hipe, native},
{src_dirs, [asn1, src,
{src_dirs, [src,
{if_var_true, tools, tools},
{if_var_true, elixir, include}]}]}.
@@ -165,9 +162,6 @@
{if_var_true, zlib, {"ezlib", []}},
{if_var_true, iconv, {"iconv", []}}]}.
{port_env, [{"CFLAGS", "-g -O2 -Wall"}]}.
{port_specs, [{"priv/lib/jid.so", ["c_src/jid.c"]}]}.
%% Local Variables:
%% mode: erlang
%% End:
-10
View File
@@ -329,16 +329,6 @@ CREATE TABLE muc_room_subscribers (
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers(host, jid);
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers(host, room, jid);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
server_host text NOT NULL,
data text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom (jid, host);
CREATE TABLE motd (
username text NOT NULL,
server_host text NOT NULL,
-9
View File
@@ -302,15 +302,6 @@ CREATE TABLE muc_room_subscribers (
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers(host, jid);
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers(host, room, jid);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
data text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom (jid, host);
CREATE TABLE motd (
username text PRIMARY KEY,
xml text,
+4 -14
View File
@@ -72,16 +72,6 @@ CREATE TABLE [dbo].[caps_features] (
CREATE CLUSTERED INDEX [caps_features_node_subnode] ON [caps_features] (node, subnode)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[irc_custom] (
[jid] [varchar] (255) NOT NULL,
[host] [varchar] (255) NOT NULL,
[data] [text] NOT NULL,
[created_at] [datetime] NOT NULL DEFAULT GETDATE()
) TEXTIMAGE_ON [PRIMARY];
CREATE UNIQUE CLUSTERED INDEX [irc_custom_jid_host] ON [irc_custom] (jid, host)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE TABLE [dbo].[last] (
[username] [varchar] (250) NOT NULL,
[seconds] [text] NOT NULL,
@@ -144,9 +134,9 @@ CREATE TABLE [dbo].[muc_online_users] (
node text NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX [muc_online_users_i] ON [muc_online_users] (username, server, resource, name, host)
CREATE UNIQUE 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);
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].[muc_room_subscribers] (
@@ -539,7 +529,7 @@ CREATE TABLE [dbo].[bosh] (
(
[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,
@@ -565,5 +555,5 @@ CREATE TABLE [dbo].[push_session] (
CREATE UNIQUE CLUSTERED INDEX [i_push_usn] ON [push_session] (username, service, node)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
CREATE UNIQUE CLUSTERED INDEX [i_push_ut] ON [push_session] (username, timestamp)
CREATE UNIQUE INDEX [i_push_ut] ON [push_session] (username, timestamp)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON);
+3 -13
View File
@@ -90,7 +90,7 @@ CREATE INDEX i_sr_user_sh_grp ON sr_user(server_host(191), grp);
CREATE TABLE spool (
username varchar(191) NOT NULL,
server_host text NOT NULL,
xml BLOB NOT NULL,
xml mediumtext NOT NULL,
seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -104,8 +104,8 @@ CREATE TABLE archive (
timestamp BIGINT UNSIGNED NOT NULL,
peer varchar(191) NOT NULL,
bare_peer varchar(191) NOT NULL,
xml text NOT NULL,
txt text,
xml mediumtext NOT NULL,
txt mediumtext,
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
kind varchar(10),
nick varchar(191),
@@ -345,16 +345,6 @@ CREATE TABLE muc_room_subscribers (
CREATE INDEX i_muc_room_subscribers_host_jid USING BTREE ON muc_room_subscribers(host, jid);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
server_host text NOT NULL,
data text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_irc_custom_jid_host USING BTREE ON irc_custom(jid(75), host(75));
CREATE TABLE motd (
username varchar(191) NOT NULL,
server_host text NOT NULL,
+3 -12
View File
@@ -80,7 +80,7 @@ CREATE INDEX i_sr_user_grp ON sr_user(grp);
CREATE TABLE spool (
username varchar(191) NOT NULL,
xml BLOB NOT NULL,
xml mediumtext NOT NULL,
seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@@ -93,8 +93,8 @@ CREATE TABLE archive (
timestamp BIGINT UNSIGNED NOT NULL,
peer varchar(191) NOT NULL,
bare_peer varchar(191) NOT NULL,
xml text NOT NULL,
txt text,
xml mediumtext NOT NULL,
txt mediumtext,
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
kind varchar(10),
nick varchar(191),
@@ -318,15 +318,6 @@ CREATE TABLE muc_room_subscribers (
CREATE INDEX i_muc_room_subscribers_host_jid USING BTREE ON muc_room_subscribers(host, jid);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
data text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE UNIQUE INDEX i_irc_custom_jid_host USING BTREE ON irc_custom(jid(75), host(75));
CREATE TABLE motd (
username varchar(191) PRIMARY KEY,
xml text,
-13
View File
@@ -144,9 +144,6 @@
-- ALTER TABLE muc_online_users ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- ALTER TABLE muc_online_users ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE irc_custom ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- ALTER TABLE irc_custom ALTER COLUMN server_host DROP DEFAULT;
-- ALTER TABLE motd ADD COLUMN server_host text NOT NULL DEFAULT '<HOST>';
-- ALTER TABLE motd DROP CONSTRAINT motd_pkey;
-- ALTER TABLE motd ADD PRIMARY KEY (server_host, username);
@@ -498,16 +495,6 @@ CREATE TABLE muc_room_subscribers (
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
server_host text NOT NULL,
data text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom USING btree (jid, host);
CREATE TABLE motd (
username text NOT NULL,
server_host text NOT NULL,
-9
View File
@@ -320,15 +320,6 @@ CREATE TABLE muc_room_subscribers (
CREATE INDEX i_muc_room_subscribers_host_jid ON muc_room_subscribers USING btree (host, jid);
CREATE UNIQUE INDEX i_muc_room_subscribers_host_room_jid ON muc_room_subscribers USING btree (host, room, jid);
CREATE TABLE irc_custom (
jid text NOT NULL,
host text NOT NULL,
data text NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX i_irc_custom_jid_host ON irc_custom USING btree (jid, host);
CREATE TABLE motd (
username text PRIMARY KEY,
xml text,
+24 -13
View File
@@ -36,14 +36,13 @@
any_rules_allowed/3, transform_options/1, opt_type/1,
acl_rule_matches/3, acl_rule_verify/1, access_matches/3,
transform_access_rules_config/1,
parse_ip_netmask/1,
parse_ip_netmask/1, ip_matches_mask/3,
access_rules_validator/1, shaper_rules_validator/1,
normalize_spec/1, resolve_access/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jid.hrl").
@@ -195,7 +194,7 @@ add_access(Host, Access, Rules) ->
-spec load_from_config() -> ok.
load_from_config() ->
Hosts = [global|?MYHOSTS],
Hosts = [global|ejabberd_config:get_myhosts()],
lists:foreach(
fun(Host) ->
ACLs = ejabberd_config:get_option(
@@ -313,7 +312,7 @@ normalize_spec(Spec) ->
{ok, Net, Mask} ->
{ip, {Net, Mask}};
error ->
?INFO_MSG("Invalid network address: ~p", [S]),
?WARNING_MSG("Invalid network address: ~p", [S]),
none
end;
BadVal ->
@@ -447,13 +446,13 @@ acl_rule_matches({acl, Name}, Data, Host) ->
RawACLs = lists:map(fun(#acl{aclspec = R}) -> R end, ACLs),
any_acl_rules_matches(RawACLs, Data, Host);
acl_rule_matches({ip, {Net, Mask}}, #{ip := {IP, _Port}}, _Host) ->
is_ip_match(IP, Net, Mask);
ip_matches_mask(IP, Net, Mask);
acl_rule_matches({ip, {Net, Mask}}, #{ip := IP}, _Host) ->
is_ip_match(IP, Net, Mask);
ip_matches_mask(IP, Net, Mask);
acl_rule_matches({user, {U, S}}, #{usr := {U, S, _}}, _Host) ->
true;
acl_rule_matches({user, U}, #{usr := {U, S, _}}, _Host) ->
lists:member(S, ?MYHOSTS);
lists:member(S, ejabberd_config:get_myhosts());
acl_rule_matches({server, S}, #{usr := {_, S, _}}, _Host) ->
true;
acl_rule_matches({resource, R}, #{usr := {_, _, R}}, _Host) ->
@@ -467,7 +466,7 @@ acl_rule_matches({shared_group, G}, #{usr := {U, S, _}}, Host) ->
acl_rule_matches({user_regexp, {UR, S}}, #{usr := {U, S, _}}, _Host) ->
is_regexp_match(U, UR);
acl_rule_matches({user_regexp, UR}, #{usr := {U, S, _}}, _Host) ->
lists:member(S, ?MYHOSTS) andalso is_regexp_match(U, UR);
lists:member(S, ejabberd_config:get_myhosts()) andalso is_regexp_match(U, UR);
acl_rule_matches({server_regexp, SR}, #{usr := {_, S, _}}, _Host) ->
is_regexp_match(S, SR);
acl_rule_matches({resource_regexp, RR}, #{usr := {_, _, R}}, _Host) ->
@@ -477,7 +476,7 @@ acl_rule_matches({node_regexp, {UR, SR}}, #{usr := {U, S, _}}, _Host) ->
acl_rule_matches({user_glob, {UR, S}}, #{usr := {U, S, _}}, _Host) ->
is_glob_match(U, UR);
acl_rule_matches({user_glob, UR}, #{usr := {U, S, _}}, _Host) ->
lists:member(S, ?MYHOSTS) andalso is_glob_match(U, UR);
lists:member(S, ejabberd_config:get_myhosts()) andalso is_glob_match(U, UR);
acl_rule_matches({server_glob, SR}, #{usr := {_, S, _}}, _Host) ->
is_glob_match(S, SR);
acl_rule_matches({resource_glob, RR}, #{usr := {_, _, R}}, _Host) ->
@@ -549,18 +548,30 @@ is_glob_match(String, Glob) ->
is_regexp_match(String,
ejabberd_regexp:sh_to_awk(Glob)).
is_ip_match({_, _, _, _} = IP, {_, _, _, _} = Net, Mask) ->
ip_matches_mask({_, _, _, _} = IP, {_, _, _, _} = Net, Mask) ->
IPInt = ip_to_integer(IP),
NetInt = ip_to_integer(Net),
M = bnot (1 bsl (32 - Mask) - 1),
IPInt band M =:= NetInt band M;
is_ip_match({_, _, _, _, _, _, _, _} = IP,
{_, _, _, _, _, _, _, _} = Net, Mask) ->
ip_matches_mask({_, _, _, _, _, _, _, _} = IP,
{_, _, _, _, _, _, _, _} = Net, Mask) ->
IPInt = ip_to_integer(IP),
NetInt = ip_to_integer(Net),
M = bnot (1 bsl (128 - Mask) - 1),
IPInt band M =:= NetInt band M;
is_ip_match(_, _, _) ->
ip_matches_mask({_, _, _, _} = IP,
{0, 0, 0, 0, 0, 16#FFFF, _, _} = Net, Mask) ->
IPInt = ip_to_integer({0, 0, 0, 0, 0, 16#FFFF, 0, 0}) + ip_to_integer(IP),
NetInt = ip_to_integer(Net),
M = bnot (1 bsl (128 - Mask) - 1),
IPInt band M =:= NetInt band M;
ip_matches_mask({0, 0, 0, 0, 0, 16#FFFF, _, _} = IP,
{_, _, _, _} = Net, Mask) ->
IPInt = ip_to_integer(IP) - ip_to_integer({0, 0, 0, 0, 0, 16#FFFF, 0, 0}),
NetInt = ip_to_integer(Net),
M = bnot (1 bsl (32 - Mask) - 1),
IPInt band M =:= NetInt band M;
ip_matches_mask(_, _, _) ->
false.
ip_to_integer({IP1, IP2, IP3, IP4}) ->
-1
View File
@@ -14,7 +14,6 @@
%% 3. tls-sni-01: https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-7.4
%% 4. (?) oob-01: https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-7.5
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("ejabberd_http.hrl").
-230
View File
@@ -1,230 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Cyrus SASL-like library
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(cyrsasl).
-author('alexey@process-one.net').
-behaviour(gen_server).
-export([start_link/0, register_mechanism/3, listmech/1,
server_new/7, server_start/3, server_step/2,
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").
-record(state, {}).
-record(sasl_mechanism,
{mechanism = <<"">> :: mechanism() | '$1',
module :: atom(),
password_type = plain :: password_type() | '$2'}).
-type(mechanism() :: binary()).
-type(mechanisms() :: [mechanism(),...]).
-type(password_type() :: plain | digest | scram).
-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,
myname,
realm,
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()) -> sasl_return().
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
init([]) ->
ets:new(sasl_mechanism,
[named_table, public,
{keypos, #sasl_mechanism.mechanism}]),
cyrsasl_plain:start([]),
cyrsasl_digest:start([]),
cyrsasl_scram:start([]),
cyrsasl_anonymous:start([]),
cyrsasl_oauth:start([]),
{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) ->
ets:insert(sasl_mechanism,
#sasl_mechanism{mechanism = Mechanism, module = Module,
password_type = PasswordType}).
check_credentials(_State, Props) ->
User = proplists:get_value(authzid, Props, <<>>),
case jid:nodeprep(User) of
error -> {error, nodeprep_failed};
<<"">> -> {error, empty_username};
_LUser -> ok
end.
-spec listmech(Host ::binary()) -> Mechanisms::mechanisms().
listmech(Host) ->
ets:select(sasl_mechanism,
[{#sasl_mechanism{mechanism = '$1',
password_type = '$2', _ = '_'},
case catch ejabberd_auth:store_type(Host) of
external -> [{'==', '$2', plain}];
scram -> [{'/=', '$2', digest}];
{'EXIT', {undef, [{Module, store_type, []} | _]}} ->
?WARNING_MSG("~p doesn't implement the function store_type/0",
[Module]),
[];
_Else -> []
end,
['$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,
realm = UserRealm, get_password = GetPassword,
check_password = CheckPassword,
check_password_digest = CheckPasswordDigest}.
-spec server_start(sasl_state(), mechanism(), binary()) -> sasl_return().
server_start(State, Mech, ClientIn) ->
case lists:member(Mech,
listmech(State#sasl_state.myname))
of
true ->
case ets:lookup(sasl_mechanism, Mech) of
[#sasl_mechanism{module = Module}] ->
{ok, MechState} =
Module:mech_new(State#sasl_state.myname,
State#sasl_state.get_password,
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, unsupported_mechanism, <<"">>}
end;
false -> {error, unsupported_mechanism, <<"">>}
end.
-spec server_step(sasl_state(), binary()) -> sasl_return().
server_step(State, ClientIn) ->
Module = State#sasl_state.mech_mod,
MechState = State#sasl_state.mech_state,
case Module:mech_step(MechState, ClientIn) of
{ok, Props} ->
case check_credentials(State, Props) of
ok -> {ok, Props};
{error, Error} -> {error, Error, <<"">>}
end;
{ok, Props, ServerOut} ->
case check_credentials(State, Props) of
ok -> {ok, Props, ServerOut};
{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, <<"">>}
end.
-spec get_mech(sasl_state()) -> binary().
get_mech(#sasl_state{mech_name = Mech}) ->
Mech.
-50
View File
@@ -1,50 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_anonymous.erl
%%% Author : Magnus Henoch <henoch@dtek.chalmers.se>
%%% Purpose : ANONYMOUS SASL mechanism
%%% See http://www.ietf.org/internet-drafts/draft-ietf-sasl-anon-05.txt
%%% Created : 23 Aug 2005 by Magnus Henoch <henoch@dtek.chalmers.se>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(cyrsasl_anonymous).
-protocol({xep, 175, '1.2'}).
-export([start/1, stop/0, mech_new/4, mech_step/2]).
-behaviour(cyrsasl).
-record(state, {server = <<"">> :: binary()}).
start(_Opts) ->
cyrsasl:register_mechanism(<<"ANONYMOUS">>, ?MODULE, plain).
stop() -> ok.
mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
{ok, #state{server = Host}}.
mech_step(#state{}, _ClientIn) ->
User = iolist_to_binary([randoms:get_string(),
integer_to_binary(p1_time_compat:unique_integer([positive]))]),
{ok, [{username, User},
{authzid, User},
{auth_module, ejabberd_auth_anonymous}]}.
-271
View File
@@ -1,271 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_digest.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : DIGEST-MD5 SASL mechanism
%%% Created : 11 Mar 2003 by Alexey Shchepin <alexey@sevcom.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(cyrsasl_digest).
-behaviour(ejabberd_config).
-author('alexey@sevcom.net').
-export([start/1, stop/0, mech_new/4, mech_step/2,
parse/1, format_error/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-behaviour(cyrsasl).
-type get_password_fun() :: fun((binary()) -> {false, any()} |
{binary(), atom()}).
-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 :: get_password_fun(),
check_password :: check_password_fun(),
auth_module :: atom(),
host = <<"">> :: binary(),
hostfqdn = [] :: [binary()]}).
start(_Opts) ->
Fqdn = get_local_fqdn(),
?DEBUG("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,
#state{step = 1, nonce = randoms:get_string(),
host = Host, hostfqdn = get_local_fqdn(),
get_password = GetPassword,
check_password = CheckPasswordDigest}}.
mech_step(#state{step = 1, nonce = Nonce} = State, _) ->
{continue,
<<"nonce=\"", Nonce/binary,
"\",qop=\"auth\",charset=utf-8,algorithm=md5-sess">>,
State#state{step = 3}};
mech_step(#state{step = 3, nonce = Nonce} = State,
ClientIn) ->
case parse(ClientIn) of
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,
State#state.hostfqdn)
of
false ->
?DEBUG("User login not authorized because digest-uri "
"seems invalid: ~p (checking for Host "
"~p, FQDN ~p)",
[DigestURI, State#state.host, State#state.hostfqdn]),
{error, invalid_digest_uri, UserName};
true ->
AuthzId = proplists:get_value(<<"authzid">>, KeyVals, <<>>),
case (State#state.get_password)(UserName) of
{false, _} -> {error, not_authorized, UserName};
{Passwd, AuthModule} ->
case (State#state.check_password)(UserName, UserName, <<"">>,
proplists:get_value(<<"response">>, KeyVals, <<>>),
fun (PW) ->
response(KeyVals,
UserName,
PW,
Nonce,
AuthzId,
<<"AUTHENTICATE">>)
end)
of
{true, _} ->
RspAuth = response(KeyVals, UserName, Passwd, Nonce,
AuthzId, <<"">>),
{continue, <<"rspauth=", RspAuth/binary>>,
State#state{step = 5, auth_module = AuthModule,
username = UserName,
authzid = AuthzId}};
false -> {error, not_authorized, UserName};
{false, _} -> {error, not_authorized, UserName}
end
end
end
end;
mech_step(#state{step = 5, auth_module = AuthModule,
username = UserName, authzid = AuthzId},
<<"">>) ->
{ok,
[{username, UserName}, {authzid, case AuthzId of
<<"">> -> UserName;
_ -> AuthzId
end
},
{auth_module, AuthModule}]};
mech_step(A, B) ->
?DEBUG("SASL DIGEST: A ~p B ~p", [A, B]),
{error, unexpected_response}.
parse(S) -> parse1(binary_to_list(S), "", []).
parse1([$= | Cs], S, Ts) ->
parse2(Cs, lists:reverse(S), "", Ts);
parse1([$, | Cs], [], Ts) -> parse1(Cs, [], Ts);
parse1([$\s | Cs], [], Ts) -> parse1(Cs, [], Ts);
parse1([C | Cs], S, Ts) -> parse1(Cs, [C | S], Ts);
parse1([], [], T) -> lists:reverse(T);
parse1([], _S, _T) -> bad.
parse2([$" | Cs], Key, Val, Ts) ->
parse3(Cs, Key, Val, Ts);
parse2([C | Cs], Key, Val, Ts) ->
parse4(Cs, Key, [C | Val], Ts);
parse2([], _, _, _) -> bad.
parse3([$" | Cs], Key, Val, Ts) ->
parse4(Cs, Key, Val, Ts);
parse3([$\\, C | Cs], Key, Val, Ts) ->
parse3(Cs, Key, [C | Val], Ts);
parse3([C | Cs], Key, Val, Ts) ->
parse3(Cs, Key, [C | Val], Ts);
parse3([], _, _, _) -> bad.
parse4([$, | Cs], Key, Val, Ts) ->
parse1(Cs, "", [{list_to_binary(Key), list_to_binary(lists:reverse(Val))} | Ts]);
parse4([$\s | Cs], Key, Val, Ts) ->
parse4(Cs, Key, Val, Ts);
parse4([C | Cs], Key, Val, Ts) ->
parse4(Cs, Key, [C | Val], Ts);
parse4([], Key, Val, Ts) ->
%% @doc Check if the digest-uri is valid.
%% RFC-2831 allows to provide the IP address in Host,
%% however ejabberd doesn't allow that.
%% If the service (for example jabber.example.org)
%% is provided by several hosts (being one of them server3.example.org),
%% then acceptable digest-uris would be:
%% xmpp/server3.example.org/jabber.example.org, xmpp/server3.example.org and
%% xmpp/jabber.example.org
%% The last version is not actually allowed by the RFC, but implemented by popular clients
parse1([], "", [{list_to_binary(Key), list_to_binary(lists:reverse(Val))} | Ts]).
is_digesturi_valid(DigestURICase, JabberDomain,
JabberFQDN) ->
DigestURI = stringprep:tolower(DigestURICase),
case catch str:tokens(DigestURI, <<"/">>) of
[<<"xmpp">>, Host] ->
IsHostFqdn = is_host_fqdn(Host, JabberFQDN),
(Host == JabberDomain) or IsHostFqdn;
[<<"xmpp">>, Host, ServName] ->
IsHostFqdn = is_host_fqdn(Host, JabberFQDN),
(ServName == JabberDomain) and IsHostFqdn;
_ ->
false
end.
is_host_fqdn(_Host, []) ->
false;
is_host_fqdn(Host, [Fqdn | _FqdnTail]) when Host == Fqdn ->
true;
is_host_fqdn(Host, [Fqdn | FqdnTail]) when Host /= Fqdn ->
is_host_fqdn(Host, FqdnTail).
get_local_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) ->
str:to_hexlist(S).
proplists_get_bin_value(Key, Pairs, Default) ->
case proplists:get_value(Key, Pairs, Default) of
L when is_list(L) ->
list_to_binary(L);
L2 ->
L2
end.
response(KeyVals, User, Passwd, Nonce, AuthzId,
A2Prefix) ->
Realm = proplists_get_bin_value(<<"realm">>, KeyVals, <<>>),
CNonce = proplists_get_bin_value(<<"cnonce">>, KeyVals, <<>>),
DigestURI = proplists_get_bin_value(<<"digest-uri">>, KeyVals, <<>>),
NC = proplists_get_bin_value(<<"nc">>, KeyVals, <<>>),
QOP = proplists_get_bin_value(<<"qop">>, KeyVals, <<>>),
MD5Hash = erlang:md5(<<User/binary, ":", Realm/binary, ":",
Passwd/binary>>),
A1 = case AuthzId of
<<"">> ->
<<MD5Hash/binary, ":", Nonce/binary, ":", CNonce/binary>>;
_ ->
<<MD5Hash/binary, ":", Nonce/binary, ":", CNonce/binary, ":",
AuthzId/binary>>
end,
A2 = case QOP of
<<"auth">> ->
<<A2Prefix/binary, ":", DigestURI/binary>>;
_ ->
<<A2Prefix/binary, ":", DigestURI/binary,
":00000000000000000000000000000000">>
end,
T = <<(hex((erlang:md5(A1))))/binary, ":", Nonce/binary,
":", NC/binary, ":", CNonce/binary, ":", QOP/binary,
":", (hex((erlang:md5(A2))))/binary>>,
hex((erlang:md5(T))).
-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].
-104
View File
@@ -1,104 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_oauth.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : X-OAUTH2 SASL mechanism
%%% Created : 17 Sep 2015 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(cyrsasl_oauth).
-author('alexey@process-one.net').
-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).
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}}.
mech_step(State, ClientIn) ->
case prepare(ClientIn) of
[AuthzId, User, Token] ->
case ejabberd_oauth:check_token(
User, State#state.host, [<<"sasl_auth">>], Token) of
true ->
{ok,
[{username, User}, {authzid, AuthzId},
{auth_module, ejabberd_oauth}]};
_ ->
{error, not_authorized, User}
end;
_ -> {error, parser_failed}
end.
prepare(ClientIn) ->
case parse(ClientIn) of
[<<"">>, UserMaybeDomain, Token] ->
case parse_domain(UserMaybeDomain) of
%% <NUL>login@domain<NUL>pwd
[User, _Domain] -> [User, User, Token];
%% <NUL>login<NUL>pwd
[User] -> [User, User, Token]
end;
%% login@domain<NUL>login<NUL>pwd
[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.
parse(S) -> parse1(binary_to_list(S), "", []).
parse1([0 | Cs], S, T) ->
parse1(Cs, "", [list_to_binary(lists:reverse(S)) | T]);
parse1([C | Cs], S, T) -> parse1(Cs, [C | S], T);
%parse1([], [], T) ->
% lists:reverse(T);
parse1([], S, T) ->
lists:reverse([list_to_binary(lists:reverse(S)) | T]).
parse_domain(S) -> parse_domain1(binary_to_list(S), "", []).
parse_domain1([$@ | Cs], S, T) ->
parse_domain1(Cs, "", [list_to_binary(lists:reverse(S)) | T]);
parse_domain1([C | Cs], S, T) ->
parse_domain1(Cs, [C | S], T);
parse_domain1([], S, T) ->
lists:reverse([list_to_binary(lists:reverse(S)) | T]).
-94
View File
@@ -1,94 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_plain.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : PLAIN SASL mechanism
%%% Created : 8 Mar 2003 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(cyrsasl_plain).
-author('alexey@process-one.net').
-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).
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}}.
mech_step(State, ClientIn) ->
case prepare(ClientIn) of
[AuthzId, User, Password] ->
case (State#state.check_password)(User, AuthzId, Password) of
{true, AuthModule} ->
{ok,
[{username, User}, {authzid, AuthzId},
{auth_module, AuthModule}]};
_ -> {error, not_authorized, User}
end;
_ -> {error, parser_failed}
end.
prepare(ClientIn) ->
case parse(ClientIn) of
[<<"">>, UserMaybeDomain, Password] ->
case parse_domain(UserMaybeDomain) of
%% <NUL>login@domain<NUL>pwd
[User, _Domain] -> [User, User, Password];
%% <NUL>login<NUL>pwd
[User] -> [User, User, Password]
end;
[AuthzId, User, Password] ->
case parse_domain(AuthzId) of
%% login@domain<NUL>login<NUL>pwd
[AuthzUser, _Domain] -> [AuthzUser, User, Password];
%% login<NUL>login<NUL>pwd
[AuthzUser] -> [AuthzUser, User, Password]
end;
_ -> error
end.
parse(S) ->
binary:split(S, <<0>>, [global]).
parse_domain(S) -> parse_domain1(binary_to_list(S), "", []).
parse_domain1([$@ | Cs], S, T) ->
parse_domain1(Cs, "", [list_to_binary(lists:reverse(S)) | T]);
parse_domain1([C | Cs], S, T) ->
parse_domain1(Cs, [C | S], T);
parse_domain1([], S, T) ->
lists:reverse([list_to_binary(lists:reverse(S)) | T]).
-249
View File
@@ -1,249 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : cyrsasl_scram.erl
%%% Author : Stephen Röttger <stephen.roettger@googlemail.com>
%%% Purpose : SASL SCRAM authentication
%%% Created : 7 Aug 2011 by Stephen Röttger <stephen.roettger@googlemail.com>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(cyrsasl_scram).
-author('stephen.roettger@googlemail.com').
-protocol({rfc, 5802}).
-export([start/1, stop/0, mech_new/4, mech_step/2, format_error/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-behaviour(cyrsasl).
-record(state,
{step = 2 :: 2 | 4,
stored_key = <<"">> :: binary(),
server_key = <<"">> :: binary(),
username = <<"">> :: binary(),
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}}.
mech_step(#state{step = 2} = State, ClientIn) ->
case re:split(ClientIn, <<",">>, [{return, binary}]) of
[_CBind, _AuthorizationIdentity, _UserNameAttribute, _ClientNonceAttribute, ExtensionAttribute | _]
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, bad_username};
UserName ->
case parse_attribute(ClientNonceAttribute) of
{$r, ClientNonce} ->
{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_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(Pass,
TempSalt,
?SCRAM_DEFAULT_ITERATION_COUNT),
{scram:stored_key(scram:client_key(SaltedPassword)),
scram:server_key(SaltedPassword),
TempSalt,
?SCRAM_DEFAULT_ITERATION_COUNT}
end,
ClientFirstMessageBare =
str:substr(ClientIn,
str:str(ClientIn, <<"n=">>)),
ServerNonce =
base64:encode(randoms:bytes(?NONCE_LENGTH)),
ServerFirstMessage =
iolist_to_binary(
["r=",
ClientNonce,
ServerNonce,
",", "s=",
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>>,
client_nonce = ClientNonce,
server_nonce = ServerNonce,
username = UserName}}
end;
_ -> {error, bad_attribute}
end
end
end;
_Else -> {error, parser_failed}
end;
mech_step(#state{step = 4} = State, ClientIn) ->
case str:tokens(ClientIn, <<",">>) of
[GS2ChannelBindingAttribute, NonceAttribute,
ClientProofAttribute] ->
case parse_attribute(GS2ChannelBindingAttribute) of
{$c, CVal} ->
ChannelBindingSupport = try binary:first(base64:decode(CVal))
catch _:badarg -> 0
end,
if (ChannelBindingSupport == $n)
or (ChannelBindingSupport == $y) ->
Nonce = <<(State#state.client_nonce)/binary,
(State#state.server_nonce)/binary>>,
case parse_attribute(NonceAttribute) of
{$r, CompareNonce} when CompareNonce == Nonce ->
case parse_attribute(ClientProofAttribute) of
{$p, ClientProofB64} ->
ClientProof = try base64:decode(ClientProofB64)
catch _:badarg -> <<>>
end,
AuthMessage = iolist_to_binary(
[State#state.auth_message,
",",
str:substr(ClientIn, 1,
str:str(ClientIn, <<",p=">>)
- 1)]),
ClientSignature =
scram:client_signature(State#state.stored_key,
AuthMessage),
ClientKey = scram:client_key(ClientProof,
ClientSignature),
CompareStoredKey = scram:stored_key(ClientKey),
if CompareStoredKey == State#state.stored_key ->
ServerSignature =
scram:server_signature(State#state.server_key,
AuthMessage),
{ok, [{username, State#state.username},
{auth_module, State#state.auth_module},
{authzid, State#state.username}],
<<"v=",
(base64:encode(ServerSignature))/binary>>};
true -> {error, not_authorized, State#state.username}
end;
_ -> {error, bad_attribute}
end;
{$r, _} -> {error, nonce_mismatch};
_ -> {error, bad_attribute}
end;
true -> {error, bad_channel_binding}
end;
_ -> {error, bad_attribute}
end;
_ -> {error, parser_failed}
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) ->
Pos = str:str(EscapedUsername, <<"=">>),
if Pos == 0 -> EscapedUsername;
true ->
Start = str:substr(EscapedUsername, 1, Pos - 1),
End = str:substr(EscapedUsername, Pos),
EndLen = byte_size(End),
if EndLen < 3 -> error;
true ->
case str:substr(End, 1, 3) of
<<"=2C">> ->
<<Start/binary, ",",
(unescape_username(str:substr(End, 4)))/binary>>;
<<"=3D">> ->
<<Start/binary, "=",
(unescape_username(str:substr(End, 4)))/binary>>;
_Else -> error
end
end
end.
is_alpha(Char) when Char >= $a, Char =< $z -> true;
is_alpha(Char) when Char >= $A, Char =< $Z -> true;
is_alpha(_) -> false.
+1 -1
View File
@@ -143,7 +143,7 @@ exit_or_halt(Reason, StartFlag) ->
end.
sleep(N) ->
timer:sleep(randoms:uniform(N)).
timer:sleep(p1_rand:uniform(N)).
get_module_file(App, Mod) ->
BaseName = atom_to_list(Mod),
+1 -1
View File
@@ -506,7 +506,7 @@ is_valid_command_name2(<<>>) ->
true;
is_valid_command_name2(<<K:8, Rest/binary>>) when (K >= $a andalso K =< $z)
orelse (K >= $0 andalso K =< $9)
orelse K == $_ ->
orelse K == $_ orelse K == $- ->
is_valid_command_name2(Rest);
is_valid_command_name2(_) ->
false.
+19 -15
View File
@@ -3,7 +3,8 @@
-behaviour(ejabberd_config).
%% ejabberdctl commands
-export([get_certificates/1,
-export([get_commands_spec/0,
get_certificates/1,
renew_certificates/0,
list_certificates/1,
revoke_certificate/1]).
@@ -19,7 +20,6 @@
terminate/2, code_change/3]).
-export([start_link/0, opt_type/1, register_certfiles/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("ejabberd_commands.hrl").
@@ -120,7 +120,7 @@ get_commands_spec() ->
args = [],
result = {certificates, string}},
#ejabberd_commands{name = list_certificates, tags = [acme],
desc = "Lists all curently handled certificates and "
desc = "Lists all currently handled certificates and "
"their respective domains in {plain|verbose} format",
module = ?MODULE, function = list_certificates,
args_desc = ["Whether to print the whole certificate "
@@ -151,7 +151,8 @@ get_certificates(Domains) ->
throw:Throw ->
Throw;
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
{error, get_certificates}
end;
false ->
@@ -243,7 +244,8 @@ get_certificate(CAUrl, DomainName, PrivateKey) ->
throw:Throw ->
Throw;
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
{error, DomainName, get_certificate}
end.
@@ -382,7 +384,8 @@ renew_certificates() ->
throw:Throw ->
Throw;
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
{error, get_certificates}
end.
@@ -447,7 +450,8 @@ list_certificates(Verbose) ->
throw:Throw ->
Throw;
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
{error, list_certificates}
end;
false ->
@@ -489,7 +493,8 @@ format_certificate(DataCert, Verbose) ->
end
catch
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
fail_format_certificate(DomainName)
end.
@@ -614,7 +619,8 @@ revoke_certificates(DomainOrFile) ->
throw:Throw ->
Throw;
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
{error, revoke_certificate}
end.
@@ -1118,7 +1124,8 @@ save_certificate({ok, DomainName, Cert}) ->
throw:Throw ->
Throw;
E:R ->
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, erlang:get_stacktrace()]),
St = erlang:get_stacktrace(),
?ERROR_MSG("Unknown ~p:~p, ~p", [E, R, St]),
{error, DomainName, saving}
end.
@@ -1215,15 +1222,12 @@ generate_key() ->
%% Option Parsing Code
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec opt_type(acme) -> fun((acme_config()) -> (acme_config()));
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(acme) ->
fun(L) ->
lists:map(
fun({ca_url, URL}) ->
URL1 = binary_to_list(URL),
{ok, _} = http_uri:parse(URL1),
{ca_url, URL1};
{ca_url, misc:try_url(URL)};
({contact, Contact}) ->
[<<_, _/binary>>, <<_, _/binary>>] =
binary:split(Contact, <<":">>),
-1
View File
@@ -22,7 +22,6 @@
%% delete_authz/3
]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
+8 -8
View File
@@ -61,7 +61,6 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_commands.hrl").
@@ -276,6 +275,8 @@ get_commands_spec() ->
#ejabberd_commands{name = import_prosody, tags = [mnesia, sql, riak],
desc = "Import data from Prosody",
longdesc = "Note: this method requires ejabberd compiled with optional tools support "
"and package must provide optional luerl dependency.",
module = prosody2ejabberd, function = from_dir,
args_desc = ["Full path to the Prosody data directory"],
args_example = ["/var/lib/prosody/datadump/"],
@@ -412,7 +413,7 @@ stop_kindly(DelaySeconds, AnnouncementTextString) ->
ejabberd_listener, stop_listeners, []},
{"Sending announcement to connected users",
mod_announce, send_announcement_to_all,
[?MYNAME, Subject, AnnouncementText]},
[ejabberd_config:get_myname(), Subject, AnnouncementText]},
{"Sending service message to MUC rooms",
ejabberd_admin, send_service_message_all_mucs,
[Subject, AnnouncementText]},
@@ -446,7 +447,7 @@ send_service_message_all_mucs(Subject, AnnouncementText) ->
ServerHost, mod_muc, <<"conference.@HOST@">>),
mod_muc:broadcast_service_message(ServerHost, MUCHost, Message)
end,
?MYHOSTS).
ejabberd_config:get_myhosts()).
%%%
%%% ejabberd_update
@@ -499,7 +500,7 @@ registered_users(Host) ->
lists:map(fun({U, _S}) -> U end, SUsers).
registered_vhosts() ->
?MYHOSTS.
ejabberd_config:get_myhosts().
reload_config() ->
ejabberd_config:reload_file().
@@ -549,13 +550,13 @@ delete_expired_messages() ->
lists:foreach(
fun(Host) ->
{atomic, ok} = mod_offline:remove_expired_messages(Host)
end, ?MYHOSTS).
end, ejabberd_config:get_myhosts()).
delete_old_messages(Days) ->
lists:foreach(
fun(Host) ->
{atomic, _} = mod_offline:remove_old_messages(Days, Host)
end, ?MYHOSTS).
end, ejabberd_config:get_myhosts()).
%%%
%%% Mnesia management
@@ -622,13 +623,12 @@ keep_tables() ->
%% loaded modules
keep_modules_tables() ->
lists:map(fun(Module) -> module_tables(Module) end,
gen_mod:loaded_modules(?MYNAME)).
gen_mod:loaded_modules(ejabberd_config:get_myname())).
%% TODO: This mapping should probably be moved to a callback function in each
%% module.
%% Mapping between modules and their tables
module_tables(mod_announce) -> [motd, motd_users];
module_tables(mod_irc) -> [irc_custom];
module_tables(mod_last) -> [last_activity];
module_tables(mod_muc) -> [muc_room, muc_registered];
module_tables(mod_offline) -> [offline_msg];
+24 -18
View File
@@ -31,7 +31,6 @@
-export([start/2, prep_stop/1, stop/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
%%%
@@ -46,22 +45,28 @@ start(normal, _Args) ->
start_elixir_application(),
ejabberd:check_app(ejabberd),
setup_if_elixir_conf_used(),
ejabberd_config:start(),
ejabberd_mnesia:start(),
file_queue_init(),
maybe_add_nameservers(),
ejabberd_system_monitor:start(),
case ejabberd_sup:start_link() of
{ok, SupPid} ->
register_elixir_config_hooks(),
ejabberd_cluster:wait_for_sync(infinity),
{T2, _} = statistics(wall_clock),
?INFO_MSG("ejabberd ~s is started in the node ~p in ~.2fs",
[?VERSION, node(), (T2-T1)/1000]),
lists:foreach(fun erlang:garbage_collect/1, processes()),
{ok, SupPid};
Err ->
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Err]),
case ejabberd_config:start() of
ok ->
ejabberd_mnesia:start(),
file_queue_init(),
maybe_add_nameservers(),
case ejabberd_sup:start_link() of
{ok, SupPid} ->
ejabberd_system_monitor:start(),
register_elixir_config_hooks(),
ejabberd_cluster:wait_for_sync(infinity),
{T2, _} = statistics(wall_clock),
?INFO_MSG("ejabberd ~s is started in the node ~p in ~.2fs",
[ejabberd_config:get_version(),
node(), (T2-T1)/1000]),
lists:foreach(fun erlang:garbage_collect/1, processes()),
{ok, SupPid};
Err ->
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Err]),
ejabberd:halt()
end;
{error, Reason} ->
?CRITICAL_MSG("Failed to start ejabberd application: ~p", [Reason]),
ejabberd:halt()
end;
start(_, _) ->
@@ -78,7 +83,8 @@ prep_stop(State) ->
%% All the processes were killed when this function is called
stop(_State) ->
?INFO_MSG("ejabberd ~s is stopped in the node ~p", [?VERSION, node()]),
?INFO_MSG("ejabberd ~s is stopped in the node ~p",
[ejabberd_config:get_version(), node()]),
delete_pid_file(),
%%ejabberd_debug:stop(),
ok.
+50 -34
View File
@@ -48,7 +48,7 @@
-export([auth_modules/1, opt_type/1]).
-include("ejabberd.hrl").
-include("scram.hrl").
-include("logger.hrl").
-define(AUTH_CACHE, auth_cache).
@@ -69,6 +69,7 @@
-callback start(binary()) -> any().
-callback stop(binary()) -> any().
-callback reload(binary()) -> any().
-callback plain_password_required(binary()) -> boolean().
-callback store_type(binary()) -> plain | external | scram.
-callback set_password(binary(), binary(), binary()) -> ok | {error, atom()}.
@@ -82,7 +83,8 @@
-callback use_cache(binary()) -> boolean().
-callback cache_nodes(binary()) -> boolean().
-optional_callbacks([set_password/3,
-optional_callbacks([reload/1,
set_password/3,
remove_user/2,
user_exists/2,
check_password/4,
@@ -105,7 +107,7 @@ init([]) ->
fun(Host, Acc) ->
Modules = auth_modules(Host),
maps:put(Host, Modules, Acc)
end, #{}, ?MYHOSTS),
end, #{}, ejabberd_config:get_myhosts()),
lists:foreach(
fun({Host, Modules}) ->
start(Host, Modules)
@@ -130,14 +132,16 @@ handle_cast({host_down, Host}, #state{host_modules = HostModules} = State) ->
init_cache(NewHostModules),
{noreply, State#state{host_modules = NewHostModules}};
handle_cast(config_reloaded, #state{host_modules = HostModules} = State) ->
NewHostModules = lists:foldl(
fun(Host, Acc) ->
OldModules = maps:get(Host, HostModules, []),
NewModules = auth_modules(Host),
start(Host, NewModules -- OldModules),
stop(Host, OldModules -- NewModules),
maps:put(Host, NewModules, Acc)
end, HostModules, ?MYHOSTS),
NewHostModules =
lists:foldl(
fun(Host, Acc) ->
OldModules = maps:get(Host, HostModules, []),
NewModules = auth_modules(Host),
start(Host, NewModules -- OldModules),
stop(Host, OldModules -- NewModules),
reload(Host, misc:intersection(OldModules, NewModules)),
maps:put(Host, NewModules, Acc)
end, HostModules, ejabberd_config:get_myhosts()),
init_cache(NewHostModules),
{noreply, State#state{host_modules = NewHostModules}};
handle_cast(Msg, State) ->
@@ -165,6 +169,15 @@ start(Host, Modules) ->
stop(Host, Modules) ->
lists:foreach(fun(M) -> M:stop(Host) end, Modules).
reload(Host, Modules) ->
lists:foreach(
fun(M) ->
case erlang:function_exported(M, reload, 1) of
true -> M:reload(Host);
false -> ok
end
end, Modules).
host_up(Host) ->
gen_server:cast(?MODULE, {host_up, Host}).
@@ -217,17 +230,22 @@ check_password_with_authmodule(User, AuthzId, Server, Password) ->
check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGen) ->
case validate_credentials(User, Server) of
{ok, LUser, LServer} ->
lists:foldl(
fun(Mod, false) ->
case db_check_password(
LUser, AuthzId, LServer, Password,
Digest, DigestGen, Mod) of
true -> {true, Mod};
false -> false
end;
(_, Acc) ->
Acc
end, false, auth_modules(LServer));
case jid:nodeprep(AuthzId) of
error ->
false;
LAuthzId ->
lists:foldl(
fun(Mod, false) ->
case db_check_password(
LUser, LAuthzId, LServer, Password,
Digest, DigestGen, Mod) of
true -> {true, Mod};
false -> false
end;
(_, Acc) ->
Acc
end, false, auth_modules(LServer))
end;
_ ->
false
end.
@@ -545,8 +563,8 @@ db_user_exists(User, Server, Mod) ->
{ok, _} ->
true;
error ->
case Mod:store_type(Server) of
external ->
case {Mod:store_type(Server), use_cache(Mod, Server)} of
{external, true} ->
case ets_cache:lookup(
?AUTH_CACHE, {User, Server},
fun() ->
@@ -559,8 +577,12 @@ db_user_exists(User, Server, Mod) ->
{ok, _} ->
true;
error ->
false
false;
{error, _} = Err ->
Err
end;
{external, false} ->
Mod:user_exists(User, Server);
_ ->
false
end
@@ -673,7 +695,7 @@ password_to_scram(Password) ->
password_to_scram(#scram{} = Password, _IterationCount) ->
Password;
password_to_scram(Password, IterationCount) ->
Salt = randoms:bytes(?SALT_LENGTH),
Salt = p1_rand:bytes(?SALT_LENGTH),
SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
ServerKey = scram:server_key(SaltedPassword),
@@ -744,7 +766,7 @@ auth_modules() ->
lists:flatmap(
fun(Host) ->
[{Host, Mod} || Mod <- auth_modules(Host)]
end, ?MYHOSTS).
end, ejabberd_config:get_myhosts()).
-spec auth_modules(binary()) -> [module()].
auth_modules(Server) ->
@@ -829,13 +851,7 @@ import(Server, {sql, _}, riak, <<"users">>, Fields) ->
import(_LServer, {sql, _}, sql, <<"users">>, _) ->
ok.
-spec opt_type(auth_method) -> fun((atom() | [atom()]) -> [atom()]);
(auth_password_format) -> fun((plain | scram) -> plain | scram);
(auth_use_cache) -> fun((boolean()) -> boolean());
(auth_cache_missed) -> fun((boolean()) -> boolean());
(auth_cache_life_time) -> fun((timeout()) -> timeout());
(auth_cache_size) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(auth_method) ->
fun (V) when is_list(V) ->
lists:map(fun(M) -> ejabberd_config:v_db(?MODULE, M) end, V);
+5 -5
View File
@@ -31,6 +31,7 @@
-export([start/1,
stop/1,
use_cache/1,
allow_anonymous/1,
is_sasl_anonymous_enabled/1,
is_login_anonymous_enabled/1,
@@ -44,7 +45,6 @@
get_users/2, count_users/2, store_type/1,
plain_password_required/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jid.hrl").
@@ -61,6 +61,9 @@ stop(Host) ->
ejabberd_hooks:delete(sm_remove_connection_hook, Host,
?MODULE, unregister_connection, 100).
use_cache(_) ->
false.
%% Return true if anonymous is allowed for host or false otherwise
allow_anonymous(Host) ->
lists:member(?MODULE, ejabberd_auth:auth_modules(Host)).
@@ -174,10 +177,7 @@ plain_password_required(_) ->
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()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(allow_multiple_connections) ->
fun (V) when is_boolean(V) -> V end;
opt_type(anonymous_protocol) ->
+45 -22
View File
@@ -31,23 +31,24 @@
-behaviour(ejabberd_auth).
-export([start/1, stop/1, set_password/3, check_password/4,
-export([start/1, stop/1, reload/1, set_password/3, check_password/4,
try_register/3, user_exists/2, remove_user/2,
store_type/1, plain_password_required/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
Cmd = ejabberd_config:get_option({extauth_program, Host}, "extauth"),
extauth:start(Host, Cmd).
extauth:start(Host).
stop(Host) ->
extauth:stop(Host).
reload(Host) ->
extauth:reload(Host).
plain_password_required(_) -> true.
store_type(_) -> external.
@@ -61,37 +62,48 @@ check_password(User, AuthzId, Server, Password) ->
set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of
true -> ok;
_ -> {error, db_failure}
Res when is_boolean(Res) -> ok;
{error, Reason} -> failure(User, Server, set_password, Reason)
end.
try_register(User, Server, Password) ->
extauth:try_register(User, Server, Password).
case extauth:try_register(User, Server, Password) of
true -> ok;
false -> {error, not_allowed};
{error, Reason} -> failure(User, Server, try_register, Reason)
end.
user_exists(User, Server) ->
try extauth:user_exists(User, Server) of
Res -> Res
catch
_:Error ->
?ERROR_MSG("external authentication program failure: ~p",
[Error]),
{error, db_failure}
case extauth:user_exists(User, Server) of
Res when is_boolean(Res) -> Res;
{error, Reason} -> failure(User, Server, user_exists, Reason)
end.
remove_user(User, Server) ->
case extauth:remove_user(User, Server) of
false -> {error, not_allowed};
true -> ok
true -> ok;
{error, Reason} -> failure(User, Server, remove_user, Reason)
end.
check_password_extauth(User, _AuthzId, Server, Password) ->
extauth:check_password(User, Server, Password) andalso
Password /= <<"">>.
if Password /= <<"">> ->
case extauth:check_password(User, Server, Password) of
Res when is_boolean(Res) -> Res;
{error, Reason} ->
failure(User, Server, check_password, Reason),
false
end;
true ->
false
end.
-spec failure(binary(), binary(), atom(), any()) -> {error, db_failure}.
failure(User, Server, Fun, Reason) ->
?ERROR_MSG("External authentication program failed when calling "
"'~s' for ~s@~s: ~p", [Fun, User, Server, Reason]),
{error, db_failure}.
-spec opt_type(extauth_cache) -> fun((false | non_neg_integer()) ->
false | non_neg_integer());
(extauth_program) -> fun((binary()) -> string());
(atom()) -> [atom()].
opt_type(extauth_cache) ->
?WARNING_MSG("option 'extauth_cache' is deprecated and has no effect, "
"use authentication or global cache configuration "
@@ -100,6 +112,17 @@ opt_type(extauth_cache) ->
fun (false) -> false;
(I) when is_integer(I), I >= 0 -> I
end;
opt_type(extauth_instances) ->
?WARNING_MSG("option 'extauth_instances' is deprecated and has no effect, "
"use 'extauth_pool_size'", []),
fun (V) when is_integer(V), V > 0 -> V end;
opt_type(extauth_program) ->
fun (V) -> binary_to_list(iolist_to_binary(V)) end;
opt_type(_) -> [extauth_cache, extauth_program].
opt_type(extauth_pool_name) ->
fun (V) -> iolist_to_binary(V) end;
opt_type(extauth_pool_size) ->
fun(I) when is_integer(I), I>0 -> I end;
opt_type(_) ->
[extauth_program, extauth_pool_size, extauth_pool_name,
%% Deprecated:
extauth_cache, extauth_instances].
+1 -5
View File
@@ -42,7 +42,6 @@
store_type/1, plain_password_required/1,
opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("eldap.hrl").
@@ -363,10 +362,7 @@ parse_options(Host) ->
sfilter = SearchFilter, lfilter = LocalFilter,
dn_filter = DNFilter, dn_filter_attrs = DNFilterAttrs}.
-spec opt_type(ldap_dn_filter) -> fun(([{binary(), binary()}]) ->
[{binary(), binary()}]);
(ldap_local_filter) -> fun((any()) -> any());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(ldap_dn_filter) ->
fun ([{DNF, DNFA}]) ->
NewDNFA = case DNFA of
+1 -1
View File
@@ -38,8 +38,8 @@
plain_password_required/1, use_cache/1]).
-export([need_transform/1, transform/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("scram.hrl").
-include("ejabberd_auth.hrl").
-record(reg_users_counter, {vhost = <<"">> :: binary(),
+1 -3
View File
@@ -82,9 +82,7 @@ get_pam_service(Host) ->
get_pam_userinfotype(Host) ->
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()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(pam_service) -> fun iolist_to_binary/1;
opt_type(pam_userinfotype) ->
fun (username) -> username;
+1 -1
View File
@@ -38,8 +38,8 @@
plain_password_required/1]).
-export([passwd_schema/0]).
-include("ejabberd.hrl").
-include("ejabberd_sql_pt.hrl").
-include("scram.hrl").
-include("ejabberd_auth.hrl").
start(_Host) ->
+2 -3
View File
@@ -37,7 +37,7 @@
remove_user/2, store_type/1, plain_password_required/1,
convert_to_scram/1, opt_type/1, export/1]).
-include("ejabberd.hrl").
-include("scram.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
-include("ejabberd_auth.hrl").
@@ -324,8 +324,7 @@ export(_Server) ->
[]
end}].
-spec opt_type(pgsql_users_number_estimate) -> fun((boolean()) -> boolean());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(pgsql_users_number_estimate) ->
fun (V) when is_boolean(V) -> V end;
opt_type(_) -> [pgsql_users_number_estimate].
+82 -115
View File
@@ -23,20 +23,18 @@
%%%
%%%-------------------------------------------------------------------
-module(ejabberd_bosh).
-behaviour(xmpp_socket).
-behaviour(p1_fsm).
-protocol({xep, 124, '1.11'}).
-protocol({xep, 206, '1.4'}).
-behaviour(p1_fsm).
%% API
-export([start/2, start/3, start_link/3]).
-export([send_xml/2, setopts/2, controlling_process/2,
migrate/3, become_controller/2,
reset_stream/1, change_shaper/2, monitor/1, close/1,
reset_stream/1, change_shaper/2, close/1,
sockname/1, peername/1, process_request/3, send/2,
change_controller/2]).
get_transport/1, get_owner/1]).
%% gen_fsm callbacks
-export([init/1, wait_for_session/2, wait_for_session/3,
@@ -44,13 +42,9 @@
handle_sync_event/4, handle_info/3, terminate/3,
code_change/4]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("ejabberd_http.hrl").
-include("bosh.hrl").
%%-define(DBGFSM, true).
@@ -92,7 +86,7 @@
sid = <<"">> :: binary(),
el_ibuf :: p1_queue:queue(),
el_obuf :: p1_queue:queue(),
shaper_state = none :: shaper:shaper(),
shaper_state = none :: ejabberd_shaper:shaper(),
c2s_pid :: pid() | undefined,
xmpp_ver = <<"">> :: binary(),
inactivity_timer :: reference() | undefined,
@@ -103,8 +97,8 @@
prev_key = <<"">> :: binary(),
prev_poll :: erlang:timestamp() | undefined,
max_concat = unlimited :: unlimited | non_neg_integer(),
responses = gb_trees:empty() :: ?TGB_TREE,
receivers = gb_trees:empty() :: ?TGB_TREE,
responses = gb_trees:empty() :: gb_trees:tree(),
receivers = gb_trees:empty() :: gb_trees:tree(),
shaped_receivers :: p1_queue:queue(),
ip :: inet:ip_address(),
max_requests = 1 :: non_neg_integer()}).
@@ -171,22 +165,12 @@ setopts({http_bind, FsmRef, _IP}, Opts) ->
controlling_process(_Socket, _Pid) -> ok.
become_controller(FsmRef, C2SPid) ->
p1_fsm:send_all_state_event(FsmRef,
{become_controller, C2SPid}).
change_controller({http_bind, FsmRef, _IP}, C2SPid) ->
become_controller(FsmRef, C2SPid).
reset_stream({http_bind, _FsmRef, _IP} = Socket) ->
Socket.
change_shaper({http_bind, FsmRef, _IP}, Shaper) ->
p1_fsm:send_all_state_event(FsmRef, {change_shaper, Shaper}).
monitor({http_bind, FsmRef, _IP}) ->
erlang:monitor(process, FsmRef).
close({http_bind, FsmRef, _IP}) ->
catch p1_fsm:sync_send_all_state_event(FsmRef,
close).
@@ -195,10 +179,11 @@ sockname(_Socket) -> {ok, {{0, 0, 0, 0}, 0}}.
peername({http_bind, _FsmRef, IP}) -> {ok, IP}.
migrate(FsmRef, Node, After) when node(FsmRef) == node() ->
catch erlang:send_after(After, FsmRef, {migrate, Node});
migrate(_FsmRef, _Node, _After) ->
ok.
get_transport(_Socket) ->
http_bind.
get_owner({http_bind, FsmRef, _IP}) ->
FsmRef.
process_request(Data, IP, Type) ->
Opts1 = ejabberd_c2s_config:get_c2s_limits(),
@@ -285,7 +270,7 @@ init([#body{attrs = Attrs}, IP, SID]) ->
Opts1 = ejabberd_c2s_config:get_c2s_limits(),
Opts2 = [{xml_socket, true} | Opts1],
Shaper = none,
ShaperState = shaper:new(Shaper),
ShaperState = ejabberd_shaper:new(Shaper),
Socket = make_socket(self(), IP),
XMPPVer = get_attr('xmpp:version', Attrs),
XMPPDomain = get_attr(to, Attrs),
@@ -299,30 +284,26 @@ init([#body{attrs = Attrs}, IP, SID]) ->
buf_new(XMPPDomain)),
Opts2}
end,
xmpp_socket:start(ejabberd_c2s, ?MODULE, Socket,
[{receiver, self()}|Opts]),
Inactivity = gen_mod:get_module_opt(XMPPDomain,
mod_bosh, max_inactivity),
MaxConcat = gen_mod:get_module_opt(XMPPDomain, mod_bosh, max_concat),
ShapedReceivers = buf_new(XMPPDomain, ?MAX_SHAPED_REQUESTS_QUEUE_LEN),
State = #state{host = XMPPDomain, sid = SID, ip = IP,
xmpp_ver = XMPPVer, el_ibuf = InBuf,
max_concat = MaxConcat, el_obuf = buf_new(XMPPDomain),
inactivity_timeout = Inactivity,
shaped_receivers = ShapedReceivers,
shaper_state = ShaperState},
NewState = restart_inactivity_timer(State),
mod_bosh:open_session(SID, self()),
{ok, wait_for_session, NewState};
init([StateName, State]) ->
mod_bosh:open_session(State#state.sid, self()),
case State#state.c2s_pid of
C2SPid when is_pid(C2SPid) ->
NewSocket = make_socket(self(), State#state.ip),
C2SPid ! {change_socket, NewSocket},
NewState = restart_inactivity_timer(State),
{ok, StateName, NewState};
_ -> {stop, normal}
case ejabberd_c2s:start({?MODULE, Socket}, [{receiver, self()}|Opts]) of
{ok, C2SPid} ->
ejabberd_c2s:accept(C2SPid),
Inactivity = gen_mod:get_module_opt(XMPPDomain,
mod_bosh, max_inactivity),
MaxConcat = gen_mod:get_module_opt(XMPPDomain, mod_bosh, max_concat),
ShapedReceivers = buf_new(XMPPDomain, ?MAX_SHAPED_REQUESTS_QUEUE_LEN),
State = #state{host = XMPPDomain, sid = SID, ip = IP,
xmpp_ver = XMPPVer, el_ibuf = InBuf,
max_concat = MaxConcat, el_obuf = buf_new(XMPPDomain),
inactivity_timeout = Inactivity,
shaped_receivers = ShapedReceivers,
shaper_state = ShaperState},
NewState = restart_inactivity_timer(State),
mod_bosh:open_session(SID, self()),
{ok, wait_for_session, NewState};
{error, Reason} ->
{stop, Reason};
ignore ->
ignore
end.
wait_for_session(_Event, State) ->
@@ -359,7 +340,7 @@ wait_for_session(#body{attrs = Attrs} = Req, From,
{'xmlns:stream', ?NS_STREAM}, {from, State#state.host}
| Polling]},
{ShaperState, _} =
shaper:update(State#state.shaper_state, Req#body.size),
ejabberd_shaper:update(State#state.shaper_state, Req#body.size),
State1 = State#state{wait_timeout = Wait,
prev_rid = RID, prev_key = NewKey,
prev_poll = PollTime, shaper_state = ShaperState,
@@ -369,15 +350,22 @@ wait_for_session(#body{attrs = Attrs} = Req, From,
{State3, RespEls} = get_response_els(State2),
State4 = stop_inactivity_timer(State3),
case RespEls of
[] ->
State5 = restart_wait_timer(State4),
Receivers = gb_trees:insert(RID, {From, Resp},
State5#state.receivers),
{next_state, active,
State5#state{receivers = Receivers}};
_ ->
reply_next_state(State4, Resp#body{els = RespEls}, RID,
From)
[{xmlstreamstart, _, _} = El1] ->
OutBuf = buf_in([El1], State4#state.el_obuf),
State5 = restart_wait_timer(State4),
Receivers = gb_trees:insert(RID, {From, Resp},
State5#state.receivers),
{next_state, active,
State5#state{receivers = Receivers, el_obuf = OutBuf}};
[] ->
State5 = restart_wait_timer(State4),
Receivers = gb_trees:insert(RID, {From, Resp},
State5#state.receivers),
{next_state, active,
State5#state{receivers = Receivers}};
_ ->
reply_next_state(State4, Resp#body{els = RespEls}, RID,
From)
end;
wait_for_session(_Event, _From, State) ->
?ERROR_MSG("unexpected sync event in 'wait_for_session': ~p",
@@ -397,7 +385,7 @@ active(#body{attrs = Attrs, size = Size} = Req, From,
"~p~n** State: ~p",
[Req, From, State]),
{ShaperState, Pause} =
shaper:update(State#state.shaper_state, Size),
ejabberd_shaper:update(State#state.shaper_state, Size),
State1 = State#state{shaper_state = ShaperState},
if Pause > 0 ->
TRef = start_shaper_timer(Pause),
@@ -408,7 +396,7 @@ active(#body{attrs = Attrs, size = Size} = Req, From,
{next_state, active,
State2#state{shaped_receivers = Q}}
catch error:full ->
cancel_timer(TRef),
misc:cancel_timer(TRef),
RID = get_attr(rid, Attrs),
reply_stop(State1,
#body{http_reason = <<"Too many requests">>,
@@ -452,7 +440,7 @@ active1(#body{attrs = Attrs} = Req, From, State) ->
{next_state, active,
do_reply(State, From, PrevBody, RID)};
none ->
State1 = drop_holding_receiver(State),
State1 = drop_holding_receiver(State, RID),
State2 = stop_inactivity_timer(State1),
State3 = restart_wait_timer(State2),
Receivers = gb_trees:insert(RID, {From, Req},
@@ -522,15 +510,13 @@ active1(#body{attrs = Attrs} = Req, From, State) ->
end
end.
handle_event({become_controller, C2SPid}, StateName,
handle_event({activate, C2SPid}, StateName,
State) ->
State1 = route_els(State#state{c2s_pid = C2SPid}),
{next_state, StateName, State1};
handle_event({change_shaper, Shaper}, StateName,
State) ->
NewShaperState = shaper:new(Shaper),
{next_state, StateName,
State#state{shaper_state = NewShaperState}};
{next_state, StateName, State#state{shaper_state = Shaper}};
handle_event(_Event, StateName, State) ->
?ERROR_MSG("unexpected event in '~s': ~p",
[StateName, _Event]),
@@ -558,7 +544,7 @@ handle_sync_event({send_xml, El}, _From, StateName,
State2 = case p1_queue:out(State1#state.shaped_receivers)
of
{{value, {TRef, From, Body}}, Q} ->
cancel_timer(TRef),
misc:cancel_timer(TRef),
p1_fsm:send_event(self(), {Body, From}),
State1#state{shaped_receivers = Q};
_ -> State1
@@ -578,7 +564,8 @@ handle_sync_event(_Event, _From, StateName, State) ->
handle_info({timeout, TRef, wait_timeout}, StateName,
#state{wait_timer = TRef} = State) ->
{next_state, StateName, drop_holding_receiver(State)};
State2 = State#state{wait_timer = undefined},
{next_state, StateName, drop_holding_receiver(State2)};
handle_info({timeout, TRef, inactive}, _StateName,
#state{inactivity_timer = TRef} = State) ->
{stop, normal, State};
@@ -596,24 +583,11 @@ handle_info({timeout, TRef, shaper_timeout}, StateName,
{stop, normal, State};
_ -> {next_state, StateName, State}
end;
handle_info({migrate, Node}, StateName, State) ->
if Node /= node() ->
NewState = bounce_receivers(State, migrated),
{migrate, NewState,
{Node, ?MODULE, start, [StateName, NewState]}, 0};
true -> {next_state, StateName, State}
end;
handle_info(_Info, StateName, State) ->
?ERROR_MSG("unexpected info:~n** Msg: ~p~n** StateName: ~p",
[_Info, StateName]),
{next_state, StateName, State}.
terminate({migrated, ClonePid}, _StateName, State) ->
?INFO_MSG("Migrating session \"~s\" (c2s_pid = "
"~p) to ~p on node ~p",
[State#state.sid, State#state.c2s_pid, ClonePid,
node(ClonePid)]),
mod_bosh:close_session(State#state.sid);
terminate(_Reason, _StateName, State) ->
mod_bosh:close_session(State#state.sid),
case State#state.c2s_pid of
@@ -688,15 +662,17 @@ reply_stop(State, Body, From, RID) ->
{stop, normal, do_reply(State, From, Body, RID)}.
drop_holding_receiver(State) ->
RID = State#state.prev_rid,
drop_holding_receiver(State, State#state.prev_rid).
drop_holding_receiver(State, RID) ->
case gb_trees:lookup(RID, State#state.receivers) of
{value, {From, Body}} ->
State1 = restart_inactivity_timer(State),
Receivers = gb_trees:delete_any(RID,
State1#state.receivers),
State2 = State1#state{receivers = Receivers},
do_reply(State2, From, Body, RID);
none -> State
{value, {From, Body}} ->
State1 = restart_inactivity_timer(State),
Receivers = gb_trees:delete_any(RID,
State1#state.receivers),
State2 = State1#state{receivers = Receivers},
do_reply(State2, From, Body, RID);
none ->
restart_inactivity_timer(State)
end.
do_reply(State, From, Body, RID) ->
@@ -714,7 +690,7 @@ do_reply(State, From, Body, RID) ->
Responses2 = gb_trees:insert(RID, Body, Responses1),
State#state{responses = Responses2}.
bounce_receivers(State, Reason) ->
bounce_receivers(State, _Reason) ->
Receivers = gb_trees:to_list(State#state.receivers),
ShapedReceivers = lists:map(fun ({_, From,
#body{attrs = Attrs} = Body}) ->
@@ -722,18 +698,13 @@ bounce_receivers(State, Reason) ->
{RID, {From, Body}}
end,
p1_queue:to_list(State#state.shaped_receivers)),
lists:foldl(fun ({RID, {From, Body}}, AccState) ->
NewBody = if Reason == closed ->
#body{http_reason =
<<"Session closed">>,
attrs =
[{type, <<"terminate">>},
{condition,
<<"other-request">>}]};
Reason == migrated ->
Body#body{http_reason =
<<"Session migrated">>}
end,
lists:foldl(fun ({RID, {From, _Body}}, AccState) ->
NewBody = #body{http_reason =
<<"Session closed">>,
attrs =
[{type, <<"terminate">>},
{condition,
<<"other-request">>}]},
do_reply(AccState, From, NewBody, RID)
end,
State, Receivers ++ ShapedReceivers).
@@ -987,7 +958,7 @@ http_error(Status, Reason, Type) ->
end,
{Status, Reason, ?HEADER(CType), <<"">>}.
make_sid() -> str:sha(randoms:get_string()).
make_sid() -> str:sha(p1_rand:get_string()).
-compile({no_auto_import, [{min, 2}]}).
@@ -1040,12 +1011,8 @@ buf_out(Buf, I, Els) ->
{empty, _} -> buf_out(Buf, 0, Els)
end.
cancel_timer(TRef) when is_reference(TRef) ->
p1_fsm:cancel_timer(TRef);
cancel_timer(_) -> false.
restart_timer(TRef, Timeout, Msg) ->
cancel_timer(TRef),
misc:cancel_timer(TRef),
erlang:start_timer(timer:seconds(Timeout), self(), Msg).
restart_inactivity_timer(#state{inactivity_timeout =
@@ -1062,7 +1029,7 @@ restart_inactivity_timer(#state{inactivity_timer =
stop_inactivity_timer(#state{inactivity_timer = TRef} =
State) ->
cancel_timer(TRef),
misc:cancel_timer(TRef),
State#state{inactivity_timer = undefined}.
restart_wait_timer(#state{wait_timer = TRef,
@@ -1072,13 +1039,13 @@ restart_wait_timer(#state{wait_timer = TRef,
State#state{wait_timer = NewTRef}.
stop_wait_timer(#state{wait_timer = TRef} = State) ->
cancel_timer(TRef), State#state{wait_timer = undefined}.
misc:cancel_timer(TRef), State#state{wait_timer = undefined}.
start_shaper_timer(Timeout) ->
erlang:start_timer(Timeout, self(), shaper_timeout).
make_random_jid(Host) ->
User = randoms:get_string(),
jid:make(User, Host, randoms:get_string()).
User = p1_rand:get_string(),
jid:make(User, Host, p1_rand:get_string()).
make_socket(Pid, IP) -> {http_bind, Pid, IP}.
+91 -113
View File
@@ -22,20 +22,20 @@
-module(ejabberd_c2s).
-behaviour(xmpp_stream_in).
-behaviour(ejabberd_config).
-behaviour(xmpp_socket).
-behaviour(ejabberd_listener).
-protocol({rfc, 6121}).
%% xmpp_socket callbacks
-export([start/2, start_link/2, socket_type/0]).
%% ejabberd_listener callbacks
-export([start/2, start_link/2, accept/1, listen_opt_type/1, listen_options/0]).
%% ejabberd_config callbacks
-export([opt_type/1, listen_opt_type/1, transform_listen_option/2]).
-export([opt_type/1, transform_listen_option/2]).
%% xmpp_stream_in callbacks
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
-export([tls_options/1, tls_required/1, tls_verify/1, tls_enabled/1,
-export([tls_options/1, tls_required/1, tls_enabled/1,
compress_methods/1, bind/2, sasl_mechanisms/2,
get_password_fun/1, check_password_fun/1, check_password_digest_fun/1,
get_password_fun/2, check_password_fun/2, check_password_digest_fun/2,
unauthenticated_stream_features/1, authenticated_stream_features/1,
handle_stream_start/2, handle_stream_end/2,
handle_unauthenticated_packet/2, handle_authenticated_packet/2,
@@ -51,7 +51,6 @@
reply/2, copy_state/2, set_timeout/2, route/2,
host_up/1, host_down/1]).
-include("ejabberd.hrl").
-include("xmpp.hrl").
-include("logger.hrl").
-include("mod_roster.hrl").
@@ -62,26 +61,18 @@
-export_type([state/0]).
%%%===================================================================
%%% xmpp_socket API
%%% ejabberd_listener API
%%%===================================================================
start(SockData, Opts) ->
case proplists:get_value(supervisor, Opts, true) of
true ->
case supervisor:start_child(ejabberd_c2s_sup, [SockData, Opts]) of
{ok, undefined} -> ignore;
Res -> Res
end;
_ ->
xmpp_stream_in:start(?MODULE, [SockData, Opts],
ejabberd_config:fsm_limit_opts(Opts))
end.
xmpp_stream_in:start(?MODULE, [SockData, Opts],
ejabberd_config:fsm_limit_opts(Opts)).
start_link(SockData, Opts) ->
xmpp_stream_in:start_link(?MODULE, [SockData, Opts],
ejabberd_config:fsm_limit_opts(Opts)).
socket_type() ->
xml_stream.
accept(Ref) ->
xmpp_stream_in:accept(Ref).
%%%===================================================================
%%% Common API
@@ -105,7 +96,7 @@ get_presence(Ref) ->
set_presence(Ref, Pres) ->
call(Ref, {set_presence, Pres}, 1000).
-spec resend_presence(pid()) -> ok.
-spec resend_presence(pid()) -> boolean().
resend_presence(Pid) ->
resend_presence(Pid, undefined).
@@ -273,7 +264,6 @@ process_terminated(#{sid := SID, socket := Socket,
State1 = case maps:is_key(pres_last, State) of
true ->
Pres = #presence{type = unavailable,
status = xmpp:mk_text(Status),
from = JID,
to = jid:remove_resource(JID)},
ejabberd_sm:close_session_unset_presence(SID, U, S, R,
@@ -340,9 +330,6 @@ tls_options(#{lserver := LServer, tls_options := DefaultOpts,
tls_required(#{tls_required := TLSRequired}) ->
TLSRequired.
tls_verify(#{tls_verify := TLSVerify}) ->
TLSVerify.
tls_enabled(#{tls_enabled := TLSEnabled,
tls_required := TLSRequired,
tls_verify := TLSVerify}) ->
@@ -359,25 +346,41 @@ unauthenticated_stream_features(#{lserver := LServer}) ->
authenticated_stream_features(#{lserver := LServer}) ->
ejabberd_hooks:run_fold(c2s_post_auth_features, LServer, [], [LServer]).
sasl_mechanisms(Mechs, #{lserver := LServer}) ->
sasl_mechanisms(Mechs, #{lserver := LServer} = State) ->
Type = ejabberd_auth:store_type(LServer),
Mechs1 = ejabberd_config:get_option({disable_sasl_mechanisms, LServer}, []),
Mechs2 = case ejabberd_auth_anonymous:is_sasl_anonymous_enabled(LServer) of
true -> Mechs1;
false -> [<<"ANONYMOUS">>|Mechs1]
end,
Mechs -- Mechs2.
%% I re-created it from cyrsasl ets magic, but I think it's wrong
%% TODO: need to check before 18.09 release
lists:filter(
fun(<<"ANONYMOUS">>) ->
ejabberd_auth_anonymous:is_sasl_anonymous_enabled(LServer);
(<<"DIGEST-MD5">>) -> Type == plain;
(<<"SCRAM-SHA-1">>) -> Type /= external;
(<<"PLAIN">>) -> true;
(<<"X-OAUTH2">>) -> true;
(<<"EXTERNAL">>) -> maps:get(tls_verify, State, false);
(_) -> false
end, Mechs -- Mechs1).
get_password_fun(#{lserver := LServer}) ->
get_password_fun(_Mech, #{lserver := LServer}) ->
fun(U) ->
ejabberd_auth:get_password_with_authmodule(U, LServer)
end.
check_password_fun(#{lserver := LServer}) ->
check_password_fun(<<"X-OAUTH2">>, #{lserver := LServer}) ->
fun(User, _AuthzId, Token) ->
case ejabberd_oauth:check_token(
User, LServer, [<<"sasl_auth">>], Token) of
true -> {true, ejabberd_oauth};
_ -> {false, ejabberd_oauth}
end
end;
check_password_fun(_Mech, #{lserver := LServer}) ->
fun(U, AuthzId, P) ->
ejabberd_auth:check_password_with_authmodule(U, AuthzId, LServer, P)
end.
check_password_digest_fun(#{lserver := LServer}) ->
check_password_digest_fun(_Mech, #{lserver := LServer}) ->
fun(U, AuthzId, P, D, DG) ->
ejabberd_auth:check_password_with_authmodule(U, AuthzId, LServer, P, D, DG)
end.
@@ -405,8 +408,8 @@ bind(R, #{user := U, server := S, access := Access, lang := Lang,
{ok, State2};
deny ->
ejabberd_hooks:run(forbidden_session_hook, LServer, [JID]),
?INFO_MSG("(~s) Forbidden c2s session for ~s",
[xmpp_socket:pp(Socket), jid:encode(JID)]),
?WARNING_MSG("(~s) Forbidden c2s session for ~s",
[xmpp_socket:pp(Socket), jid:encode(JID)]),
Txt = <<"Access denied by service policy">>,
{error, xmpp:err_not_allowed(Txt, Lang), State}
end
@@ -415,7 +418,7 @@ bind(R, #{user := U, server := S, access := Access, lang := Lang,
handle_stream_start(StreamStart, #{lserver := LServer} = State) ->
case ejabberd_router:is_my_host(LServer) of
false ->
send(State#{lserver => ?MYNAME}, xmpp:serr_host_unknown());
send(State#{lserver => ejabberd_config:get_myname()}, xmpp:serr_host_unknown());
true ->
State1 = change_shaper(State),
Opts = ejabberd_config:codec_options(LServer),
@@ -441,12 +444,12 @@ handle_auth_success(User, Mech, AuthModule,
handle_auth_failure(User, Mech, Reason,
#{socket := Socket,
ip := IP, lserver := LServer} = State) ->
?INFO_MSG("(~s) Failed c2s ~s authentication ~sfrom ~s: ~s",
[xmpp_socket:pp(Socket), Mech,
if User /= <<"">> -> ["for ", User, "@", LServer, " "];
true -> ""
end,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)), Reason]),
?WARNING_MSG("(~s) Failed c2s ~s authentication ~sfrom ~s: ~s",
[xmpp_socket:pp(Socket), Mech,
if User /= <<"">> -> ["for ", User, "@", LServer, " "];
true -> ""
end,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)), Reason]),
ejabberd_hooks:run_fold(c2s_auth_result, LServer, State, [false, User]).
handle_unbinded_packet(Pkt, #{lserver := LServer} = State) ->
@@ -526,9 +529,9 @@ init([State, Opts]) ->
tls_verify => TLSVerify,
pres_a => ?SETS:new(),
zlib => Zlib,
lang => ?MYLANG,
server => ?MYNAME,
lserver => ?MYNAME,
lang => ejabberd_config:get_mylang(),
server => ejabberd_config:get_myname(),
lserver => ejabberd_config:get_myname(),
access => Access,
shaper => Shaper},
State2 = xmpp_stream_in:set_timeout(State1, Timeout),
@@ -882,7 +885,7 @@ bounce_message_queue() ->
-spec new_uniq_id() -> binary().
new_uniq_id() ->
iolist_to_binary(
[randoms:get_string(),
[p1_rand:get_string(),
integer_to_binary(p1_time_compat:unique_integer([positive]))]).
-spec get_conn_type(state()) -> c2s | c2s_tls | c2s_compressed | websocket |
@@ -921,7 +924,7 @@ change_shaper(#{shaper := ShaperName, ip := IP, lserver := LServer,
Shaper = acl:access_matches(ShaperName,
#{usr => jid:split(JID), ip => IP},
LServer),
xmpp_stream_in:change_shaper(State, Shaper).
xmpp_stream_in:change_shaper(State, ejabberd_shaper:new(Shaper)).
-spec format_reason(state(), term()) -> binary().
format_reason(#{stop_reason := Reason}, _) ->
@@ -935,7 +938,7 @@ format_reason(_, {shutdown, _}) ->
format_reason(_, _) ->
<<"internal server error">>.
-spec get_certfile(binary()) -> file:filename_all().
-spec get_certfile(binary()) -> file:filename_all() | undefined.
get_certfile(LServer) ->
case ejabberd_pkix:get_certfile(LServer) of
{ok, CertFile} ->
@@ -949,15 +952,7 @@ get_certfile(LServer) ->
transform_listen_option(Opt, Opts) ->
[Opt|Opts].
-type resource_conflict() :: setresource | closeold | closenew | acceptnew.
-spec opt_type(c2s_ciphers) -> fun((binary()) -> binary());
(c2s_dhfile) -> fun((binary()) -> binary());
(c2s_cafile) -> fun((binary()) -> binary());
(c2s_protocol_options) -> fun(([binary()]) -> binary());
(c2s_tls_compression) -> fun((boolean()) -> boolean());
(resource_conflict) -> fun((resource_conflict()) -> resource_conflict());
(disable_sasl_mechanisms) -> fun((binary() | [binary()]) -> [binary()]);
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(c2s_ciphers) -> fun iolist_to_binary/1;
opt_type(c2s_dhfile) -> fun misc:try_read_file/1;
opt_type(c2s_cafile) -> fun misc:try_read_file/1;
@@ -983,71 +978,54 @@ opt_type(_) ->
c2s_protocol_options, c2s_tls_compression, resource_conflict,
disable_sasl_mechanisms].
-spec listen_opt_type(access) -> fun((any()) -> any());
(shaper) -> fun((any()) -> any());
(certfile) -> fun((binary()) -> binary());
(ciphers) -> fun((binary()) -> binary());
(dhfile) -> fun((binary()) -> binary());
(cafile) -> fun((binary()) -> binary());
(protocol_options) -> fun(([binary()]) -> binary());
(tls_compression) -> fun((boolean()) -> boolean());
(tls) -> fun((boolean()) -> boolean());
(starttls) -> fun((boolean()) -> boolean());
(tls_verify) -> fun((boolean()) -> boolean());
(zlib) -> fun((boolean()) -> boolean());
(supervisor) -> fun((boolean()) -> boolean());
(max_stanza_size) -> fun((timeout()) -> timeout());
(max_fsm_queue) -> fun((timeout()) -> timeout());
(stream_management) -> fun((boolean()) -> boolean());
(inet) -> fun((boolean()) -> boolean());
(inet6) -> fun((boolean()) -> boolean());
(backlog) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
listen_opt_type(access) -> fun acl:access_rules_validator/1;
listen_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
listen_opt_type(certfile = Opt) ->
fun(S) ->
?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
"'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
ok = ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(ciphers) -> opt_type(c2s_ciphers);
listen_opt_type(dhfile) -> opt_type(c2s_dhfile);
listen_opt_type(cafile) -> opt_type(c2s_cafile);
listen_opt_type(protocol_options) -> opt_type(c2s_protocol_options);
listen_opt_type(tls_compression) -> opt_type(c2s_tls_compression);
listen_opt_type(tls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(starttls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(starttls_required) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(tls_verify) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(zlib) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(supervisor) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(max_stanza_size) ->
fun(I) when is_integer(I), I>0 -> I;
(unlimited) -> infinity;
(infinity) -> infinity
listen_opt_type(zlib) ->
fun(true) ->
ejabberd:start_app(ezlib),
true;
(false) ->
false
end;
listen_opt_type(max_fsm_queue) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(stream_management) ->
?ERROR_MSG("listening option 'stream_management' is ignored: "
"use mod_stream_mgmt module", []),
fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
fun(B) when is_boolean(B) ->
?ERROR_MSG("Listening option 'stream_management' is ignored: "
"use mod_stream_mgmt module", []),
B
end;
listen_opt_type(O) ->
StreamOpts = mod_stream_mgmt:mod_options(?MYNAME),
case lists:keyfind(O, 1, StreamOpts) of
false ->
[access, shaper, certfile, ciphers, dhfile, cafile,
protocol_options, tls, tls_compression, starttls,
starttls_required, tls_verify, zlib, max_fsm_queue,
backlog, inet, inet6];
_ ->
?ERROR_MSG("Listening option '~s' is ignored: use '~s' "
"option from mod_stream_mgmt module", [O, O]),
mod_stream_mgmt:mod_opt_type(O)
MgmtOpts = mod_stream_mgmt:mod_options(ejabberd_config:get_myname()),
case lists:keymember(O, 1, MgmtOpts) of
true ->
fun(V) ->
?ERROR_MSG("Listening option '~s' is ignored: use '~s' "
"option from mod_stream_mgmt module", [O, O]),
(mod_stream_mgmt:mod_opt_type(O))(V)
end
end.
listen_options() ->
[{access, all},
{shaper, none},
{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{starttls, false},
{starttls_required, false},
{tls_verify, false},
{zlib, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000}|
mod_stream_mgmt:mod_options(ejabberd_config:get_myname())].
+9 -18
View File
@@ -45,7 +45,6 @@
config_reloaded/0, process_iq/1]).
-include("xmpp.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_http.hrl").
@@ -90,7 +89,7 @@ mk_field(Type, Var, Value) ->
create_captcha(SID, From, To, Lang, Limiter, Args) ->
case create_image(Limiter) of
{ok, Type, Key, Image} ->
Id = <<(randoms:get_string())/binary>>,
Id = <<(p1_rand:get_string())/binary>>,
JID = jid:encode(From),
CID = <<"sha1+", (str:sha(Image))/binary, "@bob.xmpp.org">>,
Data = #bob_data{cid = CID, 'max-age' = 0, type = Type,
@@ -121,7 +120,7 @@ create_captcha(SID, From, To, Lang, Limiter, Args) ->
create_captcha_x(SID, To, Lang, Limiter, #xdata{fields = Fs} = X) ->
case create_image(Limiter) of
{ok, Type, Key, Image} ->
Id = <<(randoms:get_string())/binary>>,
Id = <<(p1_rand:get_string())/binary>>,
CID = <<"sha1+", (str:sha(Image))/binary, "@bob.xmpp.org">>,
Data = #bob_data{cid = CID, 'max-age' = 0, type = Type, data = Image},
HelpTxt = translate:translate(Lang,
@@ -231,7 +230,6 @@ process_iq(#iq{type = get, lang = Lang} = IQ) ->
Txt = <<"Value 'get' of 'type' attribute is not allowed">>,
xmpp:make_error(IQ, xmpp:err_not_allowed(Txt, Lang));
process_iq(#iq{lang = Lang} = IQ) ->
?INFO_MSG("IQ = ~p", [IQ]),
Txt = <<"No module is handling this query">>,
xmpp:make_error(IQ, xmpp:err_service_unavailable(Txt, Lang)).
@@ -365,19 +363,19 @@ terminate(_Reason, #state{enabled = Enabled}) ->
register_handlers() ->
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 50),
lists:foreach(fun host_up/1, ?MYHOSTS).
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()).
unregister_handlers() ->
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 50),
lists:foreach(fun host_down/1, ?MYHOSTS).
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()).
code_change(_OldVsn, State, _Extra) -> {ok, State}.
create_image() -> create_image(undefined).
create_image(Limiter) ->
Key = str:substr(randoms:get_string(), 1, 6),
Key = str:substr(p1_rand:get_string(), 1, 6),
create_image(Limiter, Key).
create_image(Limiter, Key) ->
@@ -445,7 +443,7 @@ get_url(Str) ->
<<TransferProt/binary, ":", Host/binary, ":",
PortString/binary, "/captcha/", Str/binary>>;
_ ->
<<"http://", (?MYNAME)/binary, "/captcha/", Str/binary>>
<<"http://", (ejabberd_config:get_myname())/binary, "/captcha/", Str/binary>>
end.
get_transfer_protocol(PortString) ->
@@ -518,11 +516,7 @@ recv_data(Port, TRef, Buf) ->
end.
return(Port, TRef, Result) ->
case erlang:cancel_timer(TRef) of
false ->
receive {timeout, TRef, _} -> ok after 0 -> ok end;
_ -> ok
end,
misc:cancel_timer(TRef),
catch port_close(Port),
Result.
@@ -562,7 +556,7 @@ check_captcha(Id, ProvidedKey) ->
case ets:lookup(captcha, Id) of
[#captcha{pid = Pid, args = Args, key = ValidKey, tref = Tref}] ->
ets:delete(captcha, Id),
erlang:cancel_timer(Tref),
misc:cancel_timer(Tref),
if ValidKey == ProvidedKey ->
callback(captcha_succeed, Pid, Args),
captcha_valid;
@@ -596,10 +590,7 @@ callback(_, _, _) ->
now_priority() ->
-p1_time_compat:system_time(micro_seconds).
-spec opt_type(captcha_cmd) -> fun((binary()) -> binary());
(captcha_host) -> fun((binary()) -> binary());
(captcha_limit) -> fun((pos_integer()) -> pos_integer());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(captcha_cmd) ->
fun (FileName) ->
F = iolist_to_binary(FileName), if F /= <<"">> -> F end
-1
View File
@@ -31,7 +31,6 @@
get_known_nodes/0, node_id/0, get_node_by_id/1,
send/2, wait_for_sync/1, subscribe/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-spec init() -> ok.
+1 -4
View File
@@ -240,7 +240,6 @@
terminate/2, code_change/3]).
-include("ejabberd_commands.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
@@ -620,9 +619,7 @@ permission_addon() ->
[{access, ejabberd_config:get_option(commands_admin_access, none)}],
{get_exposed_commands(), []}}}].
-spec opt_type(commands_admin_access) -> fun((any()) -> any());
(commands) -> fun((list()) -> list());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(commands_admin_access) -> fun acl:access_rules_validator/1;
opt_type(commands) ->
fun(V) when is_list(V) -> V end;
+2 -2
View File
@@ -30,7 +30,6 @@
-export([generate_md_output/3]).
-include("ejabberd_commands.hrl").
-include("ejabberd.hrl").
-define(RAW(V), if HTMLOutput -> fxml:crypt(iolist_to_binary(V)); true -> iolist_to_binary(V) end).
-define(TAG(N), if HTMLOutput -> [<<"<", ??N, "/>">>]; true -> md_tag(N, <<"">>) end).
@@ -460,7 +459,8 @@ generate_md_output(File, RegExp, Languages) ->
end, Cmds2),
Cmds4 = [maybe_add_policy_arguments(Cmd) || Cmd <- Cmds3],
Langs = binary:split(Languages, <<",">>, [global]),
Header = <<"---\ntitle: Administration API reference\nbodyclass: nocomment\n---">>,
Header = <<"---\ntitle: Administration API reference\ntoc: true\nmenu: Administration API\norder: 40\n"
"// Autogenerated with 'ejabberdctl gen_markdown_doc_for_commands'\n---">>,
Out = lists:map(fun(C) -> gen_doc(C, false, Langs) end, Cmds4),
{ok, Fh} = file:open(File, [write]),
io:format(Fh, "~s~s", [Header, Out]),
+153 -87
View File
@@ -28,12 +28,13 @@
-export([start/0, load_file/1, reload_file/0, read_file/1,
get_option/1, get_option/2, add_option/2, has_option/1,
get_version/0, get_myhosts/0, get_mylang/0, get_lang/1,
get_version/0, get_myhosts/0, get_myname/0,
get_mylang/0, get_lang/1, get_uri/0, get_copyright/0,
get_ejabberd_config_path/0, is_using_elixir_config/0,
prepare_opt_val/4, transform_options/1, collect_options/1,
convert_to_yaml/1, convert_to_yaml/2, v_db/2,
env_binary_to_list/2, opt_type/1, may_hide_data/1,
is_elixir_enabled/0, v_dbs/1, v_dbs_mods/1,
is_elixir_enabled/0, v_dbs/1, v_dbs_mods/1, v_host/1, v_hosts/1,
default_db/1, default_db/2, default_ram_db/1, default_ram_db/2,
default_queue_type/1, queue_dir/0, fsm_limit_opts/1,
use_cache/1, cache_size/1, cache_missed/1, cache_life_time/1,
@@ -53,21 +54,16 @@
{get_global_option, 3}, {get_local_option, 3},
{get_option, 3}, {is_file_readable, 1}]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_config.hrl").
-include_lib("kernel/include/file.hrl").
-include_lib("kernel/include/inet.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-callback opt_type(atom()) -> function() | [atom()].
%% @type macro() = {macro_key(), macro_value()}
%% @type macro_key() = atom().
%% The atom must have all characters in uppercase.
%% @type macro_value() = term().
-callback opt_type(atom()) -> fun((any()) -> any()) | [atom()].
-type bad_option() :: invalid_option | unknown_option.
-spec start() -> ok | {error, bad_option()}.
start() ->
ConfigFile = get_ejabberd_config_path(),
?INFO_MSG("Loading configuration from ~s", [ConfigFile]),
@@ -75,17 +71,23 @@ start() ->
[named_table, public, {read_concurrency, true}]),
catch ets:new(ejabberd_db_modules,
[named_table, public, {read_concurrency, true}]),
State1 = load_file(ConfigFile),
UnixTime = p1_time_compat:system_time(seconds),
SharedKey = case erlang:get_cookie() of
nocookie ->
str:sha(randoms:get_string());
Cookie ->
str:sha(misc:atom_to_binary(Cookie))
end,
State2 = set_option({node_start, global}, UnixTime, State1),
State3 = set_option({shared_key, global}, SharedKey, State2),
set_opts(State3).
case load_file(ConfigFile) of
{ok, State1} ->
UnixTime = p1_time_compat:system_time(seconds),
SharedKey = case erlang:get_cookie() of
nocookie ->
str:sha(p1_rand:get_string());
Cookie ->
str:sha(misc:atom_to_binary(Cookie))
end,
State2 = set_option({node_start, global}, UnixTime, State1),
State3 = set_option({shared_key, global}, SharedKey, State2),
set_opts(State3),
ok;
{error, _} = Err ->
?ERROR_MSG("Failed to load configuration file ~s", [ConfigFile]),
Err
end.
%% When starting ejabberd for testing, we sometimes want to start a
%% subset of hosts from the one define in the config file.
@@ -114,7 +116,7 @@ start(Hosts, Opts) ->
UnixTime = p1_time_compat:system_time(seconds),
SharedKey = case erlang:get_cookie() of
nocookie ->
str:sha(randoms:get_string());
str:sha(p1_rand:get_string());
Cookie ->
str:sha(misc:atom_to_binary(Cookie))
end,
@@ -135,7 +137,7 @@ get_ejabberd_config_path() ->
undefined ->
case os:getenv("EJABBERD_CONFIG_PATH") of
false ->
?CONFIG_PATH;
"ejabberd.yml";
Path ->
Path
end
@@ -189,7 +191,7 @@ read_file(File, Opts) ->
State1 = lists:foldl(fun process_term/2, State, Head ++ Tail),
State1#state{opts = compact(State1#state.opts)}.
-spec load_file(string()) -> #state{}.
-spec load_file(string()) -> {ok, #state{}} | {error, bad_option()}.
load_file(File) ->
State0 = read_file(File),
@@ -199,23 +201,27 @@ load_file(File) ->
ModOpts = get_modules_with_options(AllMods),
validate_opts(State1, ModOpts).
-spec reload_file() -> ok.
-spec reload_file() -> ok | {error, bad_option()}.
reload_file() ->
Config = get_ejabberd_config_path(),
OldHosts = get_myhosts(),
State = load_file(Config),
set_opts(State),
NewHosts = get_myhosts(),
lists:foreach(
fun(Host) ->
ejabberd_hooks:run(host_up, [Host])
end, NewHosts -- OldHosts),
lists:foreach(
fun(Host) ->
ejabberd_hooks:run(host_down, [Host])
end, OldHosts -- NewHosts),
ejabberd_hooks:run(config_reloaded, []).
case load_file(Config) of
{error, _} = Err ->
Err;
{ok, State} ->
set_opts(State),
NewHosts = get_myhosts(),
lists:foreach(
fun(Host) ->
ejabberd_hooks:run(host_up, [Host])
end, NewHosts -- OldHosts),
lists:foreach(
fun(Host) ->
ejabberd_hooks:run(host_down, [Host])
end, OldHosts -- NewHosts),
ejabberd_hooks:run(config_reloaded, [])
end.
-spec convert_to_yaml(file:filename()) -> ok | {error, any()}.
@@ -777,8 +783,24 @@ set_opts(State) ->
fun(#local_config{key = Key, value = Val}) ->
{Key, Val}
end, Opts)),
set_fqdn(),
set_log_level().
set_fqdn() ->
FQDNs = case get_option(fqdn, []) of
[] ->
{ok, Hostname} = inet:gethostname(),
case inet:gethostbyname(Hostname) of
{ok, #hostent{h_name = FQDN}} ->
[iolist_to_binary(FQDN)];
{error, _} ->
[]
end;
Domains ->
Domains
end,
xmpp:set_config([{fqdn, FQDNs}]).
set_log_level() ->
Level = get_option(loglevel, 4),
ejabberd_logger:set(Level).
@@ -949,6 +971,33 @@ v_dbs_mods(Mod) ->
(atom_to_binary(M, utf8))/binary>>, utf8)
end, v_dbs(Mod)).
-spec v_host(binary()) -> binary().
v_host(Host) ->
hd(v_hosts([Host])).
-spec v_hosts([binary()]) -> [binary()].
v_hosts(Hosts) ->
ServerHosts = get_myhosts(),
lists:foldr(
fun(Host, Acc) ->
case lists:member(Host, ServerHosts) of
true ->
?ERROR_MSG("Failed to reuse route ~s because it's "
"already registered on a virtual host",
[Host]),
erlang:error(badarg);
false ->
case lists:member(Host, Acc) of
true ->
?ERROR_MSG("Host ~s is defined multiple times",
[Host]),
erlang:error(badarg);
false ->
[Host|Acc]
end
end
end, [], Hosts).
-spec default_db(module()) -> atom().
default_db(Module) ->
default_db(global, Module).
@@ -1017,33 +1066,40 @@ get_modules_with_options(Modules) ->
end
end, dict:new(), Modules).
-spec validate_opts(#state{}, dict:dict()) -> {ok, #state{}} | {error, bad_option()}.
validate_opts(#state{opts = Opts} = State, ModOpts) ->
NewOpts = lists:filtermap(
fun(#local_config{key = {Opt, _Host}, value = Val} = In) ->
case dict:find(Opt, ModOpts) of
{ok, [Mod|_]} ->
VFun = Mod:opt_type(Opt),
try VFun(Val) of
NewVal ->
{true, In#local_config{value = NewVal}}
catch {invalid_syntax, Error} ->
?ERROR_MSG("ignoring option '~s' with "
"invalid value: ~p: ~s",
[Opt, Val, Error]),
false;
_:_ ->
?ERROR_MSG("ignoring option '~s' with "
"invalid value: ~p",
[Opt, Val]),
false
end;
_ ->
?ERROR_MSG("unknown option '~s' will be likely"
" ignored", [Opt]),
true
end
end, Opts),
State#state{opts = NewOpts}.
try
NewOpts = lists:map(
fun(#local_config{key = {Opt, _Host}, value = Val} = In) ->
case dict:find(Opt, ModOpts) of
{ok, [Mod|_]} ->
VFun = Mod:opt_type(Opt),
try VFun(Val) of
NewVal ->
In#local_config{value = NewVal}
catch {invalid_syntax, Error} ->
?ERROR_MSG("Invalid value for "
"option '~s' (~s): ~s",
[Opt, Error,
misc:format_val({yaml, Val})]),
erlang:error(invalid_option);
_:R when R /= undef ->
?ERROR_MSG("Invalid value for "
"option '~s': ~s",
[Opt, misc:format_val({yaml, Val})]),
erlang:error(invalid_option)
end;
_ ->
?ERROR_MSG("Unknown option '~s'", [Opt]),
erlang:error(unknown_option)
end
end, Opts),
{ok, State#state{opts = NewOpts}}
catch _:invalid_option ->
{error, invalid_option};
_:unknown_option ->
{error, unknown_option}
end.
%% @spec (Path::string()) -> true | false
is_file_readable(Path) ->
@@ -1059,15 +1115,27 @@ is_file_readable(Path) ->
end.
get_version() ->
case application:get_key(ejabberd, vsn) of
undefined -> "";
{ok, Vsn} -> list_to_binary(Vsn)
case application:get_env(ejabberd, custom_vsn) of
{ok, Vsn0} when is_list(Vsn0) ->
list_to_binary(Vsn0);
{ok, Vsn1} when is_binary(Vsn1) ->
Vsn1;
_ ->
case application:get_key(ejabberd, vsn) of
undefined -> "";
{ok, Vsn} -> list_to_binary(Vsn)
end
end.
-spec get_myhosts() -> [binary()].
get_myhosts() ->
get_option(hosts).
get_option(hosts, [<<"localhost">>]).
-spec get_myname() -> binary().
get_myname() ->
hd(get_myhosts()).
-spec get_mylang() -> binary().
@@ -1078,10 +1146,17 @@ get_mylang() ->
get_lang(Host) ->
get_option({language, Host}, <<"en">>).
-spec get_uri() -> binary().
get_uri() ->
<<"http://www.process-one.net/en/ejabberd/">>.
-spec get_copyright() -> binary().
get_copyright() ->
<<"Copyright (c) ProcessOne">>.
replace_module(mod_announce_odbc) -> {mod_announce, sql};
replace_module(mod_blocking_odbc) -> {mod_blocking, sql};
replace_module(mod_caps_odbc) -> {mod_caps, sql};
replace_module(mod_irc_odbc) -> {mod_irc, sql};
replace_module(mod_last_odbc) -> {mod_last, sql};
replace_module(mod_muc_odbc) -> {mod_muc, sql};
replace_module(mod_offline_odbc) -> {mod_offline, sql};
@@ -1215,7 +1290,7 @@ transform_terms(Terms) ->
ejabberd_s2s,
ejabberd_listener,
ejabberd_sql_sup,
shaper,
ejabberd_shaper,
ejabberd_s2s_out,
acl,
ejabberd_config],
@@ -1364,22 +1439,7 @@ emit_deprecation_warning(Module, NewModule) ->
now_to_seconds({MegaSecs, Secs, _MicroSecs}) ->
MegaSecs * 1000000 + Secs.
-spec opt_type(hide_sensitive_log_data) -> fun((boolean()) -> boolean());
(hosts) -> fun(([binary()]) -> [binary()]);
(language) -> fun((binary()) -> binary());
(max_fsm_queue) -> fun((pos_integer()) -> pos_integer());
(default_db) -> fun((atom()) -> atom());
(default_ram_db) -> fun((atom()) -> atom());
(loglevel) -> fun((0..5) -> 0..5);
(queue_dir) -> fun((binary()) -> binary());
(queue_type) -> fun((ram | file) -> ram | file);
(use_cache) -> fun((boolean()) -> boolean());
(cache_size) -> fun((timeout()) -> timeout());
(cache_missed) -> fun((boolean()) -> boolean());
(cache_life_time) -> fun((timeout()) -> timeout());
(shared_key) -> fun((binary()) -> binary());
(node_start) -> fun((non_neg_integer()) -> non_neg_integer());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(hide_sensitive_log_data) ->
fun (H) when is_boolean(H) -> H end;
opt_type(hosts) ->
@@ -1422,10 +1482,16 @@ opt_type(node_start) ->
fun(I) when is_integer(I), I>=0 -> I end;
opt_type(validate_stream) ->
fun(B) when is_boolean(B) -> B end;
opt_type(fqdn) ->
fun(Domain) when is_binary(Domain) ->
[Domain];
(Domains) ->
[iolist_to_binary(Domain) || Domain <- Domains]
end;
opt_type(_) ->
[hide_sensitive_log_data, hosts, language, max_fsm_queue,
default_db, default_ram_db, queue_type, queue_dir, loglevel,
use_cache, cache_size, cache_missed, cache_life_time,
use_cache, cache_size, cache_missed, cache_life_time, fqdn,
shared_key, node_start, validate_stream, negotiation_timeout].
-spec may_hide_data(any()) -> any().
+4 -6
View File
@@ -58,7 +58,6 @@
-include("ejabberd_ctl.hrl").
-include("ejabberd_commands.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").
-define(DEFAULT_VERSION, 1000000).
@@ -169,15 +168,15 @@ process(["status"], _Version) ->
{InternalStatus, ProvidedStatus} = init:get_status(),
print("The node ~p is ~p with status: ~p~n",
[node(), InternalStatus, ProvidedStatus]),
case lists:keysearch(ejabberd, 1, application:which_applications()) of
case lists:keymember(ejabberd, 1, application:which_applications()) of
false ->
EjabberdLogPath = ejabberd_logger:get_log_path(),
print("ejabberd is not running in that node~n"
"Check for error messages: ~s~n"
"or other files in that directory.~n", [EjabberdLogPath]),
?STATUS_ERROR;
{value, {_, _, Version}} ->
print("ejabberd ~s is running in that node~n", [Version]),
true ->
print("ejabberd ~s is running in that node~n", [ejabberd_config:get_version()]),
?STATUS_SUCCESS
end;
@@ -875,8 +874,7 @@ print(Format, Args) ->
%% ["aaaa bbb ccc"].
-spec opt_type(ejabberdctl_access_commands) -> fun((list()) -> list());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(ejabberdctl_access_commands) ->
fun (V) when is_list(V) -> V end;
opt_type(_) -> [ejabberdctl_access_commands].
+2 -1
View File
@@ -380,11 +380,12 @@ safe_apply(Hook, Module, Function, Args) ->
apply(Module, Function, Args)
end
catch E:R when E /= exit; R /= normal ->
St = get_stacktrace(),
?ERROR_MSG("Hook ~p crashed when running ~p:~p/~p:~n"
"** Reason = ~p~n"
"** Arguments = ~p",
[Hook, Module, Function, length(Args),
{E, R, get_stacktrace()}, Args]),
{E, R, St}, Args]),
'EXIT'
end.
+255 -191
View File
@@ -24,24 +24,23 @@
%%%----------------------------------------------------------------------
-module(ejabberd_http).
-behaviour(ejabberd_listener).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
%% External exports
-export([start/2, start_link/2, become_controller/1,
socket_type/0, receive_headers/1,
transform_listen_option/2, listen_opt_type/1]).
-export([start/2, start_link/2,
accept/1, receive_headers/1, recv_file/2,
transform_listen_option/2, listen_opt_type/1,
listen_options/0]).
-export([init/2, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("ejabberd_http.hrl").
-include_lib("kernel/include/file.hrl").
-record(state, {sockmod,
socket,
@@ -50,7 +49,7 @@
request_path,
request_auth,
request_keepalive,
request_content_length,
request_content_length = 0,
request_lang = <<"en">>,
%% XXX bard: request handlers are configured in
%% ejabberd.cfg under the HTTP service. For example,
@@ -85,6 +84,10 @@
"org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
"">>).
-define(RECV_BUF, 65536).
-define(SEND_BUF, 65536).
-define(MAX_POST_SIZE, 20971520). %% 20Mb
start(SockData, Opts) ->
{ok,
proc_lib:spawn(ejabberd_http, init,
@@ -99,6 +102,7 @@ init({SockMod, Socket}, Opts) ->
TLSEnabled = proplists:get_bool(tls, Opts),
TLSOpts1 = lists:filter(fun ({ciphers, _}) -> true;
({dhfile, _}) -> true;
({cafile, _}) -> true;
({protocol_options, _}) -> true;
(_) -> false
end,
@@ -113,7 +117,7 @@ init({SockMod, Socket}, Opts) ->
end,
TLSOpts = [verify_none | TLSOpts3],
{SockMod1, Socket1} = if TLSEnabled ->
inet:setopts(Socket, [{recbuf, 8192}]),
inet:setopts(Socket, [{recbuf, ?RECV_BUF}]),
{ok, TLSSocket} = fast_tls:tcp_to_tls(Socket,
TLSOpts),
{fast_tls, TLSSocket};
@@ -162,24 +166,47 @@ init({SockMod, Socket}, Opts) ->
{error, _} -> State
end.
become_controller(_Pid) ->
accept(_Pid) ->
ok.
socket_type() ->
raw.
send_text(_State, none) ->
ok;
send_text(State, Text) ->
case catch
(State#state.sockmod):send(State#state.socket, Text)
of
ok -> ok;
{error, timeout} ->
?INFO_MSG("Timeout on ~p:send", [State#state.sockmod]),
exit(normal);
Error ->
?DEBUG("Error in ~p:send: ~p",
[State#state.sockmod, Error]),
exit(normal)
case (State#state.sockmod):send(State#state.socket, Text) of
ok -> ok;
{error, timeout} ->
?INFO_MSG("Timeout on ~p:send", [State#state.sockmod]),
exit(normal);
Error ->
?DEBUG("Error in ~p:send: ~p",
[State#state.sockmod, Error]),
exit(normal)
end.
send_file(State, Fd, Size, FileName) ->
try
case State#state.sockmod of
gen_tcp ->
case file:sendfile(Fd, State#state.socket, 0, Size, []) of
{ok, _} -> ok
end;
_ ->
case file:read(Fd, ?SEND_BUF) of
{ok, Data} ->
send_text(State, Data),
send_file(State, Fd, Size, FileName);
eof ->
ok
end
end
catch _:{case_clause, {error, Why}} ->
if Why /= closed ->
?WARNING_MSG("Failed to read ~s: ~s",
[FileName, file_format_error(Why)]),
exit(normal);
true ->
ok
end
end.
receive_headers(#state{trail = Trail} = State) ->
@@ -348,8 +375,8 @@ get_transfer_protocol(RE, SockMod, HostPort) ->
%% matches the requested URL path, and pass control to it. If none is
%% found, answer with HTTP 404.
process([], _, _, _, _) -> ejabberd_web:error(not_found);
process(Handlers, Request, Socket, SockMod, Trail) ->
process([], _) -> ejabberd_web:error(not_found);
process(Handlers, Request) ->
{HandlerPathPrefix, HandlerModule, HandlerOpts, HandlersLeft} =
case Handlers of
[{Pfx, Mod} | Tail] ->
@@ -369,14 +396,14 @@ process(Handlers, Request, Socket, SockMod, Trail) ->
LocalPath = lists:nthtail(length(HandlerPathPrefix), Request#request.path),
R = try
HandlerModule:socket_handoff(
LocalPath, Request, Socket, SockMod, Trail, HandlerOpts)
LocalPath, Request, HandlerOpts)
catch error:undef ->
HandlerModule:process(LocalPath, Request)
end,
ejabberd_hooks:run(http_request_debug, [{LocalPath, Request}]),
R;
false ->
process(HandlersLeft, Request, Socket, SockMod, Trail)
process(HandlersLeft, Request)
end.
extract_path_query(#state{request_method = Method,
@@ -398,24 +425,29 @@ extract_path_query(#state{request_method = Method,
extract_path_query(#state{request_method = Method,
request_path = {abs_path, Path},
request_content_length = Len,
trail = Trail,
sockmod = _SockMod,
socket = _Socket} = State)
when (Method =:= 'POST' orelse Method =:= 'PUT') andalso
is_integer(Len) ->
case recv_data(State, Len) of
error -> {State, false};
{NewState, Data} ->
?DEBUG("client data: ~p~n", [Data]),
when (Method =:= 'POST' orelse Method =:= 'PUT') andalso Len>0 ->
case catch url_decode_q_split(Path) of
{'EXIT', _} -> {NewState, false};
{'EXIT', _} -> {State, false};
{NPath, _Query} ->
LPath = normalize_path([NPE
|| NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
LQuery = case catch parse_urlencoded(Data) of
{'EXIT', _Reason} -> [];
LQ -> LQ
end,
{NewState, {LPath, LQuery, Data}}
LPath = normalize_path(
[NPE || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
case Method of
'PUT' ->
{State, {LPath, [], Trail}};
'POST' ->
case recv_data(State) of
{ok, Data} ->
LQuery = case catch parse_urlencoded(Data) of
{'EXIT', _Reason} -> [];
LQ -> LQ
end,
{State, {LPath, LQuery, Data}};
error ->
{State, false}
end
end
end;
extract_path_query(State) ->
@@ -428,16 +460,23 @@ process_request(#state{request_host = undefined,
process_request(#state{request_method = Method,
request_auth = Auth,
request_lang = Lang,
request_version = Version,
sockmod = SockMod,
socket = Socket,
options = Options,
request_host = Host,
request_port = Port,
request_tp = TP,
request_content_length = Length,
request_headers = RequestHeaders,
request_handlers = RequestHandlers,
custom_headers = CustomHeaders,
trail = Trail} = State) ->
custom_headers = CustomHeaders} = State) ->
case proplists:get_value(<<"Expect">>, RequestHeaders, <<>>) of
<<"100-", _/binary>> when Version == {1, 1} ->
send_text(State, <<"HTTP/1.1 100 Continue\r\n\r\n">>);
_ ->
ok
end,
case extract_path_query(State) of
{State2, false} ->
{State2, make_bad_request(State)};
@@ -459,7 +498,10 @@ process_request(#state{request_method = Method,
path = LPath,
q = LQuery,
auth = Auth,
data = Data,
length = Length,
sockmod = SockMod,
socket = Socket,
data = Data,
lang = Lang,
host = Host,
port = Port,
@@ -469,7 +511,7 @@ process_request(#state{request_method = Method,
ip = IP},
RequestHandlers1 = ejabberd_hooks:run_fold(
http_request_handlers, RequestHandlers, [Host, Request]),
Res = case process(RequestHandlers1, Request, Socket, SockMod, Trail) of
Res = case process(RequestHandlers1, Request) of
El when is_record(El, xmlel) ->
make_xhtml_output(State, 200, CustomHeaders, El);
{Status, Headers, El}
@@ -482,6 +524,8 @@ process_request(#state{request_method = Method,
when is_binary(Output) or is_list(Output) ->
make_text_output(State, Status,
Headers ++ CustomHeaders, Output);
{Status, Headers, {file, FileName}} ->
make_file_output(State, Status, Headers, FileName);
{Status, Reason, Headers, Output}
when is_binary(Output) or is_list(Output) ->
make_text_output(State, Status, Reason,
@@ -489,7 +533,7 @@ process_request(#state{request_method = Method,
_ ->
none
end,
{State2, Res}
{State2#state{trail = <<>>}, Res}
end.
make_bad_request(State) ->
@@ -519,118 +563,98 @@ analyze_ip_xff({IPLast, Port}, XFF, Host) ->
end,
{IPClient, Port}.
is_ipchain_trusted([], _) -> false;
is_ipchain_trusted(_UserIPs, all) -> true;
is_ipchain_trusted(UserIPs, TrustedIPs) ->
[] == UserIPs -- [<<"127.0.0.1">> | TrustedIPs].
is_ipchain_trusted(UserIPs, Masks) ->
lists:all(
fun(IP) ->
case inet:parse_address(binary_to_list(IP)) of
{ok, IP2} ->
lists:any(
fun({Mask, MaskLen}) ->
acl:ip_matches_mask(IP2, Mask, MaskLen)
end, [{{127,0,0,1}, 8} | Masks]);
_ ->
false
end
end, UserIPs).
recv_data(State, Len) -> recv_data(State, Len, <<>>).
recv_data(State, 0, Acc) -> {State, Acc};
recv_data(#state{trail = Trail} = State, Len, <<>>) when byte_size(Trail) > Len ->
<<Data:Len/binary, Rest/binary>> = Trail,
{State#state{trail = Rest}, Data};
recv_data(State, Len, Acc) ->
case State#state.trail of
<<>> ->
case (State#state.sockmod):recv(State#state.socket,
min(Len, 16#4000000), 300000)
of
{ok, Data} ->
recv_data(State, Len - byte_size(Data), <<Acc/binary, Data/binary>>);
Err ->
?DEBUG("Cannot receive HTTP data: ~p", [Err]),
error
recv_data(#state{request_content_length = Len}) when Len >= ?MAX_POST_SIZE ->
error;
recv_data(#state{request_content_length = Len, trail = Trail,
sockmod = SockMod, socket = Socket}) ->
NewLen = Len - byte_size(Trail),
if NewLen > 0 ->
case SockMod:recv(Socket, NewLen, 60000) of
{ok, Data} -> {ok, <<Trail/binary, Data/binary>>};
{error, _} -> error
end;
_ ->
Trail = (State#state.trail),
recv_data(State#state{trail = <<>>},
Len - byte_size(Trail), <<Acc/binary, Trail/binary>>)
true ->
{ok, Trail}
end.
make_xhtml_output(State, Status, Headers, XHTML) ->
Data = case lists:member(html, Headers) of
true ->
iolist_to_binary([?HTML_DOCTYPE,
fxml:element_to_binary(XHTML)]);
_ ->
iolist_to_binary([?XHTML_DOCTYPE,
fxml:element_to_binary(XHTML)])
end,
Headers1 = case lists:keysearch(<<"Content-Type">>, 1,
Headers)
of
{value, _} ->
[{<<"Content-Length">>,
integer_to_binary(byte_size(Data))}
| Headers];
_ ->
[{<<"Content-Type">>, <<"text/html; charset=utf-8">>},
{<<"Content-Length">>,
integer_to_binary(byte_size(Data))}
| Headers]
end,
HeadersOut = case {State#state.request_version,
State#state.request_keepalive}
of
{{1, 1}, true} -> Headers1;
{_, true} ->
[{<<"Connection">>, <<"keep-alive">>} | Headers1];
{_, false} ->
[{<<"Connection">>, <<"close">>} | Headers1]
end,
Version = case State#state.request_version of
{1, 1} -> <<"HTTP/1.1 ">>;
_ -> <<"HTTP/1.0 ">>
end,
H = lists:map(fun ({Attr, Val}) ->
[Attr, <<": ">>, Val, <<"\r\n">>];
(_) -> []
recv_file(#request{length = Len, data = Trail,
sockmod = SockMod, socket = Socket}, Path) ->
case file:open(Path, [write, exclusive, raw]) of
{ok, Fd} ->
Res = case file:write(Fd, Trail) of
ok ->
NewLen = max(0, Len - byte_size(Trail)),
do_recv_file(NewLen, SockMod, Socket, Fd);
{error, _} = Err ->
Err
end,
HeadersOut),
SL = [Version,
integer_to_binary(Status), <<" ">>,
code_to_phrase(Status), <<"\r\n">>],
Data2 = case State#state.request_method of
'HEAD' -> <<"">>;
_ -> Data
file:close(Fd),
case Res of
ok -> ok;
{error, _} -> file:delete(Path)
end,
[SL, H, <<"\r\n">>, Data2].
Res;
{error, _} = Err ->
Err
end.
make_text_output(State, Status, Headers, Text) ->
make_text_output(State, Status, <<"">>, Headers, Text).
do_recv_file(0, _SockMod, _Socket, _Fd) ->
ok;
do_recv_file(Len, SockMod, Socket, Fd) ->
ChunkLen = min(Len, ?RECV_BUF),
case SockMod:recv(Socket, ChunkLen, timer:seconds(30)) of
{ok, Data} ->
case file:write(Fd, Data) of
ok ->
do_recv_file(Len-size(Data), SockMod, Socket, Fd);
{error, _} = Err ->
Err
end;
{error, _} ->
{error, closed}
end.
make_text_output(State, Status, Reason, Headers, Text) ->
Data = iolist_to_binary(Text),
Headers1 = case lists:keysearch(<<"Content-Type">>, 1,
Headers)
of
{value, _} ->
[{<<"Content-Length">>,
integer_to_binary(byte_size(Data))}
| Headers];
_ ->
[{<<"Content-Type">>, <<"text/html; charset=utf-8">>},
{<<"Content-Length">>,
integer_to_binary(byte_size(Data))}
| Headers]
make_headers(State, Status, Reason, Headers, Data) ->
Len = if is_integer(Data) -> Data;
true -> iolist_size(Data)
end,
Headers1 = [{<<"Content-Length">>, integer_to_binary(Len)} | Headers],
Headers2 = case lists:keyfind(<<"Content-Type">>, 1, Headers) of
{_, _} ->
Headers1;
false ->
[{<<"Content-Type">>, <<"text/html; charset=utf-8">>}
| Headers1]
end,
HeadersOut = case {State#state.request_version,
State#state.request_keepalive}
of
{{1, 1}, true} -> Headers1;
{_, true} ->
[{<<"Connection">>, <<"keep-alive">>} | Headers1];
{_, false} ->
[{<<"Connection">>, <<"close">>} | Headers1]
State#state.request_keepalive} of
{{1, 1}, true} -> Headers2;
{_, true} ->
[{<<"Connection">>, <<"keep-alive">>} | Headers2];
{_, false} ->
[{<<"Connection">>, <<"close">>} | Headers2]
end,
Version = case State#state.request_version of
{1, 1} -> <<"HTTP/1.1 ">>;
_ -> <<"HTTP/1.0 ">>
{1, 1} -> <<"HTTP/1.1 ">>;
_ -> <<"HTTP/1.0 ">>
end,
H = lists:map(fun ({Attr, Val}) ->
[Attr, <<": ">>, Val, <<"\r\n">>]
end,
HeadersOut),
H = [[Attr, <<": ">>, Val, <<"\r\n">>] || {Attr, Val} <- HeadersOut],
NewReason = case Reason of
<<"">> -> code_to_phrase(Status);
_ -> Reason
@@ -638,11 +662,55 @@ make_text_output(State, Status, Reason, Headers, Text) ->
SL = [Version,
integer_to_binary(Status), <<" ">>,
NewReason, <<"\r\n">>],
[SL, H, <<"\r\n">>].
make_xhtml_output(State, Status, Headers, XHTML) ->
Data = case State#state.request_method of
'HEAD' -> <<"">>;
_ ->
DocType = case lists:member(html, Headers) of
true -> ?HTML_DOCTYPE;
false -> ?XHTML_DOCTYPE
end,
iolist_to_binary([DocType, fxml:element_to_binary(XHTML)])
end,
EncodedHdrs = make_headers(State, Status, <<"">>, Headers, Data),
[EncodedHdrs, Data].
make_text_output(State, Status, Headers, Text) ->
make_text_output(State, Status, <<"">>, Headers, Text).
make_text_output(State, Status, Reason, Headers, Text) ->
Data = iolist_to_binary(Text),
Data2 = case State#state.request_method of
'HEAD' -> <<"">>;
_ -> Data
'HEAD' -> <<"">>;
_ -> Data
end,
[SL, H, <<"\r\n">>, Data2].
EncodedHdrs = make_headers(State, Status, Reason, Headers, Data2),
[EncodedHdrs, Data2].
make_file_output(State, Status, Headers, FileName) ->
case file:read_file_info(FileName) of
{ok, #file_info{size = Size}} when State#state.request_method == 'HEAD' ->
make_headers(State, Status, <<"">>, Headers, Size);
{ok, #file_info{size = Size}} ->
case file:open(FileName, [raw, read]) of
{ok, Fd} ->
EncodedHdrs = make_headers(State, Status, <<"">>, Headers, Size),
send_text(State, EncodedHdrs),
send_file(State, Fd, Size, FileName),
file:close(Fd),
none;
{error, Why} ->
Reason = file_format_error(Why),
?ERROR_MSG("Failed to open ~s: ~s", [FileName, Reason]),
make_text_output(State, 404, Reason, [], <<>>)
end;
{error, Why} ->
Reason = file_format_error(Why),
?ERROR_MSG("Failed to read info of ~s: ~s", [FileName, Reason]),
make_text_output(State, 404, Reason, [], <<>>)
end.
parse_lang(Langs) ->
case str:tokens(Langs, <<",; ">>) of
@@ -650,6 +718,12 @@ parse_lang(Langs) ->
[] -> <<"en">>
end.
file_format_error(Reason) ->
case file:format_error(Reason) of
"unknown POSIX error" -> atom_to_list(Reason);
Text -> Text
end.
% Code below is taken (with some modifications) from the yaws webserver, which
% is distributed under the following license:
%
@@ -713,7 +787,8 @@ rest_dir(N, Path, <<_H, T/binary>>) -> rest_dir(N, Path, T).
expand_custom_headers(Headers) ->
lists:map(fun({K, V}) ->
{K, misc:expand_keyword(<<"@VERSION@">>, V, ?VERSION)}
{K, misc:expand_keyword(<<"@VERSION@">>, V,
ejabberd_config:get_version())}
end, Headers).
code_to_phrase(100) -> <<"Continue">>;
@@ -843,11 +918,11 @@ get_certfile(Opts) ->
{_, CertFile} ->
CertFile;
false ->
case ejabberd_pkix:get_certfile(?MYNAME) of
case ejabberd_pkix:get_certfile(ejabberd_config:get_myname()) of
{ok, CertFile} ->
CertFile;
error ->
ejabberd_config:get_option({domain_certfile, ?MYNAME})
ejabberd_config:get_option({domain_certfile, ejabberd_config:get_myname()})
end
end.
@@ -873,47 +948,26 @@ transform_listen_option({request_handlers, Hs}, Opts) ->
transform_listen_option(Opt, Opts) ->
[Opt|Opts].
-spec opt_type(trusted_proxies) -> fun((all | [binary()]) -> all | [binary()]);
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(trusted_proxies) ->
fun (all) -> all;
(TPs) -> [iolist_to_binary(TP) || TP <- TPs] end;
(TPs) -> lists:filtermap(
fun(TP) ->
case acl:parse_ip_netmask(iolist_to_binary(TP)) of
{ok, Ip, Mask} -> {true, {Ip, Mask}};
_ -> false
end
end, TPs)
end;
opt_type(_) -> [trusted_proxies].
-spec listen_opt_type(tls) -> fun((boolean()) -> boolean());
(certfile) -> fun((binary()) -> binary());
(ciphers) -> fun((binary()) -> binary());
(dhfile) -> fun((binary()) -> binary());
(protocol_options) -> fun(([binary()]) -> binary());
(tls_compression) -> fun((boolean()) -> boolean());
(captcha) -> fun((boolean()) -> boolean());
(register) -> fun((boolean()) -> boolean());
(web_admin) -> fun((boolean()) -> boolean());
(http_bind) -> fun((boolean()) -> boolean());
(xmlrpc) -> fun((boolean()) -> boolean());
(request_handlers) -> fun(([{binary(), atom()}]) ->
[{binary(), atom()}]);
(default_host) -> fun((binary()) -> binary());
(custom_headers) -> fun(([{binary(), binary()}]) ->
[{binary(), binary()}]);
(atom()) -> [atom()].
listen_opt_type(tls) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(certfile = Opt) ->
fun(S) ->
?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
"'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
ok = ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(ciphers) ->
fun iolist_to_binary/1;
listen_opt_type(dhfile) ->
fun misc:try_read_file/1;
listen_opt_type(protocol_options) ->
fun(Options) -> str:join(Options, <<"|">>) end;
listen_opt_type(tls_compression) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(captcha) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(register) ->
@@ -940,13 +994,23 @@ listen_opt_type(request_handlers) ->
end} || {Path, Mod} <- Hs2]
end;
listen_opt_type(default_host) ->
fun(A) -> A end;
fun iolist_to_binary/1;
listen_opt_type(custom_headers) ->
fun expand_custom_headers/1;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(_) ->
%% TODO
fun(A) -> A end.
fun expand_custom_headers/1.
listen_options() ->
[{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{captcha, false},
{register, false},
{web_admin, false},
{http_bind, false},
{xmlrpc, false},
{request_handlers, []},
{default_host, undefined},
{custom_headers, []}].
+51 -63
View File
@@ -23,21 +23,18 @@
%%%
%%%----------------------------------------------------------------------
-module(ejabberd_http_ws).
-behaviour(ejabberd_config).
-author('ecestari@process-one.net').
-behaviour(ejabberd_config).
-behaviour(xmpp_socket).
-behaviour(p1_fsm).
-export([start/1, start_link/1, init/1, handle_event/3,
handle_sync_event/4, code_change/4, handle_info/3,
terminate/3, send_xml/2, setopts/2, sockname/1,
peername/1, controlling_process/2, become_controller/2,
monitor/1, reset_stream/1, close/1, change_shaper/2,
socket_handoff/6, opt_type/1]).
peername/1, controlling_process/2, get_owner/1,
reset_stream/1, close/1, change_shaper/2,
socket_handoff/3, get_transport/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
@@ -55,8 +52,8 @@
timeout = ?WEBSOCKET_TIMEOUT :: non_neg_integer(),
timer = make_ref() :: reference(),
input = [] :: list(),
waiting_input = false :: false | pid(),
last_receiver = self() :: pid(),
active = false :: boolean(),
c2s_pid :: pid(),
ws :: {#ws{}, pid()},
rfc_compilant = undefined :: boolean() | undefined}).
@@ -105,15 +102,9 @@ peername({http_ws, _FsmRef, IP}) -> {ok, IP}.
controlling_process(_Socket, _Pid) -> ok.
become_controller(FsmRef, C2SPid) ->
p1_fsm:send_all_state_event(FsmRef, {activate, C2SPid}).
close({http_ws, FsmRef, _IP}) ->
catch p1_fsm:sync_send_all_state_event(FsmRef, close).
monitor({http_ws, FsmRef, _IP}) ->
erlang:monitor(process, FsmRef).
reset_stream({http_ws, _FsmRef, _IP} = Socket) ->
Socket.
@@ -121,9 +112,14 @@ change_shaper({http_ws, _FsmRef, _IP}, _Shaper) ->
%% TODO???
ok.
socket_handoff(LocalPath, Request, Socket, SockMod, Buf, Opts) ->
ejabberd_websocket:socket_handoff(LocalPath, Request, Socket, SockMod,
Buf, Opts, ?MODULE, fun get_human_html_xmlel/0).
get_transport(_Socket) ->
websocket.
get_owner({http_ws, FsmRef, _IP}) ->
FsmRef.
socket_handoff(LocalPath, Request, Opts) ->
ejabberd_websocket:socket_handoff(LocalPath, Request, Opts, ?MODULE, fun get_human_html_xmlel/0).
%%% Internal
@@ -139,39 +135,42 @@ init([{#ws{ip = IP, http_opts = HOpts}, _} = WS]) ->
end, HOpts),
Opts = ejabberd_c2s_config:get_c2s_limits() ++ SOpts,
PingInterval = ejabberd_config:get_option(
{websocket_ping_interval, ?MYNAME},
{websocket_ping_interval, ejabberd_config:get_myname()},
?PING_INTERVAL) * 1000,
WSTimeout = ejabberd_config:get_option(
{websocket_timeout, ?MYNAME},
{websocket_timeout, ejabberd_config:get_myname()},
?WEBSOCKET_TIMEOUT) * 1000,
Socket = {http_ws, self(), IP},
?DEBUG("Client connected through websocket ~p",
[Socket]),
xmpp_socket:start(ejabberd_c2s, ?MODULE, Socket,
[{receiver, self()}|Opts]),
Timer = erlang:start_timer(WSTimeout, self(), []),
{ok, loop,
#state{socket = Socket, timeout = WSTimeout,
timer = Timer, ws = WS,
ping_interval = PingInterval}}.
handle_event({activate, From}, StateName, StateData) ->
case StateData#state.input of
[] ->
{next_state, StateName,
StateData#state{waiting_input = From}};
Input ->
Receiver = From,
lists:foreach(fun(I) when is_binary(I)->
Receiver ! {tcp, StateData#state.socket, I};
(I2) ->
Receiver ! {tcp, StateData#state.socket, [I2]}
end, Input),
{next_state, StateName,
StateData#state{input = [], waiting_input = false,
last_receiver = Receiver}}
case ejabberd_c2s:start({?MODULE, Socket}, [{receiver, self()}|Opts]) of
{ok, C2SPid} ->
ejabberd_c2s:accept(C2SPid),
Timer = erlang:start_timer(WSTimeout, self(), []),
{ok, loop,
#state{socket = Socket, timeout = WSTimeout,
timer = Timer, ws = WS, c2s_pid = C2SPid,
ping_interval = PingInterval}};
{error, Reason} ->
{stop, Reason};
ignore ->
ignore
end.
handle_event({activate, From}, StateName, State) ->
State1 = case State#state.input of
[] -> State#state{active = true};
Input ->
lists:foreach(
fun(I) when is_binary(I)->
From ! {tcp, State#state.socket, I};
(I2) ->
From ! {tcp, State#state.socket, [I2]}
end, Input),
State#state{active = false, input = []}
end,
{next_state, StateName, State1#state{c2s_pid = From}}.
handle_sync_event({send_xml, Packet}, _From, StateName,
#state{ws = {_, WsPid}, rfc_compilant = R} = StateData) ->
Packet2 = case {case R of undefined -> true; V -> V end, Packet} of
@@ -235,14 +234,13 @@ handle_info(closed, _StateName, StateData) ->
{stop, normal, StateData};
handle_info({received, Packet}, StateName, StateDataI) ->
{StateData, Parsed} = parse(StateDataI, Packet),
SD = case StateData#state.waiting_input of
SD = case StateData#state.active of
false ->
Input = StateData#state.input ++ if is_binary(Parsed) -> [Parsed]; true -> Parsed end,
StateData#state{input = Input};
Receiver ->
Receiver ! {tcp, StateData#state.socket, Parsed},
setup_timers(StateData#state{waiting_input = false,
last_receiver = Receiver})
true ->
StateData#state.c2s_pid ! {tcp, StateData#state.socket, Parsed},
setup_timers(StateData#state{active = false})
end,
{next_state, StateName, SD};
handle_info(PingPong, StateName, StateData) when PingPong == ping orelse
@@ -258,7 +256,7 @@ handle_info({timeout, Timer, _}, StateName,
#state{ping_timer = Timer, ws = {_, WsPid}} = StateData) ->
case StateData#state.pong_expected of
false ->
cancel_timer(StateData#state.ping_timer),
misc:cancel_timer(StateData#state.ping_timer),
PingTimer = erlang:start_timer(StateData#state.ping_interval,
self(), []),
WsPid ! {ping, <<>>},
@@ -275,19 +273,13 @@ code_change(_OldVsn, StateName, StateData, _Extra) ->
{ok, StateName, StateData}.
terminate(_Reason, _StateName, StateData) ->
case StateData#state.waiting_input of
false -> ok;
Receiver ->
?DEBUG("C2S Pid : ~p", [Receiver]),
Receiver ! {tcp_closed, StateData#state.socket}
end,
ok.
StateData#state.c2s_pid ! {tcp_closed, StateData#state.socket}.
setup_timers(StateData) ->
cancel_timer(StateData#state.timer),
misc:cancel_timer(StateData#state.timer),
Timer = erlang:start_timer(StateData#state.timeout,
self(), []),
cancel_timer(StateData#state.ping_timer),
misc:cancel_timer(StateData#state.ping_timer),
PingTimer = case StateData#state.ping_interval of
0 -> StateData#state.ping_timer;
V -> erlang:start_timer(V, self(), [])
@@ -295,10 +287,6 @@ setup_timers(StateData) ->
StateData#state{timer = Timer, ping_timer = PingTimer,
pong_expected = false}.
cancel_timer(Timer) ->
erlang:cancel_timer(Timer),
receive {timeout, Timer, _} -> ok after 0 -> ok end.
get_human_html_xmlel() ->
Heading = <<"ejabberd ", (misc:atom_to_binary(?MODULE))/binary>>,
#xmlel{name = <<"html">>,
-224
View File
@@ -1,224 +0,0 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_idna.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Support for IDNA (RFC3490)
%%% Created : 10 Apr 2004 by Alexey Shchepin <alexey@process-one.net>
%%%
%%%
%%% ejabberd, Copyright (C) 2002-2018 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-module(ejabberd_idna).
-author('alexey@process-one.net').
-export([domain_utf8_to_ascii/1,
domain_ucs2_to_ascii/1,
utf8_to_ucs2/1]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
-spec domain_utf8_to_ascii(binary()) -> false | binary().
domain_utf8_to_ascii(Domain) ->
domain_ucs2_to_ascii(utf8_to_ucs2(Domain)).
utf8_to_ucs2(S) ->
utf8_to_ucs2(binary_to_list(S), "").
utf8_to_ucs2([], R) -> lists:reverse(R);
utf8_to_ucs2([C | S], R) when C < 128 ->
utf8_to_ucs2(S, [C | R]);
utf8_to_ucs2([C1, C2 | S], R) when C1 < 224 ->
utf8_to_ucs2(S, [C1 band 31 bsl 6 bor C2 band 63 | R]);
utf8_to_ucs2([C1, C2, C3 | S], R) when C1 < 240 ->
utf8_to_ucs2(S,
[C1 band 15 bsl 12 bor (C2 band 63 bsl 6) bor C3 band 63
| R]).
-spec domain_ucs2_to_ascii(list()) -> false | binary().
domain_ucs2_to_ascii(Domain) ->
case catch domain_ucs2_to_ascii1(Domain) of
{'EXIT', _Reason} -> false;
Res -> iolist_to_binary(Res)
end.
domain_ucs2_to_ascii1(Domain) ->
Parts = string:tokens(Domain,
[46, 12290, 65294, 65377]),
ASCIIParts = lists:map(fun (P) -> to_ascii(P) end,
Parts),
string:strip(lists:flatmap(fun (P) -> [$. | P] end,
ASCIIParts),
left, $.).
%% Domain names are already nameprep'ed in ejabberd, so we skiping this step
to_ascii(Name) ->
false = lists:any(fun (C)
when (0 =< C) and (C =< 44) or
(46 =< C) and (C =< 47)
or (58 =< C) and (C =< 64)
or (91 =< C) and (C =< 96)
or (123 =< C) and (C =< 127) ->
true;
(_) -> false
end,
Name),
case Name of
[H | _] when H /= $- -> true = lists:last(Name) /= $-
end,
ASCIIName = case lists:any(fun (C) -> C > 127 end, Name)
of
true ->
true = case Name of
"xn--" ++ _ -> false;
_ -> true
end,
"xn--" ++ punycode_encode(Name);
false -> Name
end,
L = length(ASCIIName),
true = (1 =< L) and (L =< 63),
ASCIIName.
%%% PUNYCODE (RFC3492)
-define(BASE, 36).
-define(TMIN, 1).
-define(TMAX, 26).
-define(SKEW, 38).
-define(DAMP, 700).
-define(INITIAL_BIAS, 72).
-define(INITIAL_N, 128).
punycode_encode(Input) ->
N = (?INITIAL_N),
Delta = 0,
Bias = (?INITIAL_BIAS),
Basic = lists:filter(fun (C) -> C =< 127 end, Input),
NonBasic = lists:filter(fun (C) -> C > 127 end, Input),
L = length(Input),
B = length(Basic),
SNonBasic = lists:usort(NonBasic),
Output1 = if B > 0 -> Basic ++ "-";
true -> ""
end,
Output2 = punycode_encode1(Input, SNonBasic, B, B, L, N,
Delta, Bias, ""),
Output1 ++ Output2.
punycode_encode1(Input, [M | SNonBasic], B, H, L, N,
Delta, Bias, Out)
when H < L ->
Delta1 = Delta + (M - N) * (H + 1),
% let n = m
{NewDelta, NewBias, NewH, NewOut} = lists:foldl(fun (C,
{ADelta, ABias, AH,
AOut}) ->
if C < M ->
{ADelta + 1,
ABias, AH,
AOut};
C == M ->
NewOut =
punycode_encode_delta(ADelta,
ABias,
AOut),
NewBias =
adapt(ADelta,
H +
1,
H
==
B),
{0, NewBias,
AH + 1,
NewOut};
true ->
{ADelta,
ABias, AH,
AOut}
end
end,
{Delta1, Bias, H, Out},
Input),
punycode_encode1(Input, SNonBasic, B, NewH, L, M + 1,
NewDelta + 1, NewBias, NewOut);
punycode_encode1(_Input, _SNonBasic, _B, _H, _L, _N,
_Delta, _Bias, Out) ->
lists:reverse(Out).
punycode_encode_delta(Delta, Bias, Out) ->
punycode_encode_delta(Delta, Bias, Out, ?BASE).
punycode_encode_delta(Delta, Bias, Out, K) ->
T = if K =< Bias -> ?TMIN;
K >= Bias + (?TMAX) -> ?TMAX;
true -> K - Bias
end,
if Delta < T -> [codepoint(Delta) | Out];
true ->
C = T + (Delta - T) rem ((?BASE) - T),
punycode_encode_delta((Delta - T) div ((?BASE) - T),
Bias, [codepoint(C) | Out], K + (?BASE))
end.
adapt(Delta, NumPoints, FirstTime) ->
Delta1 = if FirstTime -> Delta div (?DAMP);
true -> Delta div 2
end,
Delta2 = Delta1 + Delta1 div NumPoints,
adapt1(Delta2, 0).
adapt1(Delta, K) ->
if Delta > ((?BASE) - (?TMIN)) * (?TMAX) div 2 ->
adapt1(Delta div ((?BASE) - (?TMIN)), K + (?BASE));
true ->
K +
((?BASE) - (?TMIN) + 1) * Delta div (Delta + (?SKEW))
end.
codepoint(C) ->
if (0 =< C) and (C =< 25) -> C + 97;
(26 =< C) and (C =< 35) -> C + 22
end.
%%%===================================================================
%%% Unit tests
%%%===================================================================
-ifdef(TEST).
acsii_test() ->
?assertEqual(<<"test.org">>, domain_utf8_to_ascii(<<"test.org">>)).
utf8_test() ->
?assertEqual(
<<"xn--d1acufc.xn--p1ai">>,
domain_utf8_to_ascii(
<<208,180,208,190,208,188,208,181,208,189,46,209,128,209,132>>)).
-endif.
+1 -1
View File
@@ -49,7 +49,7 @@ start_link() ->
-spec route(iq(), atom() | pid(), term(), non_neg_integer()) -> ok.
route(#iq{type = T} = IQ, Proc, Ctx, Timeout) when T == set; T == get ->
Expire = current_time() + Timeout,
Rnd = randoms:get_string(),
Rnd = p1_rand:get_string(),
ID = encode_id(Expire, Rnd),
ets:insert(?MODULE, {{Expire, Rnd}, Proc, Ctx}),
gen_server:cast(?MODULE, {restart_timer, Expire}),
+627 -554
View File
File diff suppressed because it is too large Load Diff
+8 -60
View File
@@ -32,10 +32,8 @@
%% API
-export([start/0, start_link/0]).
-export([route/1, process_iq/1,
-export([route/1,
get_features/1,
register_iq_handler/4,
unregister_iq_handler/2,
bounce_resource_packet/1,
host_up/1, host_down/1]).
@@ -47,15 +45,12 @@
-export([route_iq/2, route_iq/3]).
-deprecated([{route_iq, 2}, {route_iq, 3}]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-include("xmpp.hrl").
-record(state, {}).
-define(IQTABLE, local_iqtable).
%%====================================================================
%% API
%%====================================================================
@@ -72,36 +67,13 @@ start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [],
[]).
-spec process_iq(iq()) -> any().
process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
when T == get; T == set ->
XMLNS = xmpp:get_ns(El),
Host = To#jid.lserver,
case ets:lookup(?IQTABLE, {Host, XMLNS}) of
[{_, Module, Function}] ->
gen_iq_handler:handle(Host, Module, Function, Packet);
[] ->
Txt = <<"No module is handling this query">>,
Err = xmpp:err_service_unavailable(Txt, Lang),
ejabberd_router:route_error(Packet, Err)
end;
process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
when T == get; T == set ->
Txt = case SubEls of
[] -> <<"No child elements found">>;
_ -> <<"Too many child elements">>
end,
Err = xmpp:err_bad_request(Txt, Lang),
ejabberd_router:route_error(Packet, Err);
process_iq(#iq{type = T}) when T == result; T == error ->
ok.
-spec route(stanza()) -> any().
route(Packet) ->
try do_route(Packet)
catch E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet), {E, {R, erlang:get_stacktrace()}}])
[xmpp:pp(Packet), {E, {R, St}}])
end.
-spec route_iq(iq(), function()) -> ok.
@@ -112,15 +84,6 @@ route_iq(IQ, Fun) ->
route_iq(IQ, Fun, Timeout) ->
ejabberd_router:route_iq(IQ, Fun, undefined, Timeout).
-spec register_iq_handler(binary(), binary(), module(), function()) -> ok.
register_iq_handler(Host, XMLNS, Module, Fun) ->
gen_server:cast(?MODULE,
{register_iq_handler, Host, XMLNS, Module, Fun}).
-spec unregister_iq_handler(binary(), binary()) -> ok.
unregister_iq_handler(Host, XMLNS) ->
gen_server:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}).
-spec bounce_resource_packet(stanza()) -> ok | stop.
bounce_resource_packet(#presence{to = #jid{lresource = <<"">>}}) ->
ok;
@@ -135,12 +98,7 @@ bounce_resource_packet(Packet) ->
-spec get_features(binary()) -> [binary()].
get_features(Host) ->
get_features(ets:next(?IQTABLE, {Host, <<"">>}), Host, []).
get_features({Host, XMLNS}, Host, XMLNSs) ->
get_features(ets:next(?IQTABLE, {Host, XMLNS}), Host, [XMLNS|XMLNSs]);
get_features(_, _, XMLNSs) ->
XMLNSs.
gen_iq_handler:get_features(?MODULE, Host).
%%====================================================================
%% gen_server callbacks
@@ -148,26 +106,16 @@ get_features(_, _, XMLNSs) ->
init([]) ->
process_flag(trap_exit, true),
lists:foreach(fun host_up/1, ?MYHOSTS),
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
ejabberd_hooks:add(host_up, ?MODULE, host_up, 10),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 100),
catch ets:new(?IQTABLE, [named_table, public, ordered_set,
{read_concurrency, true}]),
gen_iq_handler:start(?MODULE),
update_table(),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
Reply = ok, {reply, Reply, State}.
handle_cast({register_iq_handler, Host, XMLNS, Module, Function},
State) ->
ets:insert(?IQTABLE,
{{Host, XMLNS}, Module, Function}),
{noreply, State};
handle_cast({unregister_iq_handler, Host, XMLNS},
State) ->
ets:delete(?IQTABLE, {Host, XMLNS}),
{noreply, State};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info({route, Packet}, State) ->
@@ -178,7 +126,7 @@ handle_info(Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
lists:foreach(fun host_down/1, ?MYHOSTS),
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()),
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 10),
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 100),
ok.
@@ -197,7 +145,7 @@ do_route(Packet) ->
if To#jid.luser /= <<"">> ->
ejabberd_sm:route(Packet);
is_record(Packet, iq), To#jid.lresource == <<"">> ->
process_iq(Packet);
gen_iq_handler:handle(?MODULE, Packet);
Type == result; Type == error ->
ok;
true ->
+17 -3
View File
@@ -30,7 +30,6 @@
-export([start/0, restart/0, reopen_log/0, rotate_log/0, get/0, set/1,
get_log_path/0, opt_type/1]).
-include("ejabberd.hrl").
-type loglevel() :: 0 | 1 | 2 | 3 | 4 | 5.
@@ -59,7 +58,7 @@ get_log_path() ->
undefined ->
case os:getenv("EJABBERD_LOG_PATH") of
false ->
?LOG_PATH;
"ejabberd.log";
Path ->
Path
end
@@ -144,10 +143,14 @@ do_start(Level) ->
LogRotateSize = get_integer_env(log_rotate_size, 10*1024*1024),
LogRotateCount = get_integer_env(log_rotate_count, 1),
LogRateLimit = get_integer_env(log_rate_limit, 100),
ConsoleLevel = case get_lager_version() >= "3.6.0" of
true -> [{level, Level}];
false -> Level
end,
application:set_env(lager, error_logger_hwm, LogRateLimit),
application:set_env(
lager, handlers,
[{lager_console_backend, Level},
[{lager_console_backend, ConsoleLevel},
{lager_file_backend, [{file, ConsoleLog}, {level, Level}, {date, LogRotateDate},
{count, LogRotateCount}, {size, LogRotateSize}]},
{lager_file_backend, [{file, ErrorLog}, {level, error}, {date, LogRotateDate},
@@ -215,6 +218,10 @@ set(LogLevel) when is_integer(LogLevel) ->
ok
end, gen_event:which_handlers(lager_event))
end,
case LogLevel of
5 -> xmpp:set_config([{debug, true}]);
_ -> ok
end,
{module, lager};
set({_LogLevel, _}) ->
error_logger:error_msg("custom loglevels are not supported for 'lager'"),
@@ -249,3 +256,10 @@ get_lager_handlers() ->
Result ->
Result
end.
get_lager_version() ->
Apps = application:loaded_applications(),
case lists:keyfind(lager, 1, Apps) of
{_, _, Vsn} -> Vsn;
false -> "0.0.0"
end.
+3 -10
View File
@@ -50,11 +50,11 @@
config_reloaded/0,
opt_type/1]).
-export([oauth_issue_token/3, oauth_list_tokens/0, oauth_revoke_token/1]).
-export([get_commands_spec/0,
oauth_issue_token/3, oauth_list_tokens/0, oauth_revoke_token/1]).
-include("xmpp.hrl").
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_http.hrl").
@@ -646,14 +646,7 @@ logo() ->
<<>>
end.
-spec opt_type(oauth_expire) -> fun((non_neg_integer()) -> non_neg_integer());
(oauth_access) -> fun((any()) -> any());
(oauth_db_type) -> fun((atom()) -> atom());
(oauth_cache_life_time) -> fun((timeout()) -> timeout());
(oauth_cache_size) -> fun((timeout()) -> timeout());
(oauth_use_cache) -> fun((boolean()) -> boolean());
(oauth_cache_misse) -> fun((boolean()) -> boolean());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(oauth_expire) ->
fun(I) when is_integer(I), I >= 0 -> I end;
opt_type(oauth_access) ->
+4 -6
View File
@@ -34,13 +34,12 @@
clean/1,
opt_type/1]).
-include("ejabberd.hrl").
-include("ejabberd_oauth.hrl").
-include("logger.hrl").
-include("jid.hrl").
init() ->
rest:start(?MYNAME),
rest:start(ejabberd_config:get_myname()),
ok.
store(R) ->
@@ -50,7 +49,7 @@ store(R) ->
SJID = jid:encode({User, Server, <<"">>}),
case rest:with_retry(
post,
[?MYNAME, Path, [],
[ejabberd_config:get_myname(), Path, [],
{[{<<"token">>, R#oauth_token.token},
{<<"user">>, SJID},
{<<"scope">>, R#oauth_token.scope},
@@ -65,7 +64,7 @@ store(R) ->
lookup(Token) ->
Path = path(<<"lookup">>),
case rest:with_retry(post, [?MYNAME, Path, [],
case rest:with_retry(post, [ejabberd_config:get_myname(), Path, [],
{[{<<"token">>, Token}]}],
2, 500) of
{ok, 200, {Data}} ->
@@ -93,8 +92,7 @@ path(Path) ->
<<Base/binary, "/", Path/binary>>.
-spec opt_type(ext_api_path_oauth) -> fun((binary()) -> binary());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(ext_api_path_oauth) ->
fun (X) -> iolist_to_binary(X) end;
opt_type(_) -> [ext_api_path_oauth].
+3 -4
View File
@@ -34,7 +34,6 @@
clean/1]).
-include("ejabberd_oauth.hrl").
-include("ejabberd.hrl").
-include("ejabberd_sql_pt.hrl").
-include("jid.hrl").
-include("logger.hrl").
@@ -49,7 +48,7 @@ store(R) ->
Scope = str:join(R#oauth_token.scope, <<" ">>),
Expire = R#oauth_token.expire,
case ?SQL_UPSERT(
?MYNAME,
ejabberd_config:get_myname(),
"oauth_token",
["!token=%(Token)s",
"jid=%(SJID)s",
@@ -63,7 +62,7 @@ store(R) ->
lookup(Token) ->
case ejabberd_sql:sql_query(
?MYNAME,
ejabberd_config:get_myname(),
?SQL("select @(jid)s, @(scope)s, @(expire)d"
" from oauth_token where token=%(Token)s")) of
{selected, [{SJID, Scope, Expire}]} ->
@@ -79,6 +78,6 @@ lookup(Token) ->
clean(TS) ->
ejabberd_sql:sql_query(
?MYNAME,
ejabberd_config:get_myname(),
?SQL("delete from oauth_token where expire < %(TS)d")).
+39 -20
View File
@@ -40,7 +40,7 @@
-define(CHUNK_SIZE, 1024*20). %20k
-include("ejabberd.hrl").
-include("scram.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-include("mod_privacy.hrl").
@@ -92,7 +92,7 @@ import_file(FileName, State) ->
-spec export_server(binary()) -> any().
export_server(Dir) ->
export_hosts(?MYHOSTS, Dir).
export_hosts(ejabberd_config:get_myhosts(), Dir).
-spec export_host(binary(), binary()) -> any().
export_host(Dir, Host) ->
@@ -404,6 +404,8 @@ process_user(#xmlel{name = <<"user">>, attrs = Attrs, children = Els},
case ejabberd_auth:try_register(LUser, LServer, Pass) of
ok ->
process_user_els(Els, State#state{user = LUser});
{error, invalid_password} when (Password == <<>>) ->
process_user_els(Els, State#state{user = LUser});
{error, Err} ->
stop("Failed to create user '~s': ~p", [Name, Err])
end
@@ -433,7 +435,7 @@ process_user_el(#xmlel{name = Name, attrs = Attrs, children = Els} = El,
{<<"query">>, ?NS_PRIVATE} ->
process_private(xmpp:decode(El), State);
{<<"vCard">>, ?NS_VCARD} ->
process_vcard(El, State);
process_vcard(xmpp:decode(El), State);
{<<"offline-messages">>, NS} ->
Msgs = [xmpp:decode(E, NS, [ignore_els]) || E <- Els],
process_offline_msgs(Msgs, State);
@@ -473,30 +475,47 @@ process_roster(RosterQuery, State = #state{user = U, server = S}) ->
-spec process_privacy(privacy_query(), state()) -> {ok, state()} | {error, _}.
process_privacy(#privacy_query{lists = Lists,
default = Default,
active = Active} = PrivacyQuery,
active = Active},
State = #state{user = U, server = S}) ->
JID = jid:make(U, S),
IQ = #iq{type = set, id = randoms:get_string(),
from = JID, to = JID, sub_els = [PrivacyQuery]},
case mod_privacy:process_iq(IQ) of
#iq{type = error} = ResIQ ->
#stanza_error{reason = Reason} = xmpp:get_error(ResIQ),
if Reason == 'item-not-found', Lists == [],
Active == undefined, Default /= undefined ->
if Lists /= undefined ->
process_privacy2(JID, #privacy_query{lists = Lists});
true ->
ok
end,
if Active /= undefined ->
process_privacy2(JID, #privacy_query{active = Active});
true ->
ok
end,
if Default /= undefined ->
process_privacy2(JID, #privacy_query{default = Default});
true ->
ok
end,
{ok, State}.
process_privacy2(JID, PQ) ->
case mod_privacy:process_iq(#iq{type = set, id = p1_rand:get_string(),
from = JID, to = JID,
sub_els = [PQ]}) of
#iq{type = error} = ResIQ ->
#stanza_error{reason = Reason} = xmpp:get_error(ResIQ),
if Reason /= 'item-not-found' ->
%% Failed to set default list because there is no
%% list with such name. We shouldn't stop here.
{ok, State};
true ->
stop("Failed to write privacy: ~p", [Reason])
end;
_ ->
{ok, State}
end.
stop("Failed to write default privacy: ~p", [Reason]);
true ->
ok
end;
_ ->
ok
end.
-spec process_private(private(), state()) -> {ok, state()} | {error, _}.
process_private(Private, State = #state{user = U, server = S}) ->
JID = jid:make(U, S),
IQ = #iq{type = set, id = randoms:get_string(),
IQ = #iq{type = set, id = p1_rand:get_string(),
from = JID, to = JID, sub_els = [Private]},
case mod_private:process_sm_iq(IQ) of
#iq{type = result} ->
@@ -508,7 +527,7 @@ process_private(Private, State = #state{user = U, server = S}) ->
-spec process_vcard(xmlel(), state()) -> {ok, state()} | {error, _}.
process_vcard(El, State = #state{user = U, server = S}) ->
JID = jid:make(U, S),
IQ = #iq{type = set, id = randoms:get_string(),
IQ = #iq{type = set, id = p1_rand:get_string(),
from = JID, to = JID, sub_els = [El]},
case mod_vcard:process_sm_iq(IQ) of
#iq{type = result} ->
+170 -91
View File
@@ -49,9 +49,10 @@
-type bad_cert_reason() :: cert_expired | invalid_issuer | invalid_signature |
name_not_permitted | missing_basic_constraint |
invalid_key_usage | selfsigned_peer | unknown_sig_algo |
unknown_ca | missing_priv_key.
-type bad_cert() :: {bad_cert, bad_cert_reason()}.
-type cert_error() :: not_cert | not_der | not_pem | encrypted.
unknown_ca | missing_priv_key | unknown_key_algo |
unknown_key_type | encrypted | not_der | not_cert |
not_pem.
-type cert_error() :: {bad_cert, bad_cert_reason()}.
-export_type([cert_error/0]).
-define(CA_CACHE, ca_cache).
@@ -59,12 +60,17 @@
%%%===================================================================
%%% API
%%%===================================================================
-spec add_certfile(filename:filename())
-spec add_certfile(file:filename())
-> ok | {error, cert_error() | file:posix()}.
add_certfile(Path) ->
gen_server:call(?MODULE, {add_certfile, prep_path(Path)}).
try gen_server:call(?MODULE, {add_certfile, prep_path(Path)})
catch exit:{noproc, {gen_server, call, _}} ->
%% This hack will be removed after moving
%% the code into a separate repo
ok
end.
-spec try_certfile(filename:filename()) -> binary().
-spec try_certfile(file:filename()) -> binary().
try_certfile(Path0) ->
Path = prep_path(Path0),
case load_certfile(Path) of
@@ -76,13 +82,13 @@ route_registered(Route) ->
gen_server:call(?MODULE, {route_registered, Route}).
-spec format_error(cert_error() | file:posix()) -> string().
format_error(not_cert) ->
format_error({bad_cert, not_cert}) ->
"no PEM encoded certificates found";
format_error(not_pem) ->
format_error({bad_cert, not_pem}) ->
"failed to decode from PEM format";
format_error(not_der) ->
format_error({bad_cert, not_der}) ->
"failed to decode from DER format";
format_error(encrypted) ->
format_error({bad_cert, encrypted}) ->
"encrypted certificate";
format_error({bad_cert, cert_expired}) ->
"certificate is no longer valid as its expiration date has passed";
@@ -103,6 +109,10 @@ format_error({bad_cert, selfsigned_peer}) ->
"self-signed certificate";
format_error({bad_cert, unknown_sig_algo}) ->
"certificate is signed using unknown algorithm";
format_error({bad_cert, unknown_key_algo}) ->
"unknown private key algorithm";
format_error({bad_cert, unknown_key_type}) ->
"private key is of unknown type";
format_error({bad_cert, unknown_ca}) ->
"certificate is signed by unknown CA";
format_error({bad_cert, missing_priv_key}) ->
@@ -128,7 +138,7 @@ get_certfile(Domain) ->
-spec get_certfile_no_default(binary()) -> {ok, binary()} | error.
get_certfile_no_default(Domain) ->
case ejabberd_idna:domain_utf8_to_ascii(Domain) of
case xmpp_idna:domain_utf8_to_ascii(Domain) of
false ->
error;
ASCIIDomain ->
@@ -329,7 +339,8 @@ get_certfiles_from_config_options(_State) ->
Host <- ejabberd_config:get_myhosts()]),
[iolist_to_binary(P) || P <- lists:usort(Local ++ Global)].
-spec add_certfiles(state()) -> {ok, state()} | {error, bad_cert()}.
-spec add_certfiles(state()) -> {ok, state()} |
{error, cert_error() | file:posix()}.
add_certfiles(State) ->
?DEBUG("Reading certificates", []),
Paths = get_certfiles_from_config_options(State),
@@ -343,7 +354,8 @@ add_certfiles(State) ->
{error, _} = Err -> Err
end.
-spec add_certfiles(binary(), state()) -> {ok, state()} | {error, bad_cert()}.
-spec add_certfiles(binary(), state()) -> {ok, state()} |
{error, cert_error() | file:posix()}.
add_certfiles(Host, State) ->
State1 = lists:foldl(
fun(Opt, AccState) ->
@@ -363,8 +375,8 @@ add_certfiles(Host, State) ->
{ok, State}
end.
-spec add_certfile(file:filename_all(), state()) -> {ok, state()} |
{{error, cert_error()}, state()}.
-spec add_certfile(file:filename_all(), state()) ->
{ok, state()} | {{error, cert_error() | file:posix()}, state()}.
add_certfile(Path, State) ->
case lists:member(Path, State#state.paths) of
true ->
@@ -386,30 +398,14 @@ add_certfile(Path, State) ->
end
end.
-spec build_chain_and_check(state()) -> ok | {error, bad_cert()}.
-spec build_chain_and_check(state()) -> ok | {error, cert_error() | file:posix()}.
build_chain_and_check(State) ->
?DEBUG("Building certificates graph", []),
CertPaths = get_cert_paths(maps:keys(State#state.certs), State#state.graph),
?DEBUG("Finding matched certificate keys", []),
case match_cert_keys(CertPaths, State#state.keys) of
{ok, Chains} ->
?DEBUG("Storing certificate chains", []),
CertFilesWithDomains = store_certs(Chains, []),
ets:delete_all_objects(?MODULE),
lists:foreach(
fun({Path, Domain}) ->
fast_tls:add_certfile(Domain, Path),
ets:insert(?MODULE, {Domain, Path})
end, CertFilesWithDomains),
?DEBUG("Validating certificates", []),
Errors = validate(CertPaths, State#state.validate),
?DEBUG("Subscribing to file events", []),
lists:foreach(
fun({Cert, Why}) ->
Path = maps:get(Cert, State#state.certs),
?WARNING_MSG("Failed to validate certificate from ~s: ~s",
[Path, format_error(Why)])
end, Errors);
InvalidCerts = validate(CertPaths, State),
SortedChains = sort_chains(Chains, InvalidCerts),
store_certs(SortedChains, State);
{error, Cert, Why} ->
Path = maps:get(Cert, State#state.certs),
?ERROR_MSG("Failed to build certificate chain for ~s: ~s",
@@ -417,9 +413,35 @@ build_chain_and_check(State) ->
{error, Why}
end.
-spec store_certs([{[cert()], priv_key()}],
[{binary(), binary()}]) -> [{binary(), binary()}].
store_certs([{Certs, Key}|Chains], Acc) ->
-spec store_certs([{[cert()], priv_key()}], state()) -> ok | {error, file:posix()}.
store_certs(Chains, State) ->
?DEBUG("Storing certificate chains", []),
Res = lists:foldl(
fun(_, {error, _} = Err) ->
Err;
({Certs, Key}, Acc) ->
case store_cert(Certs, Key, State) of
{ok, FileDoms} ->
Acc ++ FileDoms;
{error, _} = Err ->
Err
end
end, [], Chains),
case Res of
{error, Why} ->
{error, Why};
FileDomains ->
ets:delete_all_objects(?MODULE),
lists:foreach(
fun({Path, Domain}) ->
fast_tls:add_certfile(Domain, Path),
ets:insert(?MODULE, {Domain, Path})
end, FileDomains)
end.
-spec store_cert([cert()], priv_key(), state()) -> {ok, [{binary(), binary()}]} |
{error, file:posix()}.
store_cert(Certs, Key, State) ->
CertPEMs = public_key:pem_encode(
lists:map(
fun(Cert) ->
@@ -433,20 +455,51 @@ store_certs([{Certs, Key}|Chains], Acc) ->
not_encrypted}]),
PEMs = <<CertPEMs/binary, KeyPEM/binary>>,
Cert = hd(Certs),
Domains = xmpp_stream_pkix:get_cert_domains(Cert),
FileName = filename:join(certs_dir(), str:sha(PEMs)),
case file:write_file(FileName, PEMs) of
ok ->
file:change_mode(FileName, 8#600),
NewAcc = [{FileName, Domain} || Domain <- Domains] ++ Acc,
store_certs(Chains, NewAcc);
{error, Why} ->
case xmpp_stream_pkix:get_cert_domains(Cert) of
[] ->
Path = maps:get(Cert, State#state.certs),
?WARNING_MSG("Certificate from ~s doesn't define "
"any domain names", [Path]),
{ok, [{FileName, <<"">>}]};
Domains ->
{ok, [{FileName, Domain} || Domain <- Domains]}
end;
{error, Why} = Err ->
?ERROR_MSG("Failed to write to ~s: ~s",
[FileName, file:format_error(Why)]),
store_certs(Chains, [])
end;
store_certs([], Acc) ->
Acc.
Err
end.
-spec sort_chains([{[cert()], priv_key()}], [cert()]) -> [{[cert()], priv_key()}].
sort_chains(Chains, InvalidCerts) ->
lists:sort(
fun({[Cert1|_], _}, {[Cert2|_], _}) ->
IsValid1 = not lists:member(Cert1, InvalidCerts),
IsValid2 = not lists:member(Cert2, InvalidCerts),
if IsValid1 and not IsValid2 ->
false;
IsValid2 and not IsValid1 ->
true;
true ->
compare_expiration_date(Cert1, Cert2)
end
end, Chains).
%% Returns true if the first certificate has sooner expiration date
-spec compare_expiration_date(cert(), cert()) -> boolean().
compare_expiration_date(#'OTPCertificate'{
tbsCertificate =
#'OTPTBSCertificate'{
validity = #'Validity'{notAfter = After1}}},
#'OTPCertificate'{
tbsCertificate =
#'OTPTBSCertificate'{
validity = #'Validity'{notAfter = After2}}}) ->
get_timestamp(After1) =< get_timestamp(After2).
-spec load_certfile(file:filename_all()) -> {ok, [cert()], [priv_key()]} |
{error, cert_error() | file:posix()}.
@@ -472,57 +525,69 @@ pem_decode(Data) ->
(_) -> false
end, Objects) of
{[], []} ->
{error, not_cert};
{error, {bad_cert, not_cert}};
{Certs, PrivKeys} ->
{ok, Certs, PrivKeys}
end
end
catch _:_ ->
{error, not_pem}
catch E:R ->
St = erlang:get_stacktrace(),
?DEBUG("PEM decoding stacktrace: ~p", [{E, {R, St}}]),
{error, {bad_cert, not_pem}}
end.
-spec decode_certs([public_key:pem_entry()]) -> {[cert()], [priv_key()]} |
{error, not_der | encrypted}.
-spec decode_certs([public_key:pem_entry()]) -> [cert() | priv_key()] |
{error, cert_error()}.
decode_certs(PemEntries) ->
try lists:foldr(
fun(_, {error, _} = Err) ->
Err;
({_, _, Flag}, _) when Flag /= not_encrypted ->
{error, encrypted};
({'Certificate', Der, _}, Acc) ->
[public_key:pkix_decode_cert(Der, otp)|Acc];
({'PrivateKeyInfo', Der, not_encrypted}, Acc) ->
#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{
algorithm = Algo},
privateKey = Key} =
public_key:der_decode('PrivateKeyInfo', Der),
case Algo of
?'rsaEncryption' ->
[public_key:der_decode(
'RSAPrivateKey', iolist_to_binary(Key))|Acc];
?'id-dsa' ->
[public_key:der_decode(
'DSAPrivateKey', iolist_to_binary(Key))|Acc];
?'id-ecPublicKey' ->
[public_key:der_decode(
'ECPrivateKey', iolist_to_binary(Key))|Acc];
_ ->
Acc
end;
({Tag, Der, _}, Acc) when Tag == 'RSAPrivateKey';
Tag == 'DSAPrivateKey';
Tag == 'ECPrivateKey' ->
[public_key:der_decode(Tag, Der)|Acc];
(_, Acc) ->
Acc
end, [], PemEntries)
catch _:_ ->
{error, not_der}
try lists:flatmap(
fun({Tag, Der, Flag}) ->
decode_cert(Tag, Der, Flag)
end, PemEntries)
catch _:{bad_cert, _} = Err ->
{error, Err};
E:R ->
St = erlang:get_stacktrace(),
?DEBUG("DER decoding stacktrace: ~p", [{E, {R, St}}]),
{error, {bad_cert, not_der}}
end.
-spec validate([{path, [cert()]}], boolean()) -> [{cert(), bad_cert()}].
validate(Paths, true) ->
-spec decode_cert(atom(), binary(), atom()) -> [cert() | priv_key()].
decode_cert(_, _, Flag) when Flag /= not_encrypted ->
erlang:error({bad_cert, encrypted});
decode_cert('Certificate', Der, _) ->
[public_key:pkix_decode_cert(Der, otp)];
decode_cert('PrivateKeyInfo', Der, not_encrypted) ->
case public_key:der_decode('PrivateKeyInfo', Der) of
#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{
algorithm = Algo},
privateKey = Key} ->
KeyBin = iolist_to_binary(Key),
case Algo of
?'rsaEncryption' ->
[public_key:der_decode('RSAPrivateKey', KeyBin)];
?'id-dsa' ->
[public_key:der_decode('DSAPrivateKey', KeyBin)];
?'id-ecPublicKey' ->
[public_key:der_decode('ECPrivateKey', KeyBin)];
_ ->
erlang:error({bad_cert, unknown_key_algo})
end;
#'RSAPrivateKey'{} = Key -> [Key];
#'DSAPrivateKey'{} = Key -> [Key];
#'ECPrivateKey'{} = Key -> [Key];
_ -> erlang:error({bad_cert, unknown_key_type})
end;
decode_cert(Tag, Der, _) when Tag == 'RSAPrivateKey';
Tag == 'DSAPrivateKey';
Tag == 'ECPrivateKey' ->
[public_key:der_decode(Tag, Der)];
decode_cert(_, _, _) ->
[].
-spec validate([{path, [cert()]}], state()) -> [cert()].
validate(Paths, #state{validate = true} = State) ->
?DEBUG("Validating certificates", []),
{ok, Re} = re:compile("^[a-f0-9]+\\.[0-9]+$", [unicode]),
Hashes = case file:list_dir(ca_dir()) of
{ok, Files} ->
@@ -551,13 +616,16 @@ validate(Paths, true) ->
ok ->
false;
{error, Cert, Reason} ->
{true, {Cert, Reason}}
File = maps:get(Cert, State#state.certs),
?WARNING_MSG("Failed to validate certificate from ~s: ~s",
[File, format_error(Reason)]),
{true, Cert}
end
end, Paths);
validate(_, _) ->
[].
-spec validate_path([cert()], dict:dict()) -> ok | {error, cert(), bad_cert()}.
-spec validate_path([cert()], dict:dict()) -> ok | {error, cert(), cert_error()}.
validate_path([Cert|_] = Certs, Cache) ->
case find_local_issuer(Cert, Cache) of
{ok, IssuerCert} ->
@@ -715,6 +783,7 @@ do_read_ca_file(Path) ->
-spec match_cert_keys([{path, [cert()]}], [priv_key()])
-> {ok, [{cert(), priv_key()}]} | {error, {bad_cert, missing_priv_key}}.
match_cert_keys(CertPaths, PrivKeys) ->
?DEBUG("Finding matched certificate keys", []),
KeyPairs = [{pubkey_from_privkey(PrivKey), PrivKey} || PrivKey <- PrivKeys],
match_cert_keys(CertPaths, KeyPairs, []).
@@ -763,6 +832,7 @@ pubkey_from_privkey(#'ECPrivateKey'{publicKey = Key}) ->
-spec get_cert_paths([cert()], digraph:graph()) -> [{path, [cert()]}].
get_cert_paths(Certs, G) ->
?DEBUG("Building certificates graph", []),
{NewCerts, OldCerts} =
lists:partition(
fun(Cert) ->
@@ -820,7 +890,7 @@ get_cert_path(G, [Root|_] = Acc) ->
end, Es)
end.
-spec prep_path(filename:filename()) -> binary().
-spec prep_path(file:filename()) -> binary().
prep_path(Path0) ->
case filename:pathtype(Path0) of
relative ->
@@ -838,6 +908,15 @@ short_name_hash(_) ->
"".
-endif.
-spec get_timestamp({utcTime | generalTime, string()}) -> string().
get_timestamp({utcTime, [Y1,Y2|T]}) ->
case list_to_integer([Y1,Y2]) of
N when N >= 50 -> [$1,$9,Y1,Y2|T];
_ -> [$2,$0,Y1,Y2|T]
end;
get_timestamp({generalTime, TS}) ->
TS.
wildcard(Path) when is_binary(Path) ->
wildcard(binary_to_list(Path));
wildcard(Path) ->
+7 -6
View File
@@ -33,7 +33,6 @@
-export([start_link/0, init/1, opt_type/1,
config_reloaded/0, start_host/1, stop_host/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
start_link() ->
@@ -56,7 +55,7 @@ get_specs() ->
{ok, Spec} -> [Spec];
undefined -> []
end
end, ?MYHOSTS).
end, ejabberd_config:get_myhosts()).
-spec get_spec(binary()) -> {ok, supervisor:child_spec()} | undefined.
get_spec(Host) ->
@@ -72,7 +71,7 @@ get_spec(Host) ->
-spec config_reloaded() -> ok.
config_reloaded() ->
lists:foreach(fun start_host/1, ?MYHOSTS).
lists:foreach(fun reload_host/1, ejabberd_config:get_myhosts()).
-spec start_host(binary()) -> ok.
start_host(Host) ->
@@ -97,6 +96,10 @@ stop_host(Host) ->
supervisor:delete_child(?MODULE, SupName),
ok.
-spec reload_host(binary()) -> ok.
reload_host(Host) ->
ejabberd_sql_sup:reload(Host).
%% Returns {true, App} if we have configured sql for the given host
needs_sql(Host) ->
LHost = jid:nameprep(Host),
@@ -109,9 +112,7 @@ needs_sql(Host) ->
undefined -> false
end.
-type sql_type() :: mysql | pgsql | sqlite | mssql | odbc.
-spec opt_type(sql_type) -> fun((sql_type()) -> sql_type());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(sql_type) ->
fun (mysql) -> mysql;
(pgsql) -> pgsql;
+41 -5
View File
@@ -33,10 +33,10 @@
%% API
-export([start_link/1, get_proc/1, get_connection/1, q/1, qp/1, format_error/1]).
%% Commands
-export([multi/1, get/1, set/2, del/1,
-export([multi/1, get/1, set/2, del/1, info/1,
sadd/2, srem/2, smembers/1, sismember/2, scard/1,
hget/2, hset/3, hdel/2, hlen/1, hgetall/1, hkeys/1,
subscribe/1, publish/2]).
subscribe/1, publish/2, script_load/1, evalsha/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -50,7 +50,6 @@
-define(CALL_TIMEOUT, 60*1000). %% 60 seconds
-include("logger.hrl").
-include("ejabberd.hrl").
-record(state, {connection :: pid() | undefined,
num :: pos_integer(),
@@ -62,6 +61,9 @@
-type redis_reply() :: binary() | [binary()].
-type redis_command() :: [binary()].
-type redis_pipeline() :: [redis_command()].
-type redis_info() :: server | clients | memory | persistence |
stats | replication | cpu | commandstats |
cluster | keyspace | default | all.
-type state() :: #state{}.
-export_type([error_reason/0]).
@@ -317,6 +319,40 @@ publish(Channel, Data) ->
tr_enq(Cmd, Stack)
end.
-spec script_load(iodata()) -> {ok, binary()} | redis_error().
script_load(Data) ->
case erlang:get(?TR_STACK) of
undefined ->
q([<<"SCRIPT">>, <<"LOAD">>, Data]);
_ ->
erlang:error(transaction_unsupported)
end.
-spec evalsha(binary(), [iodata()], [iodata()]) -> {ok, binary()} | redis_error().
evalsha(SHA, Keys, Args) ->
case erlang:get(?TR_STACK) of
undefined ->
q([<<"EVALSHA">>, SHA, length(Keys)|Keys ++ Args]);
_ ->
erlang:error(transaction_unsupported)
end.
-spec info(redis_info()) -> {ok, [{atom(), binary()}]} | redis_error().
info(Type) ->
case erlang:get(?TR_STACK) of
undefined ->
case q([<<"INFO">>, misc:atom_to_binary(Type)]) of
{ok, Info} ->
Lines = binary:split(Info, <<"\r\n">>, [global]),
KVs = [binary:split(Line, <<":">>) || Line <- Lines],
{ok, [{misc:binary_to_atom(K), V} || [K, V] <- KVs]};
{error, _} = Err ->
Err
end;
_ ->
erlang:error(transaction_unsupported)
end.
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
@@ -438,7 +474,7 @@ connect(#state{num = Num}) ->
erlang:error(Why)
end
catch _:Reason ->
Timeout = randoms:uniform(
Timeout = p1_rand:uniform(
min(10, ejabberd_redis_sup:get_pool_size())),
?ERROR_MSG("Redis connection #~p at ~s:~p has failed: ~p; "
"reconnecting in ~p seconds",
@@ -503,7 +539,7 @@ log_error(Cmd, Reason) ->
-spec get_rnd_id() -> pos_integer().
get_rnd_id() ->
randoms:round_robin(ejabberd_redis_sup:get_pool_size() - 1) + 2.
p1_rand:round_robin(ejabberd_redis_sup:get_pool_size() - 1) + 2.
-spec get_result([{error, atom() | binary()} | {ok, iodata()}]) ->
{ok, [redis_reply()]} | {error, binary()}.
+2 -10
View File
@@ -32,7 +32,6 @@
%% Supervisor callbacks
-export([init/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-define(DEFAULT_POOL_SIZE, 10).
@@ -98,7 +97,7 @@ init([]) ->
%%% Internal functions
%%%===================================================================
is_redis_configured() ->
lists:any(fun is_redis_configured/1, ?MYHOSTS).
lists:any(fun is_redis_configured/1, ejabberd_config:get_myhosts()).
is_redis_configured(Host) ->
ServerConfigured = ejabberd_config:has_option({redis_server, Host}),
@@ -127,14 +126,7 @@ get_pool_size() ->
iolist_to_list(IOList) ->
binary_to_list(iolist_to_binary(IOList)).
-spec opt_type(redis_connect_timeout) -> fun((pos_integer()) -> pos_integer());
(redis_db) -> fun((non_neg_integer()) -> non_neg_integer());
(redis_password) -> fun((binary()) -> binary());
(redis_port) -> fun((0..65535) -> 0..65535);
(redis_server) -> fun((binary()) -> binary());
(redis_pool_size) -> fun((pos_integer()) -> pos_integer());
(redis_queue_type) -> fun((ram | file) -> ram | file);
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(redis_connect_timeout) ->
fun (I) when is_integer(I), I > 0 -> I end;
opt_type(redis_db) ->
-1
View File
@@ -41,7 +41,6 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
-record(state, {pid = self() :: pid()}).
+3 -11
View File
@@ -33,7 +33,6 @@
transform_options/1, get_random_pid/0,
host_up/1, config_reloaded/0, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-define(DEFAULT_POOL_SIZE, 10).
@@ -74,7 +73,7 @@ config_reloaded() ->
end.
is_riak_configured() ->
lists:any(fun is_riak_configured/1, ?MYHOSTS).
lists:any(fun is_riak_configured/1, ejabberd_config:get_myhosts()).
is_riak_configured(Host) ->
ServerConfigured = ejabberd_config:has_option({riak_server, Host}),
@@ -163,7 +162,7 @@ get_pids() ->
[ejabberd_riak:get_proc(I) || I <- lists:seq(1, get_pool_size())].
get_random_pid() ->
I = randoms:round_robin(get_pool_size()) + 1,
I = p1_rand:round_robin(get_pool_size()) + 1,
ejabberd_riak:get_proc(I).
transform_options(Opts) ->
@@ -174,14 +173,7 @@ transform_options({riak_server, {S, P}}, Opts) ->
transform_options(Opt, Opts) ->
[Opt|Opts].
-spec opt_type(riak_pool_size) -> fun((pos_integer()) -> pos_integer());
(riak_port) -> fun((0..65535) -> 0..65535);
(riak_server) -> fun((binary()) -> binary());
(riak_start_interval) -> fun((pos_integer()) -> pos_integer());
(riak_cacertfile) -> fun((binary()) -> binary());
(riak_username) -> fun((binary()) -> binary());
(riak_password) -> fun((binary()) -> binary());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(riak_pool_size) ->
fun (N) when is_integer(N), N >= 1 -> N end;
opt_type(riak_port) ->
+6 -19
View File
@@ -68,7 +68,6 @@
%% This value is used in SIP and Megaco for a transaction lifetime.
-define(IQ_TIMEOUT, 32000).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_router.hrl").
-include("xmpp.hrl").
@@ -92,8 +91,9 @@ start_link() ->
route(Packet) ->
try do_route(Packet)
catch E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet), {E, {R, erlang:get_stacktrace()}}])
[xmpp:pp(Packet), {E, {R, St}}])
end.
-spec route(jid(), jid(), xmlel() | stanza()) -> ok.
@@ -306,12 +306,8 @@ is_my_host(Domain) ->
end.
-spec process_iq(iq()) -> any().
process_iq(#iq{to = To} = IQ) ->
if To#jid.luser == <<"">> ->
ejabberd_local:process_iq(IQ);
true ->
ejabberd_sm:process_iq(IQ)
end.
process_iq(IQ) ->
gen_iq_handler:handle(IQ).
-spec config_reloaded() -> ok.
config_reloaded() ->
@@ -484,7 +480,7 @@ cache_opts() ->
end,
[{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
-spec clean_cache(node()) -> ok.
-spec clean_cache(node()) -> non_neg_integer().
clean_cache(Node) ->
ets_cache:filter(
?ROUTES_CACHE,
@@ -503,16 +499,7 @@ clean_cache(Node) ->
clean_cache() ->
ejabberd_cluster:eval_everywhere(?MODULE, clean_cache, [node()]).
-type domain_balancing() :: random | source | destination |
bare_source | bare_destination.
-spec opt_type(domain_balancing) -> fun((domain_balancing()) -> domain_balancing());
(domain_balancing_component_number) -> fun((pos_integer()) -> pos_integer());
(router_db_type) -> fun((atom()) -> atom());
(router_use_cache) -> fun((boolean()) -> boolean());
(router_cache_missed) -> fun((boolean()) -> boolean());
(router_cache_size) -> fun((timeout()) -> timeout());
(router_cache_life_time) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(domain_balancing) ->
fun (random) -> random;
(source) -> source;
-1
View File
@@ -30,7 +30,6 @@
-export([init/1, handle_cast/2, handle_call/3, handle_info/2,
terminate/2, code_change/3, start_link/0]).
-include("ejabberd.hrl").
-include("ejabberd_router.hrl").
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-1
View File
@@ -41,7 +41,6 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
-1
View File
@@ -31,7 +31,6 @@
-export([init/1, handle_cast/2, handle_call/3, handle_info/2,
terminate/2, code_change/3, start_link/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_router.hrl").
+7 -7
View File
@@ -29,7 +29,6 @@
-export([init/0, register_route/5, unregister_route/3, find_routes/1,
get_all_routes/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
-include("ejabberd_router.hrl").
@@ -41,7 +40,7 @@ init() ->
Node = erlang:atom_to_binary(node(), latin1),
?DEBUG("Cleaning SQL 'route' table...", []),
case ejabberd_sql:sql_query(
?MYNAME, ?SQL("delete from route where node=%(Node)s")) of
ejabberd_config:get_myname(), ?SQL("delete from route where node=%(Node)s")) of
{updated, _} ->
ok;
Err ->
@@ -53,7 +52,7 @@ register_route(Domain, ServerHost, LocalHint, _, Pid) ->
PidS = misc:encode_pid(Pid),
LocalHintS = enc_local_hint(LocalHint),
Node = erlang:atom_to_binary(node(Pid), latin1),
case ?SQL_UPSERT(?MYNAME, "route",
case ?SQL_UPSERT(ejabberd_config:get_myname(), "route",
["!domain=%(Domain)s",
"!server_host=%(ServerHost)s",
"!node=%(Node)s",
@@ -69,7 +68,7 @@ unregister_route(Domain, _, Pid) ->
PidS = misc:encode_pid(Pid),
Node = erlang:atom_to_binary(node(Pid), latin1),
case ejabberd_sql:sql_query(
?MYNAME,
ejabberd_config:get_myname(),
?SQL("delete from route where domain=%(Domain)s "
"and pid=%(PidS)s and node=%(Node)s")) of
{updated, _} ->
@@ -80,7 +79,7 @@ unregister_route(Domain, _, Pid) ->
find_routes(Domain) ->
case ejabberd_sql:sql_query(
?MYNAME,
ejabberd_config:get_myname(),
?SQL("select @(server_host)s, @(node)s, @(pid)s, @(local_hint)s "
"from route where domain=%(Domain)s")) of
{selected, Rows} ->
@@ -94,7 +93,7 @@ find_routes(Domain) ->
get_all_routes() ->
case ejabberd_sql:sql_query(
?MYNAME,
ejabberd_config:get_myname(),
?SQL("select @(domain)s from route where domain <> server_host")) of
{selected, Domains} ->
{ok, [Domain || {Domain} <- Domains]};
@@ -123,10 +122,11 @@ row_to_route(Domain, {ServerHost, NodeS, PidS, LocalHintS} = Row) ->
catch _:{bad_node, _} ->
[];
E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("failed to decode row from 'route' table:~n"
"Row = ~p~n"
"Domain = ~s~n"
"Reason = ~p",
[Row, Domain, {E, {R, erlang:get_stacktrace()}}]),
[Row, Domain, {E, {R, St}}]),
[]
end.
+12 -19
View File
@@ -54,7 +54,6 @@
-export([get_info_s2s_connections/1,
transform_options/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
@@ -96,8 +95,9 @@ start_link() ->
route(Packet) ->
try do_route(Packet)
catch E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet), {E, {R, erlang:get_stacktrace()}}])
[xmpp:pp(Packet), {E, {R, St}}])
end.
clean_temporarily_blocked_table() ->
@@ -303,7 +303,7 @@ init([]) ->
{attributes, record_info(fields, temporarily_blocked)}]),
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
lists:foreach(fun host_up/1, ?MYHOSTS),
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
@@ -322,7 +322,7 @@ handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) ->
ejabberd_commands:unregister_commands(get_commands_spec()),
lists:foreach(fun host_down/1, ?MYHOSTS),
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()),
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60),
ok.
@@ -544,7 +544,7 @@ is_service(From, To) ->
s2s -> % bypass RFC 3920 10.3
false;
local ->
Hosts = (?MYHOSTS),
Hosts = ejabberd_config:get_myhosts(),
P = fun (ParentDomain) ->
lists:member(ParentDomain, Hosts)
end,
@@ -708,19 +708,7 @@ get_s2s_state(S2sPid) ->
end,
[{s2s_pid, S2sPid} | Infos].
-type use_starttls() :: boolean() | optional | required | required_trusted.
-spec opt_type(route_subdomains) -> fun((s2s | local) -> s2s | local);
(s2s_access) -> fun((any()) -> any());
(s2s_ciphers) -> fun((binary()) -> binary());
(s2s_dhfile) -> fun((binary()) -> binary());
(s2s_cafile) -> fun((binary()) -> binary());
(s2s_protocol_options) -> fun(([binary()]) -> binary());
(s2s_tls_compression) -> fun((boolean()) -> boolean());
(s2s_use_starttls) -> fun((use_starttls()) -> use_starttls());
(s2s_zlib) -> fun((boolean()) -> boolean());
(s2s_timeout) -> fun((timeout()) -> timeout());
(s2s_queue_type) -> fun((ram | file) -> ram | file);
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(route_subdomains) ->
fun (s2s) -> s2s;
(local) -> local
@@ -750,7 +738,12 @@ opt_type(s2s_use_starttls) ->
required_trusted
end;
opt_type(s2s_zlib) ->
fun(B) when is_boolean(B) -> B end;
fun(true) ->
ejabberd:start_app(ezlib),
true;
(false) ->
false
end;
opt_type(s2s_timeout) ->
fun(I) when is_integer(I), I >= 0 -> timer:seconds(I);
(infinity) -> infinity;
+38 -70
View File
@@ -21,17 +21,14 @@
%%%-------------------------------------------------------------------
-module(ejabberd_s2s_in).
-behaviour(xmpp_stream_in).
-behaviour(xmpp_socket).
-behaviour(ejabberd_listener).
%% xmpp_socket callbacks
-export([start/2, start_link/2, socket_type/0]).
%% ejabberd_listener callbacks
-export([listen_opt_type/1]).
-export([start/2, start_link/2, accept/1, listen_opt_type/1, listen_options/0]).
%% xmpp_stream_in callbacks
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3]).
-export([tls_options/1, tls_required/1, tls_verify/1, tls_enabled/1,
compress_methods/1,
-export([tls_options/1, tls_required/1, tls_enabled/1, compress_methods/1,
unauthenticated_stream_features/1, authenticated_stream_features/1,
handle_stream_start/2, handle_stream_end/2,
handle_stream_established/1, handle_auth_success/4,
@@ -44,7 +41,6 @@
-export([stop/1, close/1, close/2, send/2, update_state/2, establish/1,
host_up/1, host_down/1]).
-include("ejabberd.hrl").
-include("xmpp.hrl").
-include("logger.hrl").
@@ -55,16 +51,8 @@
%%% API
%%%===================================================================
start(SockData, Opts) ->
case proplists:get_value(supervisor, Opts, true) of
true ->
case supervisor:start_child(ejabberd_s2s_in_sup, [SockData, Opts]) of
{ok, undefined} -> ignore;
Res -> Res
end;
_ ->
xmpp_stream_in:start(?MODULE, [SockData, Opts],
ejabberd_config:fsm_limit_opts(Opts))
end.
xmpp_stream_in:start(?MODULE, [SockData, Opts],
ejabberd_config:fsm_limit_opts(Opts)).
start_link(SockData, Opts) ->
xmpp_stream_in:start_link(?MODULE, [SockData, Opts],
@@ -79,8 +67,8 @@ close(Ref, Reason) ->
stop(Ref) ->
xmpp_stream_in:stop(Ref).
socket_type() ->
xml_stream.
accept(Ref) ->
xmpp_stream_in:accept(Ref).
-spec send(pid(), xmpp_element()) -> ok;
(state(), xmpp_element()) -> state().
@@ -133,7 +121,15 @@ reject_unauthenticated_packet(State, _Pkt) ->
Err = xmpp:serr_not_authorized(),
send(State, Err).
process_closed(State, _Reason) ->
process_closed(#{server := LServer} = State, Reason) ->
RServer = case State of
#{remote_server := Name} ->
Name;
#{ip := IP} ->
ejabberd_config:may_hide_data(misc:ip_to_list(IP))
end,
?INFO_MSG("Closing inbound s2s connection ~s -> ~s: ~s",
[RServer, LServer, xmpp_stream_out:format_error(Reason)]),
stop(State).
%%%===================================================================
@@ -145,9 +141,6 @@ tls_options(#{tls_options := TLSOpts, server_host := LServer}) ->
tls_required(#{server_host := LServer}) ->
ejabberd_s2s:tls_required(LServer).
tls_verify(#{server_host := LServer}) ->
ejabberd_s2s:tls_verify(LServer).
tls_enabled(#{server_host := LServer}) ->
ejabberd_s2s:tls_enabled(LServer).
@@ -202,9 +195,9 @@ handle_auth_failure(RServer, Mech, Reason,
#{socket := Socket, ip := IP,
server_host := ServerHost,
lserver := LServer} = State) ->
?INFO_MSG("(~s) Failed inbound s2s ~s authentication ~s -> ~s (~s): ~s",
[xmpp_socket:pp(Socket), Mech, RServer, LServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)), Reason]),
?WARNING_MSG("(~s) Failed inbound s2s ~s authentication ~s -> ~s (~s): ~s",
[xmpp_socket:pp(Socket), Mech, RServer, LServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)), Reason]),
ejabberd_hooks:run_fold(s2s_in_auth_result,
ServerHost, State, [false, RServer]).
@@ -263,10 +256,10 @@ init([State, Opts]) ->
State1 = State#{tls_options => TLSOpts2,
auth_domains => sets:new(),
xmlns => ?NS_SERVER,
lang => ?MYLANG,
server => ?MYNAME,
lserver => ?MYNAME,
server_host => ?MYNAME,
lang => ejabberd_config:get_mylang(),
server => ejabberd_config:get_myname(),
lserver => ejabberd_config:get_myname(),
server_host => ejabberd_config:get_myname(),
established => false,
shaper => Shaper},
State2 = xmpp_stream_in:set_timeout(State1, Timeout),
@@ -345,49 +338,24 @@ set_idle_timeout(State) ->
change_shaper(#{shaper := ShaperName, server_host := ServerHost} = State,
RServer) ->
Shaper = acl:match_rule(ServerHost, ShaperName, jid:make(RServer)),
xmpp_stream_in:change_shaper(State, Shaper).
xmpp_stream_in:change_shaper(State, ejabberd_shaper:new(Shaper)).
-spec listen_opt_type(shaper) -> fun((any()) -> any());
(certfile) -> fun((binary()) -> binary());
(ciphers) -> fun((binary()) -> binary());
(dhfile) -> fun((binary()) -> binary());
(cafile) -> fun((binary()) -> binary());
(protocol_options) -> fun(([binary()]) -> binary());
(tls_compression) -> fun((boolean()) -> boolean());
(tls) -> fun((boolean()) -> boolean());
(supervisor) -> fun((boolean()) -> boolean());
(max_stanza_type) -> fun((timeout()) -> timeout());
(max_fsm_queue) -> fun((pos_integer()) -> pos_integer());
(inet) -> fun((boolean()) -> boolean());
(inet6) -> fun((boolean()) -> boolean());
(backlog) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
listen_opt_type(shaper) -> fun acl:shaper_rules_validator/1;
listen_opt_type(certfile = Opt) ->
fun(S) ->
?WARNING_MSG("Listening option '~s' for ~s is deprecated, use "
"'certfiles' global option instead", [Opt, ?MODULE]),
ejabberd_pkix:add_certfile(S),
ok = ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(ciphers) -> ejabberd_s2s:opt_type(s2s_ciphers);
listen_opt_type(dhfile) -> ejabberd_s2s:opt_type(s2s_dhfile);
listen_opt_type(cafile) -> ejabberd_s2s:opt_type(s2s_cafile);
listen_opt_type(protocol_options) -> ejabberd_s2s:opt_type(s2s_protocol_options);
listen_opt_type(tls_compression) -> ejabberd_s2s:opt_type(s2s_tls_compression);
listen_opt_type(tls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(supervisor) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(max_stanza_size) ->
fun(I) when is_integer(I), I>0 -> I;
(unlimited) -> infinity;
(infinity) -> infinity
end;
listen_opt_type(max_fsm_queue) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(_) ->
[shaper, certfile, ciphers, dhfile, cafile, protocol_options,
tls_compression, tls, max_fsm_queue, backlog, inet, inet6].
end.
listen_options() ->
[{shaper, none},
{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000}].
+15 -22
View File
@@ -42,7 +42,6 @@
-export([start/3, start_link/3, connect/1, close/1, close/2, stop/1, send/2,
route/2, establish/1, update_state/2, host_up/1, host_down/1]).
-include("ejabberd.hrl").
-include("xmpp.hrl").
-include("logger.hrl").
@@ -61,12 +60,12 @@ start(From, To, Opts) ->
Res -> Res
end;
_ ->
xmpp_stream_out:start(?MODULE, [xmpp_socket, From, To, Opts],
xmpp_stream_out:start(?MODULE, [From, To, Opts],
ejabberd_config:fsm_limit_opts([]))
end.
start_link(From, To, Opts) ->
xmpp_stream_out:start_link(?MODULE, [xmpp_socket, From, To, Opts],
xmpp_stream_out:start_link(?MODULE, [From, To, Opts],
ejabberd_config:fsm_limit_opts([])).
-spec connect(pid()) -> ok.
@@ -139,9 +138,9 @@ host_down(Host) ->
process_auth_result(#{server := LServer, remote_server := RServer} = State,
{false, Reason}) ->
Delay = get_delay(),
?INFO_MSG("Failed to establish outbound s2s connection ~s -> ~s: "
"authentication failed; bouncing for ~p seconds",
[LServer, RServer, Delay]),
?WARNING_MSG("Failed to establish outbound s2s connection ~s -> ~s: "
"authentication failed; bouncing for ~p seconds",
[LServer, RServer, Delay]),
State1 = State#{on_route => bounce, stop_reason => Reason},
State2 = close(State1),
State3 = bounce_queue(State2),
@@ -158,9 +157,9 @@ process_closed(#{server := LServer, remote_server := RServer,
process_closed(#{server := LServer, remote_server := RServer} = State,
Reason) ->
Delay = get_delay(),
?INFO_MSG("Failed to establish outbound s2s connection ~s -> ~s: ~s; "
"bouncing for ~p seconds",
[LServer, RServer, format_error(Reason), Delay]),
?WARNING_MSG("Failed to establish outbound s2s connection ~s -> ~s: ~s; "
"bouncing for ~p seconds",
[LServer, RServer, format_error(Reason), Delay]),
State1 = State#{on_route => bounce},
State2 = bounce_queue(State1),
xmpp_stream_out:set_timeout(State2, timer:seconds(Delay)).
@@ -224,10 +223,10 @@ handle_auth_failure(Mech, Reason,
remote_server := RServer,
server_host := ServerHost,
server := LServer} = State) ->
?INFO_MSG("(~s) Failed outbound s2s ~s authentication ~s -> ~s (~s): ~s",
[xmpp_socket:pp(Socket), Mech, LServer, RServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)),
xmpp_stream_out:format_error(Reason)]),
?WARNING_MSG("(~s) Failed outbound s2s ~s authentication ~s -> ~s (~s): ~s",
[xmpp_socket:pp(Socket), Mech, LServer, RServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)),
xmpp_stream_out:format_error(Reason)]),
ejabberd_hooks:run_fold(s2s_out_auth_result, ServerHost, State, [{false, Reason}]).
handle_packet(Pkt, #{server_host := ServerHost} = State) ->
@@ -274,7 +273,7 @@ init([#{server := LServer, remote_server := RServer} = State, Opts]) ->
State1 = State#{on_route => queue,
queue => p1_queue:new(QueueType, QueueLimit),
xmlns => ?NS_SERVER,
lang => ?MYLANG,
lang => ejabberd_config:get_mylang(),
server_host => ServerHost,
shaper => none},
State2 = xmpp_stream_out:set_timeout(State1, Timeout),
@@ -376,7 +375,7 @@ mk_bounce_error(_Lang, _State) ->
-spec get_delay() -> non_neg_integer().
get_delay() ->
MaxDelay = ejabberd_config:get_option(s2s_max_retry_delay, 300),
randoms:uniform(MaxDelay).
p1_rand:uniform(MaxDelay).
-spec set_idle_timeout(state()) -> state().
set_idle_timeout(#{on_route := send, server := LServer} = State) ->
@@ -444,13 +443,7 @@ maybe_report_huge_timeout(Opt, T) when is_integer(T), T >= 1000 ->
maybe_report_huge_timeout(_, _) ->
ok.
-spec opt_type(outgoing_s2s_families) -> fun(([ipv4|ipv6]) -> [inet|inet6]);
(outgoing_s2s_port) -> fun((0..65535) -> 0..65535);
(outgoing_s2s_timeout) -> fun((timeout()) -> timeout());
(s2s_dns_retries) -> fun((non_neg_integer()) -> non_neg_integer());
(s2s_dns_timeout) -> fun((timeout()) -> timeout());
(s2s_max_retry_delay) -> fun((pos_integer()) -> pos_integer());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(outgoing_s2s_families) ->
fun(Families) ->
lists:map(
+46 -71
View File
@@ -21,22 +21,20 @@
%%%-------------------------------------------------------------------
-module(ejabberd_service).
-behaviour(xmpp_stream_in).
-behaviour(xmpp_socket).
-behaviour(ejabberd_listener).
-protocol({xep, 114, '1.6'}).
%% xmpp_socket callbacks
-export([start/2, start_link/2, socket_type/0, close/1, close/2]).
%% ejabberd_listener callbacks
-export([listen_opt_type/1, transform_listen_option/2]).
-export([start/2, start_link/2, accept/1]).
-export([listen_opt_type/1, listen_options/0, transform_listen_option/2]).
%% xmpp_stream_in callbacks
-export([init/1, handle_info/2, terminate/2, code_change/3]).
-export([handle_stream_start/2, handle_auth_success/4, handle_auth_failure/4,
handle_authenticated_packet/2, get_password_fun/1, tls_options/1]).
%% API
-export([send/2]).
-export([send/2, close/1, close/2]).
-include("ejabberd.hrl").
-include("xmpp.hrl").
-include("logger.hrl").
@@ -54,8 +52,8 @@ start_link(SockData, Opts) ->
xmpp_stream_in:start_link(?MODULE, [SockData, Opts],
ejabberd_config:fsm_limit_opts(Opts)).
socket_type() ->
xml_stream.
accept(Ref) ->
xmpp_stream_in:accept(Ref).
-spec send(pid(), xmpp_element()) -> ok;
(state(), xmpp_element()) -> state().
@@ -80,7 +78,8 @@ tls_options(#{tls_options := TLSOptions}) ->
init([State, Opts]) ->
Access = proplists:get_value(access, Opts, all),
Shaper = proplists:get_value(shaper_rule, Opts, none),
Shaper = proplists:get_value(shaper, Opts,
proplists:get_value(shaper_rule, Opts, none)),
GlobalPassword = proplists:get_value(password, Opts, random_password()),
HostOpts = proplists:get_value(hosts, Opts, [{global, GlobalPassword}]),
HostOpts1 = lists:map(
@@ -102,12 +101,12 @@ init([State, Opts]) ->
end,
GlobalRoutes = proplists:get_value(global_routes, Opts, true),
Timeout = ejabberd_config:negotiation_timeout(),
State1 = xmpp_stream_in:change_shaper(State, Shaper),
State1 = xmpp_stream_in:change_shaper(State, ejabberd_shaper:new(Shaper)),
State2 = xmpp_stream_in:set_timeout(State1, Timeout),
State3 = State2#{access => Access,
xmlns => ?NS_COMPONENT,
lang => ?MYLANG,
server => ?MYNAME,
lang => ejabberd_config:get_mylang(),
server => ejabberd_config:get_myname(),
host_opts => dict:from_list(HostOpts1),
stream_version => undefined,
tls_options => TLSOpts,
@@ -147,10 +146,10 @@ get_password_fun(#{remote_server := RemoteServer,
{ok, Password} ->
{Password, undefined};
error ->
?INFO_MSG("(~s) Domain ~s is unconfigured for "
"external component from ~s",
[xmpp_socket:pp(Socket), RemoteServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP))]),
?WARNING_MSG("(~s) Domain ~s is unconfigured for "
"external component from ~s",
[xmpp_socket:pp(Socket), RemoteServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP))]),
{false, undefined}
end
end.
@@ -170,7 +169,7 @@ handle_auth_success(_, Mech, _,
end,
lists:foreach(
fun(H) ->
ejabberd_router:register_route(H, ?MYNAME),
ejabberd_router:register_route(H, ejabberd_config:get_myname()),
ejabberd_hooks:run(component_connected, [H])
end, Routes),
State.
@@ -178,11 +177,11 @@ handle_auth_success(_, Mech, _,
handle_auth_failure(_, Mech, Reason,
#{remote_server := RemoteServer,
socket := Socket, ip := IP} = State) ->
?INFO_MSG("(~s) Failed external component ~s authentication "
"for ~s from ~s: ~s",
[xmpp_socket:pp(Socket), Mech, RemoteServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)),
Reason]),
?WARNING_MSG("(~s) Failed external component ~s authentication "
"for ~s from ~s: ~s",
[xmpp_socket:pp(Socket), Mech, RemoteServer,
ejabberd_config:may_hide_data(misc:ip_to_list(IP)),
Reason]),
State.
handle_authenticated_packet(Pkt0, #{ip := {IP, _}, lang := Lang} = State)
@@ -262,7 +261,7 @@ check_from(From, #{host_opts := HostOpts}) ->
dict:is_key(Server, HostOpts).
random_password() ->
str:sha(randoms:bytes(20)).
str:sha(p1_rand:bytes(20)).
transform_listen_option({hosts, Hosts, O}, Opts) ->
case lists:keyfind(hosts, 1, Opts) of
@@ -282,39 +281,12 @@ transform_listen_option({host, Host, Os}, Opts) ->
transform_listen_option(Opt, Opts) ->
[Opt|Opts].
-spec listen_opt_type(access) -> fun((any()) -> any());
(shaper_rule) -> fun((any()) -> any());
(certfile) -> fun((binary()) -> binary());
(ciphers) -> fun((binary()) -> binary());
(dhfile) -> fun((binary()) -> binary());
(cafile) -> fun((binary()) -> binary());
(protocol_options) -> fun(([binary()]) -> binary());
(tls_compression) -> fun((boolean()) -> boolean());
(tls) -> fun((boolean()) -> boolean());
(check_from) -> fun((boolean()) -> boolean());
(password) -> fun((boolean()) -> boolean());
(hosts) -> fun(([{binary(), [{password, binary()}]}]) ->
[{binary(), binary() | undefined}]);
(max_stanza_type) -> fun((timeout()) -> timeout());
(max_fsm_queue) -> fun((pos_integer()) -> pos_integer());
(inet) -> fun((boolean()) -> boolean());
(inet6) -> fun((boolean()) -> boolean());
(backlog) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
listen_opt_type(access) -> fun acl:access_rules_validator/1;
listen_opt_type(shaper_rule) -> fun acl:shaper_rules_validator/1;
listen_opt_type(certfile) ->
fun(S) ->
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
listen_opt_type(shaper_rule) ->
fun(V) ->
?WARNING_MSG("Listening option 'shaper_rule' of module ~s "
"is renamed to 'shaper'", [?MODULE]),
acl:shaper_rules_validator(V)
end;
listen_opt_type(ciphers) -> fun iolist_to_binary/1;
listen_opt_type(dhfile) -> fun misc:try_read_file/1;
listen_opt_type(cafile) -> fun misc:try_read_file/1;
listen_opt_type(protocol_options) ->
fun(Options) -> str:join(Options, <<"|">>) end;
listen_opt_type(tls_compression) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(tls) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(check_from) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(password) -> fun iolist_to_binary/1;
listen_opt_type(hosts) ->
@@ -329,19 +301,22 @@ listen_opt_type(hosts) ->
end, HostOpts)
end;
listen_opt_type(global_routes) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(max_stanza_size) ->
fun(I) when is_integer(I) -> I;
(unlimited) -> infinity;
(infinity) -> infinity
end;
listen_opt_type(max_fsm_queue) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(inet) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(inet6) -> fun(B) when is_boolean(B) -> B end;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(_) ->
[access, shaper_rule, certfile, ciphers, dhfile, cafile, tls,
protocol_options, tls_compression, password, hosts, check_from,
max_fsm_queue, global_routes, backlog, inet, inet6].
fun(B) when is_boolean(B) -> B end.
listen_options() ->
[{access, all},
{shaper, none},
{shaper_rule, none},
{certfile, undefined},
{ciphers, undefined},
{dhfile, undefined},
{cafile, undefined},
{protocol_options, undefined},
{tls, false},
{tls_compression, false},
{max_stanza_size, infinity},
{max_fsm_queue, 5000},
{password, undefined},
{hosts, []},
{check_from, true},
{global_routes, true}].
+52 -74
View File
@@ -1,5 +1,5 @@
%%%----------------------------------------------------------------------
%%% File : shaper.erl
%%% File : ejabberd_shaper.erl
%%% Author : Alexey Shchepin <alexey@process-one.net>
%%% Purpose : Functions to control connections traffic
%%% Created : 9 Feb 2003 by Alexey Shchepin <alexey@process-one.net>
@@ -23,34 +23,29 @@
%%%
%%%----------------------------------------------------------------------
-module(shaper).
-module(ejabberd_shaper).
-behaviour(gen_server).
-behaviour(ejabberd_config).
-author('alexey@process-one.net').
-export([start_link/0, new/1, new1/1, update/2,
-export([start_link/0, new/1, update/2,
get_max_rate/1, transform_options/1, load_from_config/0,
opt_type/1]).
%% 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").
-record(maxrate, {maxrate = 0 :: integer(),
lastrate = 0.0 :: float(),
lasttime = 0 :: integer()}).
-record(shaper, {name :: {atom(), global},
maxrate :: integer()}).
-record(shaper, {name :: {atom(), global},
maxrate :: integer(),
burst_size :: integer()}).
-record(state, {}).
-type shaper() :: none | #maxrate{}.
-type shaper() :: none | p1_shaper:state().
-export_type([shaper/0]).
-spec start_link() -> {ok, pid()} | {error, any()}.
@@ -59,9 +54,9 @@ start_link() ->
init([]) ->
ejabberd_mnesia:create(?MODULE, shaper,
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, shaper)}]),
[{ram_copies, [node()]},
{local_content, true},
{attributes, record_info(fields, shaper)}]),
ejabberd_hooks:add(config_reloaded, ?MODULE, load_from_config, 20),
load_from_config(),
{ok, #state{}}.
@@ -83,25 +78,26 @@ code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-spec load_from_config() -> ok | {error, any()}.
load_from_config() ->
Shapers = ejabberd_config:get_option(shaper, []),
case mnesia:transaction(
fun() ->
lists:foreach(
fun({Name, MaxRate}) ->
mnesia:write(#shaper{name = {Name, global},
maxrate = MaxRate})
end, Shapers)
end) of
{atomic, ok} ->
ok;
Err ->
{error, Err}
fun() ->
lists:foreach(
fun({Name, MaxRate, BurstSize}) ->
mnesia:write(
#shaper{name = {Name, global},
maxrate = MaxRate,
burst_size = BurstSize})
end,
Shapers)
end) of
{atomic, ok} ->
ok;
Err ->
{error, Err}
end.
-spec get_max_rate(atom()) -> none | non_neg_integer().
get_max_rate(none) ->
none;
get_max_rate(Name) ->
@@ -113,62 +109,44 @@ get_max_rate(Name) ->
end.
-spec new(atom()) -> shaper().
new(none) ->
none;
new(Name) ->
MaxRate = case ets:lookup(shaper, {Name, global}) of
[#shaper{maxrate = R}] ->
R;
[] ->
none
end,
new1(MaxRate).
-spec new1(none | integer()) -> shaper().
new1(none) -> none;
new1(MaxRate) ->
#maxrate{maxrate = MaxRate, lastrate = 0.0,
lasttime = p1_time_compat:system_time(micro_seconds)}.
case ets:lookup(shaper, {Name, global}) of
[#shaper{maxrate = R, burst_size = B}] ->
p1_shaper:new(R, B);
[] ->
none
end.
-spec update(shaper(), integer()) -> {shaper(), integer()}.
update(none, _Size) -> {none, 0};
update(#maxrate{} = State, Size) ->
MinInterv = 1000 * Size /
(2 * State#maxrate.maxrate - State#maxrate.lastrate),
Interv = (p1_time_compat:system_time(micro_seconds) - State#maxrate.lasttime) /
1000,
?DEBUG("State: ~p, Size=~p~nM=~p, I=~p~n",
[State, Size, MinInterv, Interv]),
Pause = if MinInterv > Interv ->
1 + trunc(MinInterv - Interv);
true -> 0
end,
NextNow = p1_time_compat:system_time(micro_seconds) + Pause * 1000,
Div = case NextNow - State#maxrate.lasttime of
0 -> 1;
V -> V
end,
{State#maxrate{lastrate =
(State#maxrate.lastrate +
1000000 * Size / Div)
/ 2,
lasttime = NextNow},
Pause}.
update(Shaper, Size) ->
Result = p1_shaper:update(Shaper, Size),
?DEBUG("Shaper update:~n~s =>~n~s",
[p1_shaper:pp(Shaper), p1_shaper:pp(Result)]),
Result.
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
transform_options({OptName, Name, {maxrate, N}}, Opts) when OptName == shaper ->
[{shaper, [{Name, N}]}|Opts];
transform_options({OptName, Name, none}, Opts) when OptName == shaper ->
[{shaper, [{Name, none}]}|Opts];
transform_options({shaper, Name, {maxrate, N}}, Opts) ->
[{shaper, [{Name, N}]} | Opts];
transform_options({shaper, Name, none}, Opts) ->
[{shaper, [{Name, none}]} | Opts];
transform_options({shaper, List}, Opts) when is_list(List) ->
R = lists:map(
fun({Name, Args}) when is_list(Args) ->
MaxRate = proplists:get_value(rate, Args, 1000),
BurstSize = proplists:get_value(burst_size, Args, MaxRate),
{Name, MaxRate, BurstSize};
({Name, Val}) ->
{Name, Val, Val}
end, List),
[{shaper, R} | Opts];
transform_options(Opt, Opts) ->
[Opt|Opts].
[Opt | Opts].
-spec opt_type(shaper) -> fun((any()) -> any());
(atom()) -> [atom()].
opt_type(shaper) -> fun (V) -> V end;
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(shaper) -> fun(V) -> V end;
opt_type(_) -> [shaper].
+25 -28
View File
@@ -24,27 +24,29 @@
%%%-------------------------------------------------------------------
-module(ejabberd_sip).
-behaviour(ejabberd_listener).
-ifndef(SIP).
-include("logger.hrl").
-export([socket_type/0, start/2, listen_opt_type/1]).
log_error() ->
?CRITICAL_MSG("ejabberd is not compiled with SIP support", []).
socket_type() ->
log_error(),
raw.
listen_opt_type(_) ->
log_error(),
[].
-export([accept/1, start/2, start_link/2, listen_options/0]).
fail() ->
?CRITICAL_MSG("Listening module ~s is not available: "
"ejabberd is not compiled with SIP support",
[?MODULE]),
erlang:error(sip_not_compiled).
accept(_) ->
fail().
listen_options() ->
fail().
start(_, _) ->
log_error(),
{error, sip_not_compiled}.
fail().
start_link(_, _) ->
fail().
-else.
%% API
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2,
socket_type/0, listen_opt_type/1]).
start_link/2, accept/1, listen_options/0]).
-include("ejabberd.hrl").
%%%===================================================================
%%% API
@@ -63,19 +65,22 @@ udp_recv(Sock, Addr, Port, Data, Opts) ->
start(Opaque, Opts) ->
esip_socket:start(Opaque, Opts).
socket_type() ->
raw.
start_link({gen_tcp, Sock}, Opts) ->
esip_socket:start_link(Sock, Opts).
accept(_) ->
ok.
set_certfile(Opts) ->
case lists:keymember(certfile, 1, Opts) of
true ->
Opts;
false ->
case ejabberd_pkix:get_certfile(?MYNAME) of
case ejabberd_pkix:get_certfile(ejabberd_config:get_myname()) of
{ok, CertFile} ->
[{certfile, CertFile}|Opts];
error ->
case ejabberd_config:get_option({domain_certfile, ?MYNAME}) of
case ejabberd_config:get_option({domain_certfile, ejabberd_config:get_myname()}) of
undefined ->
Opts;
CertFile ->
@@ -84,17 +89,9 @@ set_certfile(Opts) ->
end
end.
listen_opt_type(certfile) ->
fun(S) ->
%% We cannot deprecate the option for now:
%% I think SIP clients are too stupid to set SNI
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(tls) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(_) ->
[tls, certfile].
listen_options() ->
[{tls, false},
{certfile, undefined}].
%%%===================================================================
%%% Internal functions
+50 -81
View File
@@ -39,7 +39,6 @@
stop/0,
route/1,
route/2,
process_iq/1,
open_session/5,
open_session/6,
close_session/4,
@@ -58,13 +57,12 @@
get_vh_session_list/1,
get_vh_session_number/1,
get_vh_by_backend/1,
register_iq_handler/4,
unregister_iq_handler/2,
force_update_presence/1,
connected_users/0,
connected_users_number/0,
user_resources/2,
kick_user/2,
kick_user/3,
get_session_pid/3,
get_session_sid/3,
get_session_sids/2,
@@ -87,7 +85,6 @@
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, terminate/2, code_change/3, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp.hrl").
@@ -145,9 +142,10 @@ route(Packet) ->
Packet1 ->
try do_route(Packet1), ok
catch E:R ->
St = erlang:get_stacktrace(),
?ERROR_MSG("failed to route packet:~n~s~nReason = ~p",
[xmpp:pp(Packet1),
{E, {R, erlang:get_stacktrace()}}])
{E, {R, St}}])
end
end.
@@ -245,10 +243,12 @@ get_user_info(User, Server) ->
LServer = jid:nameprep(Server),
Mod = get_sm_backend(LServer),
Ss = online(get_sessions(Mod, LUser, LServer)),
[{LResource, [{node, node(Pid)}|Info]}
[{LResource, [{node, node(Pid)}, {ts, Ts}, {pid, Pid},
{priority, Priority} | Info]}
|| #session{usr = {_, _, LResource},
priority = Priority,
info = Info,
sid = {_, Pid}} <- clean_session_list(Ss)].
sid = {Ts, Pid}} <- clean_session_list(Ss)].
-spec get_user_info(binary(), binary(), binary()) -> info() | offline.
@@ -262,8 +262,11 @@ get_user_info(User, Server, Resource) ->
offline;
Ss ->
Session = lists:max(Ss),
Node = node(element(2, Session#session.sid)),
[{node, Node}|Session#session.info]
{Ts, Pid} = Session#session.sid,
Node = node(Pid),
Priority = Session#session.priority,
[{node, Node}, {ts, Ts}, {pid, Pid}, {priority, Priority}
|Session#session.info]
end.
-spec set_presence(sid(), binary(), binary(), binary(),
@@ -397,17 +400,6 @@ get_vh_session_number(Server) ->
Mod = get_sm_backend(LServer),
length(online(get_sessions(Mod, LServer))).
-spec register_iq_handler(binary(), binary(), atom(), atom()) -> ok.
register_iq_handler(Host, XMLNS, Module, Fun) ->
?GEN_SERVER:cast(?MODULE,
{register_iq_handler, Host, XMLNS, Module, Fun}).
-spec unregister_iq_handler(binary(), binary()) -> ok.
unregister_iq_handler(Host, XMLNS) ->
?GEN_SERVER:cast(?MODULE, {unregister_iq_handler, Host, XMLNS}).
%% Why the hell do we have so many similar kicks?
c2s_handle_info(#{lang := Lang} = State, replaced) ->
State1 = State#{replaced => true},
@@ -435,28 +427,26 @@ config_reloaded() ->
init([]) ->
process_flag(trap_exit, true),
init_cache(),
lists:foreach(fun(Mod) -> Mod:init() end, get_sm_backends()),
clean_cache(),
ets:new(sm_iqtable, [named_table, public, {read_concurrency, true}]),
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
lists:foreach(fun host_up/1, ?MYHOSTS),
ejabberd_commands:register_commands(get_commands_spec()),
{ok, #state{}}.
case lists:foldl(
fun(Mod, ok) -> Mod:init();
(_, Err) -> Err
end, ok, get_sm_backends()) of
ok ->
clean_cache(),
gen_iq_handler:start(?MODULE),
ejabberd_hooks:add(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:add(host_down, ?MODULE, host_down, 60),
ejabberd_hooks:add(config_reloaded, ?MODULE, config_reloaded, 50),
lists:foreach(fun host_up/1, ejabberd_config:get_myhosts()),
ejabberd_commands:register_commands(get_commands_spec()),
{ok, #state{}};
{error, Why} ->
{stop, Why}
end.
handle_call(_Request, _From, State) ->
Reply = ok, {reply, Reply, State}.
handle_cast({register_iq_handler, Host, XMLNS, Module, Function},
State) ->
ets:insert(sm_iqtable,
{{Host, XMLNS}, Module, Function}),
{noreply, State};
handle_cast({unregister_iq_handler, Host, XMLNS},
State) ->
ets:delete(sm_iqtable, {Host, XMLNS}),
{noreply, State};
handle_cast(_Msg, State) -> {noreply, State}.
handle_info({route, Packet}, State) ->
@@ -467,7 +457,7 @@ handle_info(Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
lists:foreach(fun host_down/1, ?MYHOSTS),
lists:foreach(fun host_down/1, ejabberd_config:get_myhosts()),
ejabberd_hooks:delete(host_up, ?MODULE, host_up, 50),
ejabberd_hooks:delete(host_down, ?MODULE, host_down, 60),
ejabberd_hooks:delete(config_reloaded, ?MODULE, config_reloaded, 50),
@@ -664,7 +654,7 @@ do_route(#message{to = #jid{lresource = <<"">>}, type = T} = Packet) ->
end;
do_route(#iq{to = #jid{lresource = <<"">>}} = Packet) ->
?DEBUG("processing IQ to bare JID:~n~s", [xmpp:pp(Packet)]),
process_iq(Packet);
gen_iq_handler:handle(?MODULE, Packet);
do_route(Packet) ->
?DEBUG("processing packet to full JID:~n~s", [xmpp:pp(Packet)]),
To = xmpp:get_to(Packet),
@@ -849,31 +839,6 @@ get_max_user_sessions(LUser, Host) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec process_iq(iq()) -> any().
process_iq(#iq{to = To, type = T, lang = Lang, sub_els = [El]} = Packet)
when T == get; T == set ->
XMLNS = xmpp:get_ns(El),
Host = To#jid.lserver,
case ets:lookup(sm_iqtable, {Host, XMLNS}) of
[{_, Module, Function}] ->
gen_iq_handler:handle(Host, Module, Function, Packet);
[] ->
Txt = <<"No module is handling this query">>,
Err = xmpp:err_service_unavailable(Txt, Lang),
ejabberd_router:route_error(Packet, Err)
end;
process_iq(#iq{type = T, lang = Lang, sub_els = SubEls} = Packet)
when T == get; T == set ->
Txt = case SubEls of
[] -> <<"No child elements found">>;
_ -> <<"Too many child elements">>
end,
Err = xmpp:err_bad_request(Txt, Lang),
ejabberd_router:route_error(Packet, Err);
process_iq(#iq{}) ->
ok.
-spec force_update_presence({binary(), binary()}) -> ok.
force_update_presence({LUser, LServer}) ->
@@ -895,7 +860,7 @@ get_sm_backend(Host) ->
-spec get_sm_backends() -> [module()].
get_sm_backends() ->
lists:usort([get_sm_backend(Host) || Host <- ?MYHOSTS]).
lists:usort([get_sm_backend(Host) || Host <- ejabberd_config:get_myhosts()]).
-spec get_vh_by_backend(module()) -> [binary()].
@@ -903,7 +868,7 @@ get_vh_by_backend(Mod) ->
lists:filter(
fun(Host) ->
get_sm_backend(Host) == Mod
end, ?MYHOSTS).
end, ejabberd_config:get_myhosts()).
%%--------------------------------------------------------------------
%%% Cache stuff
@@ -933,7 +898,7 @@ cache_opts() ->
end,
[{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
-spec clean_cache(node()) -> ok.
-spec clean_cache(node()) -> non_neg_integer().
clean_cache(Node) ->
ets_cache:filter(
?SM_CACHE,
@@ -966,7 +931,7 @@ use_cache() ->
fun(Host) ->
Mod = get_sm_backend(Host),
use_cache(Mod, Host)
end, ?MYHOSTS).
end, ejabberd_config:get_myhosts()).
-spec cache_nodes(module(), binary()) -> [node()].
cache_nodes(Mod, LServer) ->
@@ -1026,24 +991,28 @@ user_resources(User, Server) ->
Resources = get_user_resources(User, Server),
lists:sort(Resources).
-spec kick_user(binary(), binary()) -> non_neg_integer().
kick_user(User, Server) ->
Resources = get_user_resources(User, Server),
lists:foreach(
fun(Resource) ->
PID = get_session_pid(User, Server, Resource),
ejabberd_c2s:route(PID, kick)
end, Resources),
length(Resources).
lists:foldl(
fun(Resource, Acc) ->
case kick_user(User, Server, Resource) of
false -> Acc;
true -> Acc + 1
end
end, 0, Resources).
-spec kick_user(binary(), binary(), binary()) -> boolean().
kick_user(User, Server, Resource) ->
case get_session_pid(User, Server, Resource) of
none -> false;
Pid -> ejabberd_c2s:route(Pid, kick)
end.
make_sid() ->
{p1_time_compat:unique_timestamp(), self()}.
-spec opt_type(sm_db_type) -> fun((atom()) -> atom());
(sm_use_cache) -> fun((boolean()) -> boolean());
(sm_cache_missed) -> fun((boolean()) -> boolean());
(sm_cache_size) -> fun((timeout()) -> timeout());
(sm_cache_life_time) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(sm_db_type) -> fun(T) -> ejabberd_config:v_db(?MODULE, T) end;
opt_type(O) when O == sm_use_cache; O == sm_cache_missed ->
fun(B) when is_boolean(B) -> B end;
-1
View File
@@ -40,7 +40,6 @@
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3, start_link/0]).
-include("ejabberd.hrl").
-include("ejabberd_sm.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
+79 -29
View File
@@ -27,21 +27,20 @@
-define(GEN_SERVER, p1_server).
-endif.
-behaviour(?GEN_SERVER).
-behaviour(ejabberd_sm).
-export([init/0, set_session/1, delete_session/1,
get_sessions/0, get_sessions/1, get_sessions/2,
cache_nodes/1]).
cache_nodes/1, clean_table/1, clean_table/0]).
%% gen_server callbacks
-export([init/1, handle_cast/2, handle_call/3, handle_info/2,
terminate/2, code_change/3, start_link/0]).
-include("ejabberd.hrl").
-include("ejabberd_sm.hrl").
-include("logger.hrl").
-define(SM_KEY, <<"ejabberd:sm">>).
-define(MIN_REDIS_VERSION, <<"3.2.0">>).
-record(state, {}).
%%%===================================================================
@@ -71,10 +70,14 @@ set_session(Session) ->
SIDKey = sid_to_key(Session#session.sid),
ServKey = server_to_key(element(2, Session#session.us)),
USSIDKey = us_sid_to_key(Session#session.us, Session#session.sid),
NodeHostKey = node_host_to_key(node(), element(2, Session#session.us)),
case ejabberd_redis:multi(
fun() ->
ejabberd_redis:hset(USKey, SIDKey, T),
ejabberd_redis:hset(ServKey, USSIDKey, T),
ejabberd_redis:hset(NodeHostKey,
<<USKey/binary, "||", SIDKey/binary>>,
USSIDKey),
ejabberd_redis:publish(
?SM_KEY, term_to_binary({delete, Session#session.us}))
end) of
@@ -90,10 +93,13 @@ delete_session(#session{sid = SID} = Session) ->
SIDKey = sid_to_key(SID),
ServKey = server_to_key(element(2, Session#session.us)),
USSIDKey = us_sid_to_key(Session#session.us, SID),
NodeHostKey = node_host_to_key(node(), element(2, Session#session.us)),
case ejabberd_redis:multi(
fun() ->
ejabberd_redis:hdel(USKey, [SIDKey]),
ejabberd_redis:hdel(ServKey, [USSIDKey]),
ejabberd_redis:hdel(NodeHostKey,
[<<USKey/binary, "||", SIDKey/binary>>]),
ejabberd_redis:publish(
?SM_KEY,
term_to_binary({delete, Session#session.us}))
@@ -137,8 +143,10 @@ get_sessions(LUser, LServer) ->
%%%===================================================================
init([]) ->
ejabberd_redis:subscribe([?SM_KEY]),
clean_table(),
{ok, #state{}}.
case clean_table() of
ok -> {ok, #state{}};
{error, Why} -> {stop, Why}
end.
handle_call(_Request, _From, State) ->
Reply = ok,
@@ -169,10 +177,10 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%%===================================================================
us_to_key({LUser, LServer}) ->
<<"ejabberd:sm:", LUser/binary, "@", LServer/binary>>.
<<(?SM_KEY)/binary, ":", LUser/binary, "@", LServer/binary>>.
server_to_key(LServer) ->
<<"ejabberd:sm:", LServer/binary>>.
<<(?SM_KEY)/binary, ":", LServer/binary>>.
us_sid_to_key(US, SID) ->
term_to_binary({US, SID}).
@@ -180,33 +188,75 @@ us_sid_to_key(US, SID) ->
sid_to_key(SID) ->
term_to_binary(SID).
node_session_deletion_cursor(Node, Host) ->
NodeName = node_host_to_key(Node, Host),
<<NodeName/binary, ":deletioncursor">>.
node_host_to_key(Node, Host) when is_atom(Node) ->
NodeBin = atom_to_binary(node(), utf8),
node_host_to_key(NodeBin, Host);
node_host_to_key(NodeBin, Host) ->
HostKey = server_to_key(Host),
<<HostKey/binary, ":node:", NodeBin/binary>>.
decode_session_list(Vals) ->
[binary_to_term(Val) || {_, Val} <- Vals].
clean_table() ->
?DEBUG("Cleaning Redis SM table...", []),
clean_table(node()).
clean_table(Node) when is_atom(Node) ->
clean_table(atom_to_binary(Node, utf8));
clean_table(Node) ->
?DEBUG("Cleaning Redis SM table... ", []),
try
lists:foreach(
fun(LServer) ->
ServKey = server_to_key(LServer),
{ok, Vals} = ejabberd_redis:hkeys(ServKey),
{ok, _} =
ejabberd_redis:multi(
fun() ->
lists:foreach(
fun(USSIDKey) ->
{US, SID} = binary_to_term(USSIDKey),
if node(element(2, SID)) == node() ->
USKey = us_to_key(US),
SIDKey = sid_to_key(SID),
ejabberd_redis:hdel(ServKey, [USSIDKey]),
ejabberd_redis:hdel(USKey, [SIDKey]);
true ->
ok
end
end, Vals)
end)
fun(Host) ->
ok = clean_node_sessions(Node, Host)
end, ejabberd_sm:get_vh_by_backend(?MODULE))
catch _:{badmatch, {error, _}} ->
?ERROR_MSG("failed to clean redis c2s sessions", [])
catch _:{badmatch, {error, _} = Err} ->
?ERROR_MSG("Failed to clean Redis SM table", []),
Err
end.
clean_node_sessions(Node, Host) ->
case load_script() of
{ok, SHA} ->
clean_node_sessions(Node, Host, SHA);
Err ->
Err
end.
clean_node_sessions(Node, Host, SHA) ->
Keys = [node_host_to_key(Node, Host),
server_to_key(Host),
node_session_deletion_cursor(Node, Host)],
case ejabberd_redis:evalsha(SHA, Keys, [1000]) of
{ok, <<"0">>} ->
ok;
{ok, _Cursor} ->
clean_node_sessions(Node, Host, SHA);
{error, _} = Err ->
Err
end.
load_script() ->
case misc:read_lua("redis_sm.lua") of
{ok, Data} ->
case ejabberd_redis:info(server) of
{ok, Info} ->
case proplists:get_value(redis_version, Info) of
V when V >= ?MIN_REDIS_VERSION ->
ejabberd_redis:script_load(Data);
V ->
?CRITICAL_MSG("Unsupported Redis version: ~s. "
"The version must be ~s or above",
[V, ?MIN_REDIS_VERSION]),
{error, unsupported_redis_version}
end;
{error, _} = Err ->
Err
end;
{error, _} = Err ->
Err
end.
+1 -2
View File
@@ -36,7 +36,6 @@
get_sessions/1,
get_sessions/2]).
-include("ejabberd.hrl").
-include("ejabberd_sm.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
@@ -56,7 +55,7 @@ init() ->
ok;
Err ->
?ERROR_MSG("failed to clean 'sm' table: ~p", [Err]),
Err
{error, db_failure}
end;
(_, Err) ->
Err
+72 -46
View File
@@ -66,7 +66,6 @@
session_established/2, session_established/3,
opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
@@ -137,7 +136,7 @@ start_link(Host, StartInterval) ->
-spec sql_query(binary(), sql_query()) -> sql_query_result().
sql_query(Host, Query) ->
check_error(sql_call(Host, {sql_query, Query}), Query).
sql_call(Host, {sql_query, Query}).
%% SQL transaction based on a list of queries
%% This function automatically
@@ -173,10 +172,16 @@ sql_call(Host, Msg) ->
end.
keep_alive(Host, PID) ->
sync_send_event(PID,
case sync_send_event(PID,
{sql_cmd, {sql_query, ?KEEPALIVE_QUERY},
p1_time_compat:monotonic_time(milli_seconds)},
query_timeout(Host)).
query_timeout(Host)) of
{selected,[<<"1">>],[[<<"1">>]]} ->
ok;
_Err ->
?ERROR_MSG("keep alive query failed, closing connection: ~p", [_Err]),
sync_send_event(PID, force_timeout, query_timeout(Host))
end.
sync_send_event(Pid, Msg, Timeout) ->
try p1_fsm:sync_send_event(Pid, Msg, Timeout)
@@ -336,10 +341,10 @@ connecting(connect, #state{host = Host} = State) ->
State2 = get_db_version(State1),
{next_state, session_established, State2};
{error, Reason} ->
?INFO_MSG("~p connection failed:~n** Reason: ~p~n** "
"Retry after: ~p seconds",
[State#state.db_type, Reason,
State#state.start_interval div 1000]),
?WARNING_MSG("~p connection failed:~n** Reason: ~p~n** "
"Retry after: ~p seconds",
[State#state.db_type, Reason,
State#state.start_interval div 1000]),
p1_fsm:send_event_after(State#state.start_interval,
connect),
{next_state, connecting, State}
@@ -390,6 +395,8 @@ session_established(Request, {Who, _Ref}, State) ->
session_established({sql_cmd, Command, From, Timestamp},
State) ->
run_sql_cmd(Command, From, State, Timestamp);
session_established(force_timeout, State) ->
{stop, timeout, State};
session_established(Event, State) ->
?WARNING_MSG("unexpected event in 'session_established': ~p",
[Event]),
@@ -581,18 +588,19 @@ sql_query_internal(#sql_query{} = Query) ->
sqlite ->
sqlite_sql_query(Query)
end
catch
Class:Reason ->
catch exit:{timeout, _} ->
{error, <<"timed out">>};
exit:{killed, _} ->
{error, <<"killed">>};
exit:{normal, _} ->
{error, <<"terminated unexpectedly">>};
Class:Reason ->
ST = erlang:get_stacktrace(),
?ERROR_MSG("Internal error while processing SQL query: ~p",
[{Class, Reason, ST}]),
{error, <<"internal error">>}
end,
case Res of
{error, <<"No SQL-driver information available.">>} ->
{updated, 0};
_Else -> Res
end;
check_error(Res, Query);
sql_query_internal(F) when is_function(F) ->
case catch execute_fun(F) of
{'EXIT', Reason} -> {error, Reason};
@@ -617,17 +625,12 @@ sql_query_internal(Query) ->
[Query], self(),
[{timeout, QueryTimeout - 1000},
{result_type, binary}])),
%% ?INFO_MSG("MySQL, Received result~n~p~n", [R]),
R;
sqlite ->
Host = State#state.host,
sqlite_to_odbc(Host, sqlite3:sql_exec(sqlite_db(Host), Query))
end,
case Res of
{error, <<"No SQL-driver information available.">>} ->
{updated, 0};
_Else -> Res
end.
check_error(Res, Query).
select_sql_query(Queries, State) ->
select_sql_query(
@@ -746,14 +749,23 @@ sql_query_to_iolist(SQLQuery) ->
generic_sql_query_format(SQLQuery).
%% Generate the OTP callback return tuple depending on the driver result.
abort_on_driver_error({error, <<"query timed out">>} =
Reply,
abort_on_driver_error({error,
<<"query timed out">>} = Reply,
From) ->
p1_fsm:reply(From, Reply),
{stop, timeout, get(?STATE_KEY)};
abort_on_driver_error({error,
<<"Failed sending data on socket", _/binary>>} =
Reply,
<<"Failed sending data on socket", _/binary>>} = Reply,
From) ->
p1_fsm:reply(From, Reply),
{stop, closed, get(?STATE_KEY)};
abort_on_driver_error({error,
<<"SQL connection failed">>} = Reply,
From) ->
p1_fsm:reply(From, Reply),
{stop, timeout, get(?STATE_KEY)};
abort_on_driver_error({error,
<<"Communication link failure">>} = Reply,
From) ->
p1_fsm:reply(From, Reply),
{stop, closed, get(?STATE_KEY)};
@@ -769,6 +781,7 @@ odbc_connect(SQLServer, Timeout) ->
ejabberd:start_app(odbc),
odbc:connect(binary_to_list(SQLServer),
[{scrollable_cursors, off},
{extended_errors, on},
{tuple_row, off},
{timeout, Timeout},
{binary_strings, on}]).
@@ -1030,6 +1043,7 @@ init_mssql(Host) ->
FreeTDS = io_lib:fwrite("[~s]~n"
"\thost = ~s~n"
"\tport = ~p~n"
"\tclient charset = UTF-8~n"
"\ttds version = 7.1~n",
[Host, Server, Port]),
ODBCINST = io_lib:fwrite("[freetds]~n"
@@ -1094,37 +1108,49 @@ query_timeout(LServer) ->
timer:seconds(
ejabberd_config:get_option({sql_query_timeout, LServer}, 60)).
%% ***IMPORTANT*** This error format requires extended_errors turned on.
extended_error({"08S01", _, Reason}) ->
% TCP Provider: The specified network name is no longer available
?DEBUG("ODBC Link Failure: ~s", [Reason]),
<<"Communication link failure">>;
extended_error({"08001", _, Reason}) ->
% Login timeout expired
?DEBUG("ODBC Connect Timeout: ~s", [Reason]),
<<"SQL connection failed">>;
extended_error({"IMC01", _, Reason}) ->
% The connection is broken and recovery is not possible
?DEBUG("ODBC Link Failure: ~s", [Reason]),
<<"Communication link failure">>;
extended_error({"IMC06", _, Reason}) ->
% The connection is broken and recovery is not possible
?DEBUG("ODBC Link Failure: ~s", [Reason]),
<<"Communication link failure">>;
extended_error({Code, _, Reason}) ->
?DEBUG("ODBC Error ~s: ~s", [Code, Reason]),
iolist_to_binary(Reason);
extended_error(Error) ->
Error.
check_error({error, Why} = Err, _Query) when Why == killed ->
Err;
check_error({error, Why} = Err, #sql_query{} = Query) ->
check_error({error, Why}, #sql_query{} = Query) ->
Err = extended_error(Why),
?ERROR_MSG("SQL query '~s' at ~p failed: ~p",
[Query#sql_query.hash, Query#sql_query.loc, Why]),
Err;
check_error({error, Why} = Err, Query) ->
[Query#sql_query.hash, Query#sql_query.loc, Err]),
{error, Err};
check_error({error, Why}, Query) ->
Err = extended_error(Why),
case catch iolist_to_binary(Query) of
SQuery when is_binary(SQuery) ->
?ERROR_MSG("SQL query '~s' failed: ~p", [SQuery, Why]);
?ERROR_MSG("SQL query '~s' failed: ~p", [SQuery, Err]);
_ ->
?ERROR_MSG("SQL query ~p failed: ~p", [Query, Why])
?ERROR_MSG("SQL query ~p failed: ~p", [Query, Err])
end,
Err;
{error, Err};
check_error(Result, _Query) ->
Result.
-spec opt_type(sql_database) -> fun((binary()) -> binary());
(sql_keepalive_interval) -> fun((pos_integer()) -> pos_integer());
(sql_password) -> fun((binary()) -> binary());
(sql_port) -> fun((0..65535) -> 0..65535);
(sql_server) -> fun((binary()) -> binary());
(sql_username) -> fun((binary()) -> binary());
(sql_ssl) -> fun((boolean()) -> boolean());
(sql_ssl_verify) -> fun((boolean()) -> boolean());
(sql_ssl_certfile) -> fun((boolean()) -> boolean());
(sql_ssl_cafile) -> fun((boolean()) -> boolean());
(sql_query_timeout) -> fun((pos_integer()) -> pos_integer());
(sql_connect_timeout) -> fun((pos_integer()) -> pos_integer());
(sql_queue_type) -> fun((ram | file) -> ram | file);
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(sql_database) -> fun iolist_to_binary/1;
opt_type(sql_keepalive_interval) ->
fun (I) when is_integer(I), I > 0 -> I end;
+47 -32
View File
@@ -31,22 +31,19 @@
-export([start_link/1, init/1, add_pid/2, remove_pid/2,
get_pids/1, get_random_pid/1, transform_options/1,
opt_type/1]).
reload/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
-define(PGSQL_PORT, 5432).
-define(MYSQL_PORT, 3306).
-define(DEFAULT_POOL_SIZE, 10).
-define(DEFAULT_SQL_START_INTERVAL, 30).
-define(CONNECT_TIMEOUT, 500).
-record(sql_pool, {host, pid}).
-record(sql_pool, {host :: binary(),
pid :: pid()}).
start_link(Host) ->
ejabberd_mnesia:create(?MODULE, sql_pool,
@@ -60,9 +57,6 @@ start_link(Host) ->
?MODULE, [Host]).
init([Host]) ->
StartInterval = ejabberd_config:get_option(
{sql_start_interval, Host},
?DEFAULT_SQL_START_INTERVAL),
Type = ejabberd_config:get_option({sql_type, Host}, odbc),
PoolSize = get_pool_size(Type, Host),
case Type of
@@ -73,16 +67,37 @@ init([Host]) ->
_ ->
ok
end,
{ok, {{one_for_one, PoolSize * 10, 1},
[child_spec(I, Host) || I <- lists:seq(1, PoolSize)]}}.
{ok,
{{one_for_one, PoolSize * 10, 1},
lists:map(fun (I) ->
{I,
{ejabberd_sql, start_link,
[Host, StartInterval * 1000]},
transient, 2000, worker, [?MODULE]}
end,
lists:seq(1, PoolSize))}}.
reload(Host) ->
Type = ejabberd_config:get_option({sql_type, Host}, odbc),
NewPoolSize = get_pool_size(Type, Host),
OldPoolSize = ets:select_count(
sql_pool,
ets:fun2ms(
fun(#sql_pool{host = H}) when H == Host ->
true
end)),
reload(Host, NewPoolSize, OldPoolSize).
reload(Host, NewPoolSize, OldPoolSize) ->
Sup = gen_mod:get_module_proc(Host, ?MODULE),
if NewPoolSize == OldPoolSize ->
ok;
NewPoolSize > OldPoolSize ->
lists:foreach(
fun(I) ->
Spec = child_spec(I, Host),
supervisor:start_child(Sup, Spec)
end, lists:seq(OldPoolSize+1, NewPoolSize));
OldPoolSize > NewPoolSize ->
lists:foreach(
fun(I) ->
supervisor:terminate_child(Sup, I),
supervisor:delete_child(Sup, I)
end, lists:seq(NewPoolSize+1, OldPoolSize))
end.
get_pids(Host) ->
Rs = mnesia:dirty_read(sql_pool, Host),
@@ -92,7 +107,7 @@ get_random_pid(Host) ->
case get_pids(Host) of
[] -> none;
Pids ->
I = randoms:round_robin(length(Pids)) + 1,
I = p1_rand:round_robin(length(Pids)) + 1,
lists:nth(I, Pids)
end.
@@ -124,6 +139,13 @@ get_pool_size(SQLType, Host) ->
end,
PoolSize.
child_spec(I, Host) ->
StartInterval = ejabberd_config:get_option(
{sql_start_interval, Host},
?DEFAULT_SQL_START_INTERVAL),
{I, {ejabberd_sql, start_link, [Host, timer:seconds(StartInterval)]},
transient, 2000, worker, [?MODULE]}.
transform_options(Opts) ->
lists:foldl(fun transform_options/2, [], Opts).
@@ -168,16 +190,11 @@ check_sqlite_db(Host) ->
ok
end;
{error, Reason} ->
?INFO_MSG("Failed open sqlite database, reason ~p", [Reason])
?WARNING_MSG("Failed open sqlite database, reason ~p", [Reason])
end.
create_sqlite_tables(DB) ->
SqlDir = case code:priv_dir(ejabberd) of
{error, _} ->
?SQL_DIR;
PrivDir ->
filename:join(PrivDir, "sql")
end,
SqlDir = misc:sql_dir(),
File = filename:join(SqlDir, "lite.sql"),
case file:open(File, [read, binary]) of
{ok, Fd} ->
@@ -186,8 +203,8 @@ create_sqlite_tables(DB) ->
[ok = sqlite3:sql_exec(DB, Q) || Q <- Qs],
ok = sqlite3:sql_exec(DB, "commit");
{error, Reason} ->
?INFO_MSG("Failed to read SQLite schema file: ~s",
[file:format_error(Reason)])
?WARNING_MSG("Failed to read SQLite schema file: ~s",
[file:format_error(Reason)])
end.
read_lines(Fd, File, Acc) ->
@@ -218,9 +235,7 @@ read_lines(Fd, File, Acc) ->
[]
end.
-spec opt_type(sql_pool_size) -> fun((pos_integer()) -> pos_integer());
(sql_start_interval) -> fun((pos_integer()) -> pos_integer());
(atom()) -> [atom()].
-spec opt_type(atom()) -> fun((any()) -> any()) | [atom()].
opt_type(sql_pool_size) ->
fun (I) when is_integer(I), I > 0 -> I end;
opt_type(sql_start_interval) ->
+40 -41
View File
@@ -24,29 +24,30 @@
%%%-------------------------------------------------------------------
-module(ejabberd_stun).
-behaviour(ejabberd_listener).
-protocol({rfc, 5766}).
-protocol({xep, 176, '1.0'}).
-ifndef(STUN).
-include("logger.hrl").
-export([socket_type/0, start/2, listen_opt_type/1]).
log_error() ->
?CRITICAL_MSG("ejabberd is not compiled with STUN/TURN support", []).
socket_type() ->
log_error(),
raw.
listen_opt_type(_) ->
log_error(),
[].
-export([accept/1, start/2, start_link/2, listen_options/0]).
fail() ->
?CRITICAL_MSG("Listening module ~s is not available: "
"ejabberd is not compiled with STUN/TURN support",
[?MODULE]),
erlang:error(stun_not_compiled).
accept(_) ->
fail().
listen_options() ->
fail().
start(_, _) ->
log_error(),
{error, sip_not_compiled}.
fail().
start_link(_, _) ->
fail().
-else.
-export([tcp_init/2, udp_init/2, udp_recv/5, start/2,
socket_type/0, listen_opt_type/1]).
start_link/2, accept/1, listen_opt_type/1, listen_options/0]).
-include("ejabberd.hrl").
-include("logger.hrl").
%%%===================================================================
@@ -66,8 +67,11 @@ udp_recv(Socket, Addr, Port, Packet, Opts) ->
start(Opaque, Opts) ->
stun:start(Opaque, Opts).
socket_type() ->
raw.
start_link({gen_tcp, Sock}, Opts) ->
stun:start_link(Sock, Opts).
accept(_Pid) ->
ok.
%%%===================================================================
%%% Internal functions
@@ -79,7 +83,7 @@ prepare_turn_opts(Opts) ->
prepare_turn_opts(Opts, _UseTurn = false) ->
set_certfile(Opts);
prepare_turn_opts(Opts, _UseTurn = true) ->
NumberOfMyHosts = length(?MYHOSTS),
NumberOfMyHosts = length(ejabberd_config:get_myhosts()),
case proplists:get_value(turn_ip, Opts) of
undefined ->
?WARNING_MSG("option 'turn_ip' is undefined, "
@@ -100,15 +104,15 @@ prepare_turn_opts(Opts, _UseTurn = true) ->
"'auth_type' is set to 'user', "
"more likely the TURN relay won't "
"be working properly. Using ~s as "
"a fallback", [?MYNAME]);
"a fallback", [ejabberd_config:get_myname()]);
true ->
ok
end,
[{auth_realm, ?MYNAME}];
[{auth_realm, ejabberd_config:get_myname()}];
_ ->
[]
end,
MaxRate = shaper:get_max_rate(Shaper),
MaxRate = ejabberd_shaper:get_max_rate(Shaper),
Opts1 = Realm ++ [{auth_fun, AuthFun},{shaper, MaxRate} |
lists:keydelete(shaper, 1, Opts)],
set_certfile(Opts1).
@@ -118,7 +122,7 @@ set_certfile(Opts) ->
true ->
Opts;
false ->
Realm = proplists:get_value(auth_realm, Opts, ?MYNAME),
Realm = proplists:get_value(auth_realm, Opts, ejabberd_config:get_myname()),
case ejabberd_pkix:get_certfile(Realm) of
{ok, CertFile} ->
[{certfile, CertFile}|Opts];
@@ -139,27 +143,16 @@ listen_opt_type(turn_ip) ->
{ok, Addr} = inet_parse:ipv4_address(binary_to_list(S)),
Addr
end;
listen_opt_type(shaper) ->
fun acl:shaper_rules_validator/1;
listen_opt_type(auth_type) ->
fun(anonymous) -> anonymous;
(user) -> user
end;
listen_opt_type(auth_realm) ->
fun iolist_to_binary/1;
listen_opt_type(tls) ->
fun(B) when is_boolean(B) -> B end;
listen_opt_type(certfile) ->
fun(S) ->
%% We cannot deprecate the option for now:
%% I think STUN/TURN clients are too stupid to set SNI
ejabberd_pkix:add_certfile(S),
iolist_to_binary(S)
end;
listen_opt_type(turn_min_port) ->
fun(P) when is_integer(P), P > 0, P =< 65535 -> P end;
fun(P) when is_integer(P), P > 1024, P < 65536 -> P end;
listen_opt_type(turn_max_port) ->
fun(P) when is_integer(P), P > 0, P =< 65535 -> P end;
fun(P) when is_integer(P), P > 1024, P < 65536 -> P end;
listen_opt_type(turn_max_allocations) ->
fun(I) when is_integer(I), I>0 -> I;
(unlimited) -> infinity;
@@ -171,11 +164,17 @@ listen_opt_type(turn_max_permissions) ->
(infinity) -> infinity
end;
listen_opt_type(server_name) ->
fun iolist_to_binary/1;
listen_opt_type(backlog) ->
fun(I) when is_integer(I), I>0 -> I end;
listen_opt_type(_) ->
[shaper, auth_type, auth_realm, tls, certfile, turn_min_port,
turn_max_port, turn_max_allocations, turn_max_permissions,
server_name, backlog].
fun iolist_to_binary/1.
listen_options() ->
[{shaper, none},
{auth_type, user},
{auth_realm, undefined},
{tls, false},
{certfile, undefined},
{turn_min_port, 49152},
{turn_max_port, 65535},
{turn_max_allocations, 10},
{turn_max_permissions, 10},
{server_name, <<"ejabberd">>}].
-endif.
+1 -2
View File
@@ -39,7 +39,6 @@ init([]) ->
{ok, {{one_for_one, 10, 1},
[worker(ejabberd_hooks),
worker(ejabberd_cluster),
worker(cyrsasl),
worker(translate),
worker(ejabberd_access_permissions),
worker(ejabberd_ctl),
@@ -53,7 +52,7 @@ init([]) ->
simple_supervisor(ejabberd_s2s_out),
simple_supervisor(ejabberd_service),
worker(acl),
worker(shaper),
worker(ejabberd_shaper),
supervisor(ejabberd_backend_sup),
supervisor(ejabberd_rdbms),
supervisor(ejabberd_riak_sup),

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