mirror of
https://github.com/anope/anope.git
synced 2026-06-20 04:34:47 +02:00
Compare commits
155 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ccc478830 | |||
| 100ecbb9be | |||
| cdf636e696 | |||
| 45878bf182 | |||
| f1bec3999d | |||
| a259244297 | |||
| c1da009de3 | |||
| 4f412bc213 | |||
| 1882916dc4 | |||
| f436ce9912 | |||
| ef9729fb02 | |||
| 296a75f2a9 | |||
| bce7237d9f | |||
| 85834e19dc | |||
| ca6b3723a9 | |||
| 23b1086072 | |||
| 860deb14ce | |||
| 62885fa462 | |||
| 3fef01e35b | |||
| b0597e35ec | |||
| 8d1ad6fbe5 | |||
| 750569201a | |||
| 1a1a781b72 | |||
| 4b5ce8a972 | |||
| 98cfdd26c4 | |||
| 051a42b547 | |||
| 220e278213 | |||
| 547fe0da1a | |||
| 09bec79b47 | |||
| 55a5affcb8 | |||
| a8b4297023 | |||
| 5969362425 | |||
| 3ceae33b16 | |||
| 5de4c1fc97 | |||
| fd109048dd | |||
| a0747516ce | |||
| 605e1f2a03 | |||
| dc23c58869 | |||
| b7e646ec83 | |||
| 4d54358745 | |||
| ed0882ec04 | |||
| 526c4e4659 | |||
| b70f72bf2b | |||
| 2ad4c1906e | |||
| 049760cc7e | |||
| e2ecec31b5 | |||
| fee016bb84 | |||
| d24fb03917 | |||
| 5adc8bfefc | |||
| abcf0cde5a | |||
| 8f3bd314ed | |||
| e2d456d4ce | |||
| 96202ae545 | |||
| 2b0229d4e2 | |||
| beaa3196b3 | |||
| b6d771a114 | |||
| d3ed756bd0 | |||
| f8308841a6 | |||
| 1dfdf36fc3 | |||
| 4ac3ade126 | |||
| 212abeb986 | |||
| 7d4427c313 | |||
| e836be489e | |||
| 1db5c555d6 | |||
| bb1b015103 | |||
| e42684ac39 | |||
| d7de7eee60 | |||
| 0a390ad392 | |||
| aa6b12c5eb | |||
| e2bd08fbff | |||
| 2047934060 | |||
| e07dcbff08 | |||
| e3a8a45a61 | |||
| f1ad7fd582 | |||
| 43f2645b32 | |||
| b6935e706c | |||
| a3c845894d | |||
| 5933a5e9b1 | |||
| 109d8f431f | |||
| 1edb7e776b | |||
| 928e2e1b7c | |||
| 5a140e4898 | |||
| f64393941e | |||
| 0db81ca46a | |||
| 7f7144de1f | |||
| 3883716883 | |||
| 5beea4eb7e | |||
| 2d0fdb74d1 | |||
| 80588fba81 | |||
| ef7dc94f88 | |||
| 7b4eec9748 | |||
| baff417652 | |||
| 7074944810 | |||
| 1c39d25cca | |||
| f1c5c27f3f | |||
| 9c0134ee2c | |||
| 959fee5937 | |||
| 3854a5570f | |||
| ab1e0ebfb3 | |||
| cffe864900 | |||
| bc1575318b | |||
| a71d0f6757 | |||
| 50d7bf710e | |||
| d44bcef31b | |||
| c0ce71e55a | |||
| 0eeb0caf08 | |||
| b13bded620 | |||
| 1b1180fda6 | |||
| a4ecfa5bc0 | |||
| 3c8009b495 | |||
| ca85df2d74 | |||
| 5dfa6598c2 | |||
| f428d61045 | |||
| fc50edf046 | |||
| 269c2786e9 | |||
| 96fc940af7 | |||
| 8c8e6d464a | |||
| 22976b8a7c | |||
| 4dff710361 | |||
| fe80d2cded | |||
| 16dac87841 | |||
| 30c59562e0 | |||
| 6d61a84286 | |||
| f6b8596c7b | |||
| da6760f606 | |||
| ad962ad759 | |||
| 5327becf41 | |||
| f43c99c5cc | |||
| c0a491cb06 | |||
| 66cc965fd7 | |||
| 2440514a7b | |||
| fad1da81a3 | |||
| bb0e2a9a07 | |||
| 4f8c4f8fef | |||
| 25957111b2 | |||
| 9a8895359a | |||
| 53f8db0198 | |||
| f94cb7fb11 | |||
| c30fb13a0c | |||
| 7926238fd2 | |||
| 211a944210 | |||
| cff61617e1 | |||
| 4455d4346c | |||
| 405b41ec87 | |||
| bacb276181 | |||
| 4c1f6b48d8 | |||
| 53a78c2688 | |||
| e61a283c02 | |||
| c3302194eb | |||
| cd184596a2 | |||
| f28b1142f5 | |||
| 87230c17b7 | |||
| a29b7897f0 | |||
| e965bc3049 | |||
| 01780c9e7a |
@@ -497,6 +497,10 @@ if(WIN32)
|
||||
install(FILES ${Anope_SOURCE_DIR}/src/win32/anope.bat
|
||||
DESTINATION ${BIN_DIR}
|
||||
)
|
||||
|
||||
# Package any DLLs in src/win/
|
||||
file(GLOB EXTRA_DLLS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${Anope_SOURCE_DIR}/src/win32/*.dll")
|
||||
install(FILES ${EXTRA_DLLS} DESTINATION ${BIN_DIR})
|
||||
endif(WIN32)
|
||||
|
||||
install(CODE "file(REMOVE_RECURSE \"${CMAKE_INSTALL_PREFIX}/${LIB_DIR}/modules\")")
|
||||
|
||||
@@ -3,7 +3,17 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* First, create the service.
|
||||
* First, create the service. If you do not want to have a 'BotServ', but do want the ability to have
|
||||
* ChanServ assigned to channels for the use of fantasy commands, you may delete the below 'service' block.
|
||||
*
|
||||
* Note that deleting a 'service' block for a pseudoclient that is already online will not remove the
|
||||
* client, the client becomes no different from a normal service bot, so you will have to use botserv/bot
|
||||
* to manually delete the client.
|
||||
*
|
||||
* You may then waant to map some of the below commands to other services, like placing botserv/bot on
|
||||
* OperServ so you can delete the below client, and mapping assign and unassign to ChanServ so users are
|
||||
* able to control whether or not ChanServ is in the channel. You may also want to map botserv/set/nobot
|
||||
* to OperServ so you can restrict who can assign the other core service clients.
|
||||
*/
|
||||
service
|
||||
{
|
||||
@@ -62,6 +72,8 @@ module
|
||||
|
||||
/*
|
||||
* The name of the client that should be BotServ.
|
||||
*
|
||||
* This directive is optional.
|
||||
*/
|
||||
client = "BotServ"
|
||||
|
||||
|
||||
@@ -173,18 +173,18 @@ module
|
||||
* ChanServ privilege configuration.
|
||||
*
|
||||
* ChanServ privileges are used to determine who has what access in channels. By default the core has its own
|
||||
* set of levels it uses for various ChanServ commands, which are defined below. Privilege ranks are used to
|
||||
* determine how powerful privileges are relative to each other, which is used by Anope to determine who has greater
|
||||
* access in a channel.
|
||||
* set of privileges it uses for various commands, which are defined below. Privilege ranks are used to
|
||||
* determine how powerful privileges are relative to other privileges, which is used by Anope to determine
|
||||
* who has greater access in a channel.
|
||||
*
|
||||
* If you loaded cs_access, you may define a level for the privilege, which is used by chanserv/access and chanserv/levels.
|
||||
* If you load cs_access, you may define a level for the privilege, which is used by chanserv/access and chanserv/levels.
|
||||
* The levels defined will be used as the default levels for newly registered channels.
|
||||
* The level "founder" is a special level which means anyone with the privilege FOUNDER on the channel
|
||||
* has that permission. Additionally, the level "disabled" means that no one can use the privilege, including founders.
|
||||
*
|
||||
* If you loaded cs_flags, you may define a flag associated with that privilege for use in chanserv/flags.
|
||||
* If you load cs_flags, you may define a flag associated with that privilege for use in chanserv/flags.
|
||||
*
|
||||
* If you loaded cs_xop, you may define a xop command to associate the privilege with.
|
||||
* If you load cs_xop, you may define a XOP command to associate the privilege with.
|
||||
*
|
||||
* The name of privileges are uesd to associate them with channel modes. If you are using an IRCd that allows you to define additional
|
||||
* channel status modes, such as InspIRCd, you can associate privileges (and thus access levels, flags, xop) with the mode by naming
|
||||
@@ -829,7 +829,12 @@ command { service = "ChanServ"; name = "HELP"; command = "generic/help"; }
|
||||
* Provides commands chanserv/access and chanserv/levels.
|
||||
* Provides the access system "levels".
|
||||
*
|
||||
* Used for giving users access in channels.
|
||||
* Used for giving users access in channels using a levels system. Allows allows redefining which privileges
|
||||
* are representated by given level on a per channel basis.
|
||||
*
|
||||
* The "LIST" subcommand of chanserv/access will show every access entry on the channel, including access
|
||||
* entries not added by cs_access. The "level" of these entries will be the representation of the access
|
||||
* entry by the other access system, which could be an XOP command name, or a set of flags.
|
||||
*/
|
||||
module { name = "cs_access" }
|
||||
command { service = "ChanServ"; name = "ACCESS"; command = "chanserv/access"; group = "chanserv/access"; }
|
||||
@@ -921,6 +926,10 @@ command { service = "ChanServ"; name = "ENTRYMSG"; command = "chanserv/entrymsg"
|
||||
* Provides the access system "flags".
|
||||
*
|
||||
* Used for giving users access in channels.
|
||||
*
|
||||
* The "LIST" subcommand of chanserv/flags will show every access entry on the channel, including access
|
||||
* entries not added by cs_flags. The "Flags" of these entries will be the flags representation of the
|
||||
* privilege set granted by the access entry.
|
||||
*/
|
||||
module { name = "cs_flags" }
|
||||
command { service = "ChanServ"; name = "FLAGS"; command = "chanserv/flags"; group = "chanserv/access"; }
|
||||
@@ -1032,7 +1041,9 @@ command { service = "ChanServ"; name = "LOG"; command = "chanserv/log"; group =
|
||||
*
|
||||
* Provides the command chanserv/mode and chanserv/modes.
|
||||
*
|
||||
* Used for changing mode locks and changing modes.
|
||||
* Used for changing mode locks and changing modes. Multiple commands may be mapped to chanserv/modes, the
|
||||
* configuration directive 'set' and 'unset' are used to tell chanserv/modes which modes should be set or
|
||||
* unset when the command is executed.
|
||||
*/
|
||||
module
|
||||
{
|
||||
@@ -1255,6 +1266,9 @@ command { service = "ChanServ"; name = "UP"; command = "chanserv/up"; group = "c
|
||||
* privileges given by each is determined by the privilege:xop settings above. These commands should
|
||||
* be ordered from highest to lowest, as each command inherits the privileges of the commands below
|
||||
* it.
|
||||
*
|
||||
* The "LIST" subcommand of chanserv/xop will show only XOP access entries of the given XOP type. You
|
||||
* can not view the entire access list at once, and instead should use another access system to do that.
|
||||
*/
|
||||
module { name = "cs_xop" }
|
||||
command { service = "ChanServ"; name = "QOP"; command = "chanserv/xop"; group = "chanserv/access"; }
|
||||
|
||||
+6
-23
@@ -168,7 +168,7 @@ uplink
|
||||
|
||||
/*
|
||||
* Enable if Services should connect using SSL.
|
||||
* You must have m_ssl loaded for this to work.
|
||||
* You must have an SSL module loaded for this to work.
|
||||
*/
|
||||
ssl = no
|
||||
|
||||
@@ -276,13 +276,6 @@ module
|
||||
* If the protocol module you have loaded does not support this, this setting will have no effect.
|
||||
*/
|
||||
use_server_side_topiclock = yes
|
||||
|
||||
/*
|
||||
* Some IRCds allow "SASL" authentication to let users identify to Services
|
||||
* during the IRCd user registration process. If set, Services will allow
|
||||
* authenticating users through this mechanism.
|
||||
*/
|
||||
sasl = yes
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -768,6 +761,7 @@ log
|
||||
* nickserv/confirm - Can confirm other users nicknames
|
||||
* nickserv/drop - Can drop other users nicks
|
||||
* operserv/config - Can modify services's configuration
|
||||
* protected - Can not be kicked from channels by Services
|
||||
*
|
||||
* Available commands:
|
||||
* botserv/bot/del botserv/bot/add botserv/bot/change botserv/set/private
|
||||
@@ -786,7 +780,7 @@ log
|
||||
* memoserv/sendall memoserv/staff
|
||||
*
|
||||
* nickserv/getpass nickserv/getemail nickserv/suspend nickserv/ajoin
|
||||
* nickserv/resetpass nickserv/list
|
||||
* nickserv/list
|
||||
*
|
||||
* nickserv/saset/autoop nickserv/saset/email nickserv/saset/greet nickserv/saset/password
|
||||
* nickserv/saset/display nickserv/saset/kill nickserv/saset/language nickserv/saset/message
|
||||
@@ -832,7 +826,7 @@ opertype
|
||||
inherits = "Helper, Another Helper"
|
||||
|
||||
/* What commands (see above) this opertype may use */
|
||||
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/resetpass nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
|
||||
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
|
||||
|
||||
/* What privs (see above) this opertype has */
|
||||
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm"
|
||||
@@ -958,18 +952,6 @@ mail
|
||||
*/
|
||||
sendfrom = "services@localhost.net"
|
||||
|
||||
/*
|
||||
* If set, RESETPASS will be restricted to services operators with access to
|
||||
* nickserv/resetpass in their opertype:commands.
|
||||
* This directive is optional.
|
||||
*
|
||||
* WARNING: If you choose to not enable this option, you should limit the
|
||||
* number of processes that the services user can have at a time (you can
|
||||
* create a special user for this; remember to NEVER launch Services as
|
||||
* root).
|
||||
*/
|
||||
restrict = yes
|
||||
|
||||
/*
|
||||
* This controls the minimum amount of time a user must wait before sending
|
||||
* another e-mail after they have sent one. It also controls the minimum time
|
||||
@@ -1065,7 +1047,7 @@ mail
|
||||
|
||||
/*
|
||||
* This is the encryption type used by the databases. This must be set correctly or
|
||||
* your passwords will not work. Valid options are: md5, oldmd5, sha1, and none.
|
||||
* your passwords will not work. Valid options are: md5, oldmd5, sha1, and plain.
|
||||
* You must also be sure to load the correct encryption module below in the Encryption
|
||||
* Modules section so that your passwords work.
|
||||
*/
|
||||
@@ -1223,6 +1205,7 @@ module
|
||||
*
|
||||
*/
|
||||
|
||||
#module { name = "enc_bcrypt" }
|
||||
module { name = "enc_sha256" }
|
||||
#module { name = "enc_md5" }
|
||||
#module { name = "enc_sha1" }
|
||||
|
||||
@@ -103,7 +103,20 @@ command { service = "HostServ"; name = "DELALL"; command = "hostserv/delall"; pe
|
||||
*
|
||||
* Used for grouping one vHost to many nicks.
|
||||
*/
|
||||
module { name = "hs_group" }
|
||||
module
|
||||
{
|
||||
name = "hs_group"
|
||||
|
||||
/*
|
||||
* Upon nickserv/group, this option syncs the nick's main vHost to the grouped nick.
|
||||
*/
|
||||
syncongroup = false
|
||||
|
||||
/*
|
||||
* This makes vhosts act as if they are per account.
|
||||
*/
|
||||
synconset = false
|
||||
}
|
||||
command { service = "HostServ"; name = "GROUP"; command = "hostserv/group"; }
|
||||
|
||||
/*
|
||||
@@ -139,7 +152,7 @@ command { service = "HostServ"; name = "ON"; command = "hostserv/on"; }
|
||||
/*
|
||||
* hs_request
|
||||
*
|
||||
* Provides the commands hostserv/request, hostserv/active, hostserv/reject, and hostserv/waiting.
|
||||
* Provides the commands hostserv/request, hostserv/activate, hostserv/reject, and hostserv/waiting.
|
||||
*
|
||||
* Used to manage vHosts requested by users.
|
||||
*/
|
||||
|
||||
+181
-112
@@ -184,7 +184,7 @@ module { name = "help" }
|
||||
/* Time before connections to this server are timed out. */
|
||||
timeout = 30
|
||||
|
||||
/* Listen using SSL. Requires m_ssl. */
|
||||
/* Listen using SSL. Requires an SSL module. */
|
||||
#ssl = yes
|
||||
|
||||
/* If you are using a reverse proxy that sends one of the
|
||||
@@ -340,6 +340,82 @@ module { name = "help" }
|
||||
port = 3306
|
||||
}
|
||||
}
|
||||
/*
|
||||
* m_redis
|
||||
*
|
||||
* This module allows other modules to use Redis.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "m_redis"
|
||||
|
||||
/* A redis database */
|
||||
redis
|
||||
{
|
||||
/* The name of this service */
|
||||
name = "redis/main"
|
||||
|
||||
/*
|
||||
* The redis database to use. New connections default to 0.
|
||||
*/
|
||||
db = 0
|
||||
|
||||
ip = "127.0.0.1"
|
||||
port = 6379
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* m_regex_pcre [EXTRA]
|
||||
*
|
||||
* Provides the regex engine regex/pcre, which uses the Perl Compatible Regular Expressions library.
|
||||
*/
|
||||
#module { name = "m_regex_pcre" }
|
||||
|
||||
/*
|
||||
* m_regex_posix [EXTRA]
|
||||
*
|
||||
* Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
|
||||
* This is likely the only regex module you will not need extra libraries for.
|
||||
*/
|
||||
#module { name = "m_regex_posix" }
|
||||
|
||||
/*
|
||||
* m_regex_tre [EXTRA]
|
||||
*
|
||||
* Provides the regex engine regex/tre, which uses the TRE regex library.
|
||||
*/
|
||||
#module { name = "m_regex_tre" }
|
||||
|
||||
/*
|
||||
* m_rewrite
|
||||
*
|
||||
* Allows rewriting commands sent to/from clients.
|
||||
*/
|
||||
#module { name = "m_rewrite" }
|
||||
#command
|
||||
{
|
||||
service = "ChanServ"; name = "CLEAR"; command = "rewrite"
|
||||
|
||||
/* Enable m_rewrite. */
|
||||
rewrite = true
|
||||
|
||||
/* Source message to match. A $ can be used to match anything. */
|
||||
rewrite_source = "CLEAR $ USERS"
|
||||
|
||||
/*
|
||||
* Message to rewrite the source message to. A $ followed by a number, eg $0, gets
|
||||
* replaced by the number-th word from the source_message, starting from 0.
|
||||
*/
|
||||
rewrite_target = "KICK $1 *"
|
||||
|
||||
/*
|
||||
* The command description. This only shows up in HELP's output.
|
||||
* Comment this option to prevent the command from showing in the
|
||||
* HELP command.
|
||||
*/
|
||||
rewrite_description = "Clears all users from a channel"
|
||||
}
|
||||
|
||||
/*
|
||||
* m_proxyscan
|
||||
@@ -423,6 +499,97 @@ module { name = "help" }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* m_sasl
|
||||
*
|
||||
* Some IRCds allow "SASL" authentication to let users identify to Services
|
||||
* during the IRCd user registration process. If this module is loaded, Services will allow
|
||||
* authenticating users through this mechanism. Supported mechanisms are:
|
||||
* PLAIN, EXTERNAL.
|
||||
*/
|
||||
#module { name = "m_sasl" }
|
||||
|
||||
/*
|
||||
* m_sasl_dh-aes [EXTRA]
|
||||
*
|
||||
* Add the DH-AES mechanism to SASL.
|
||||
* Requires m_sasl to be loaded.
|
||||
* Requires openssl.
|
||||
*/
|
||||
#module { name = "m_sasl_dh-aes" }
|
||||
|
||||
/*
|
||||
* m_sasl_dh-blowfish [EXTRA]
|
||||
*
|
||||
* Add the DH-BLOWFISH mechanism to SASL.
|
||||
* Requires m_sasl to be loaded.
|
||||
* Requires openssl.
|
||||
*/
|
||||
#module { name = "m_sasl_dh-blowfish" }
|
||||
|
||||
/*
|
||||
* m_ssl_gnutls [EXTRA]
|
||||
*
|
||||
* This module provides SSL services to Anope using GnuTLS, for example to
|
||||
* connect to the uplink server(s) via SSL.
|
||||
*
|
||||
* You may only load either m_ssl_gnutls or m_ssl_openssl, bot not both.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "m_ssl_gnutls"
|
||||
|
||||
/*
|
||||
* An optional certificate and key for m_gnutls to give to the uplink.
|
||||
*
|
||||
* You can generate your own certificate and key pair by using:
|
||||
*
|
||||
* certtool --generate-privkey --bits 2048 --outfile anope.key
|
||||
* certtool --generate-self-signed --load-privkey anope.key --outfile anope.crt
|
||||
*
|
||||
*/
|
||||
cert = "data/anope.crt"
|
||||
key = "data/anope.key"
|
||||
|
||||
/*
|
||||
* Diffie-Hellman parameters to use when acting as a server. This is only
|
||||
* required for TLS servers that want to use ephemeral DH cipher suites.
|
||||
*
|
||||
* This is NOT required for Anope to connect to the uplink server(s) via SSL.
|
||||
*
|
||||
* You can generate DH parameters by using:
|
||||
*
|
||||
* certtool --generate-dh-params --bits 2048 --outfile dhparams.pem
|
||||
*
|
||||
*/
|
||||
# dhparams = "data/dhparams.pem"
|
||||
}
|
||||
|
||||
/*
|
||||
* m_ssl_openssl [EXTRA]
|
||||
*
|
||||
* This module provides SSL services to Anope using OpenSSL, for example to
|
||||
* connect to the uplink server(s) via SSL.
|
||||
*
|
||||
* You may only load either m_ssl_openssl or m_ssl_gnutls, bot not both.
|
||||
*
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "m_ssl_openssl"
|
||||
|
||||
/*
|
||||
* An optional certificate and key for m_openssl to give to the uplink.
|
||||
*
|
||||
* You can generate your own certificate and key pair by using:
|
||||
*
|
||||
* openssl genrsa -out anope.key 2048
|
||||
* openssl req -new -x509 -key anope.key -out anope.crt -days 1095
|
||||
*/
|
||||
cert = "data/anope.crt"
|
||||
key = "data/anope.key"
|
||||
}
|
||||
|
||||
/*
|
||||
* m_sql_authentication [EXTRA]
|
||||
*
|
||||
@@ -541,101 +708,26 @@ module { name = "help" }
|
||||
}
|
||||
|
||||
/*
|
||||
* m_redis
|
||||
* webcpanel
|
||||
*
|
||||
* This module allows other modules to use Redis.
|
||||
* This module creates a web configuration panel that allows users and operators to perform any task
|
||||
* as they could over IRC. If you are using the default configuration you should be able to access
|
||||
* this panel by visiting http://127.0.0.1:8080 in your web browser from the machine Anope is running on.
|
||||
*
|
||||
* This module requires m_httpd.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "m_redis"
|
||||
name = "webcpanel"
|
||||
|
||||
/* A redis database */
|
||||
redis
|
||||
{
|
||||
/* The name of this service */
|
||||
name = "redis/main"
|
||||
/* Web server to use. */
|
||||
server = "httpd/main";
|
||||
|
||||
/*
|
||||
* The redis database to use. New connections default to 0.
|
||||
*/
|
||||
db = 0
|
||||
/* Template to use. */
|
||||
template = "default";
|
||||
|
||||
ip = "127.0.0.1"
|
||||
port = 6379
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* m_regex_pcre [EXTRA]
|
||||
*
|
||||
* Provides the regex engine regex/pcre, which uses the Perl Compatible Regular Expressions library.
|
||||
*/
|
||||
#module { name = "m_regex_pcre" }
|
||||
|
||||
/*
|
||||
* m_regex_posix [EXTRA]
|
||||
*
|
||||
* Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
|
||||
* This is likely the only regex module you will not need extra libraries for.
|
||||
*/
|
||||
#module { name = "m_regex_posix" }
|
||||
|
||||
/*
|
||||
* m_regex_tre [EXTRA]
|
||||
*
|
||||
* Provides the regex engine regex/tre, which uses the TRE regex library.
|
||||
*/
|
||||
#module { name = "m_regex_tre" }
|
||||
|
||||
/*
|
||||
* m_rewrite
|
||||
*
|
||||
* Allows rewriting commands sent to/from clients.
|
||||
*/
|
||||
#module { name = "m_rewrite" }
|
||||
#command
|
||||
{
|
||||
service = "ChanServ"; name = "CLEAR"; command = "rewrite"
|
||||
|
||||
/* Enable m_rewrite. */
|
||||
rewrite = true
|
||||
|
||||
/* Source message to match. A $ can be used to match anything. */
|
||||
rewrite_source = "CLEAR $ USERS"
|
||||
|
||||
/*
|
||||
* Message to rewrite the source message to. A $ followed by a number, eg $0, gets
|
||||
* replaced by the number-th word from the source_message, starting from 0.
|
||||
*/
|
||||
rewrite_target = "KICK $1 *"
|
||||
|
||||
/*
|
||||
* The command description. This only shows up in HELP's output.
|
||||
* Comment this option to prevent the command from showing in the
|
||||
* HELP command.
|
||||
*/
|
||||
rewrite_description = "Clears all users from a channel"
|
||||
}
|
||||
|
||||
/*
|
||||
* m_ssl [EXTRA]
|
||||
*
|
||||
* This module uses SSL to connect to the uplink server(s).
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "m_ssl"
|
||||
|
||||
/*
|
||||
* An optional certificate and key for m_ssl to give to the uplink.
|
||||
*
|
||||
* You can generate your own certificate and key pair by using:
|
||||
*
|
||||
* openssl genrsa -out anope.key 2048
|
||||
* openssl req -new -x509 -key anope.key -out anope.crt -days 1095
|
||||
*/
|
||||
cert = "data/anope.crt"
|
||||
key = "data/anope.key"
|
||||
/* Page title. */
|
||||
title = "Anope IRC Services";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -659,26 +751,3 @@ module { name = "help" }
|
||||
* Requires m_xmlrpc.
|
||||
*/
|
||||
#module { name = "m_xmlrpc_main" }
|
||||
|
||||
/*
|
||||
* webcpanel
|
||||
*
|
||||
* This module creates a web configuration panel that allows users and operators to perform any task
|
||||
* as they could over IRC. If you are using the default configuration you should be able to access
|
||||
* this panel by visiting http://127.0.0.1:8080 in your web browser from the machine Anope is running on.
|
||||
*
|
||||
* This module requires m_httpd.
|
||||
*/
|
||||
#module
|
||||
{
|
||||
name = "webcpanel"
|
||||
|
||||
/* Web server to use. */
|
||||
server = "httpd/main";
|
||||
|
||||
/* Template to use. */
|
||||
template = "default";
|
||||
|
||||
/* Page title. */
|
||||
title = "Anope IRC Services";
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ module
|
||||
* The maximum number of entries allowed on a nickname's certificate fingerprint list.
|
||||
* The default is 5. This number cannot be set to 0.
|
||||
*/
|
||||
accessmax = 5
|
||||
max = 5
|
||||
}
|
||||
command { service = "NickServ"; name = "CERT"; command = "nickserv/cert"; }
|
||||
|
||||
@@ -640,7 +640,7 @@ command { service = "NickServ"; name = "UPDATE"; command = "nickserv/update"; }
|
||||
* Limits how many times the same email address may be used in Anope
|
||||
* to register accounts.
|
||||
*/
|
||||
module
|
||||
#module
|
||||
{
|
||||
name = "ns_maxemail"
|
||||
|
||||
@@ -649,5 +649,5 @@ module
|
||||
* commented, there will be no limit enforced when registering new accounts or using
|
||||
* /msg NickServ SET EMAIL.
|
||||
*/
|
||||
#maxemails = 1
|
||||
maxemails = 1
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ uplink
|
||||
|
||||
/*
|
||||
* Enable if Services should connect using SSL.
|
||||
* You must have m_ssl loaded for this to work.
|
||||
* You must have an SSL module loaded for this to work.
|
||||
*/
|
||||
ssl = no
|
||||
|
||||
|
||||
+156
-2
@@ -1,5 +1,159 @@
|
||||
Revision 1cc85f4 - Tue, 21 Jan 2014 21:18:21 -0500 - Update version.log
|
||||
Revision 68b87b4 - Tue, 21 Jan 2014 21:18:19 -0500 - Update language files
|
||||
Revision cdf636e - Sun, 23 Mar 2014 08:57:08 -0400 - Regen langauge files
|
||||
Revision 45878bf - Sat, 22 Mar 2014 21:14:02 +0100 - SASL: Also disallow suspended nicks to login using EXTERNAL mechanism. Improve the log message for failed logins.
|
||||
Revision f1bec39 - Sat, 22 Mar 2014 07:21:22 -0400 - Do not allow SASL login to suspended nicks
|
||||
Revision a259244 - Thu, 20 Mar 2014 10:53:27 -0400 - Make bouncymodes harder to trigger by only bumping server modcount when something changes
|
||||
Revision c1da009 - Wed, 19 Mar 2014 02:40:48 -0400 - Show a better log message when disconnecting from the uplink
|
||||
Revision 4f412bc - Wed, 19 Mar 2014 03:05:54 +0100 - cs_set_misc: Add missing override capability for services operators, and logging.
|
||||
Revision 1882916 - Mon, 17 Mar 2014 01:15:28 +0100 - Update the dutch language file.
|
||||
Revision f436ce9 - Mon, 17 Mar 2014 00:58:51 +0100 - m_ssl_gnutls: Fix deprecation warnings when using newer GnuTLS versions.
|
||||
Revision ef9729f - Fri, 14 Mar 2014 22:13:04 -0400 - Mark all channels as syncing when we connect to our uplink. They will finish syncing later when the uplink syncs. Normally the channel state is fully synced here anyway, except if we do not know the modes the uplink has yet.
|
||||
Revision 296a75f - Thu, 13 Mar 2014 20:07:50 -0400 - Do not allow users to add certs that other users are using. Only allow adding certfps if the user is using it.
|
||||
Revision bce7237 - Tue, 11 Mar 2014 09:45:34 -0400 - Set LDAP_OPT_NETWORK_TIMEOUT to 0 in m_ldap to prevent the asynchronous library cals from blocking...
|
||||
Revision 85834e1 - Mon, 10 Mar 2014 22:30:41 +0100 - Update the dutch language file. ns_maxemail: Bold code 2 -> 002.
|
||||
Revision ca6b372 - Mon, 10 Mar 2014 07:32:24 -0400 - Merge pull request #64 from ShutterQuick/2.0+hsgroupsync
|
||||
Revision 23b1086 - Mon, 10 Mar 2014 07:31:34 -0400 - Merge pull request #63 from alexbarton/ngircd-fix-KILL
|
||||
Revision 860deb1 - Mon, 10 Mar 2014 07:26:09 -0400 - Do not send unregistered notice to users who are logged in, even if their nick isn't registered
|
||||
Revision 62885fa - Mon, 10 Mar 2014 05:04:25 -0400 - Set nickserv's modesonid on login too
|
||||
Revision 3fef01e - Mon, 10 Mar 2014 04:56:17 -0400 - Fix compile error in m_sasl_dh-aes and m_sasl_dh-blowfish on unusually old g++ versions
|
||||
Revision b0597e3 - Mon, 10 Mar 2014 04:31:08 -0400 - Do not allow nickserv/ungroup to bypass ns_maxemail, and allow opers to bypass ns_maxemail
|
||||
Revision 8d1ad6f - Sun, 9 Mar 2014 22:59:16 -0400 - Make nickserv/glist show the correct expire time for unconfirmed nicks
|
||||
Revision 7505692 - Sun, 9 Mar 2014 22:56:25 -0400 - Add missing space to session exception expiration message
|
||||
Revision 1a1a781 - Sun, 9 Mar 2014 10:07:13 -0400 - Remove mail:restrict as it is no longer useful. Changes nickserv/resetpass default to allow normal users to use it.
|
||||
Revision 4b5ce8a - Sun, 9 Mar 2014 04:55:35 +0100 - irc2sql: removed the currentusers field from the chan table, keeping it updated on each join/part eats too many ressources
|
||||
Revision 98cfdd2 - Thu, 6 Mar 2014 04:55:30 -0800 - ns_group: Don't require a nick param when logged in
|
||||
Revision 051a42b - Thu, 6 Mar 2014 04:55:30 -0800 - hs_group: Allow automatic HS GROUP-ing on NS GROUP, and allow vhosts to be per account rather than nick.
|
||||
Revision 220e278 - Wed, 5 Mar 2014 20:23:44 -0500 - Open database files using std::ios_base::binary in db_flatfile, which Windows can require
|
||||
Revision 547fe0d - Wed, 5 Mar 2014 10:26:54 +0100 - ngircd protocol module: really kill users
|
||||
Revision 09bec79 - Tue, 4 Mar 2014 04:15:32 -0500 - Fix 2 crashes from removing the permanent channel mode from channels which do not exist
|
||||
Revision 55a5aff - Tue, 4 Mar 2014 04:15:32 -0500 - Do not allow guest nicks to exceed nicklen, and use a default enforcer ident/host if none is provided
|
||||
Revision a8b4297 - Mon, 3 Mar 2014 19:20:56 +0100 - Update the dutch language file.
|
||||
Revision 5969362 - Sat, 1 Mar 2014 22:41:45 -0500 - When unserializing channels with persist, set their ts=now. If we are supposed to lower it later we will then.
|
||||
Revision 3ceae33 - Sat, 1 Mar 2014 21:56:26 -0500 - Convert limit and key mlocks in db_old
|
||||
Revision 5de4c1f - Sat, 1 Mar 2014 21:40:47 -0500 - Set +x on plexus when vhosts are activated, fix desync from /hs off
|
||||
Revision fd10904 - Sat, 1 Mar 2014 21:20:32 -0500 - Make db_old load entrymsg
|
||||
Revision a074751 - Sat, 1 Mar 2014 21:20:18 -0500 - Export interface for cs_entrymsg
|
||||
Revision 605e1f2 - Sat, 1 Mar 2014 21:12:27 -0500 - Make chanserv/invite show who invited you
|
||||
Revision dc23c58 - Sat, 1 Mar 2014 21:11:58 -0500 - Fix botserv help to show the correct fantasy characters
|
||||
Revision b7e646e - Sat, 1 Mar 2014 20:02:17 -0500 - Allow opers with chanserv/administration to use fantasy, even if they don't have the access for it
|
||||
Revision 4d54358 - Sat, 1 Mar 2014 19:59:40 -0500 - When unserializating channels and persist is set, only assign chanserv if the perm channel mode doesnt exist
|
||||
Revision ed0882e - Sat, 1 Mar 2014 18:39:10 -0500 - Do not enforce mlock when enforcing mlock
|
||||
Revision 526c4e4 - Sat, 1 Mar 2014 18:38:14 -0500 - Check modes after applying mlocks in db_old
|
||||
Revision b70f72b - Sat, 1 Mar 2014 04:31:52 -0500 - Do not allow changing the email of unconfirmed accounts
|
||||
Revision 2ad4c19 - Sat, 1 Mar 2014 04:27:45 -0500 - Fix incorrect comment in modules.example.conf
|
||||
Revision 049760c - Fri, 28 Feb 2014 00:30:35 -0500 - Allow svsjoin/svspart on yourself
|
||||
Revision e2ecec3 - Thu, 27 Feb 2014 23:21:50 -0500 - Hybrid does not let us add resvs as a server, but the core expects to be able to qline bot nicks before introducing the bots as a way to prevent collisions, so try harder to find a valid bot to send resvs on startup
|
||||
Revision fee016b - Thu, 27 Feb 2014 22:42:54 -0500 - Handle nick collisions somewhat instead of blindly overwriting the nicks in memory, which does weird things.
|
||||
Revision d24fb03 - Thu, 27 Feb 2014 04:49:28 -0500 - Allow registration=mail forceemail=false to work, and simply give fully registered accounts to people who do not provide an email to nickserv/register
|
||||
Revision 5adc8bf - Thu, 27 Feb 2014 04:48:48 -0500 - Do not take modes from users in channels with secureops off if we are always lowering channels timestamps to their creations
|
||||
Revision abcf0cd - Wed, 26 Feb 2014 19:32:25 -0500 - Remove unreachable code in config.cpp, this error is caught earlier
|
||||
Revision 8f3bd31 - Wed, 26 Feb 2014 19:26:50 -0500 - Fix not detecting eols in the config reader when the end of the line is the end of a multiline comment
|
||||
Revision e2d456d - Wed, 26 Feb 2014 19:24:32 -0500 - Do not setuid/gid down until after modules are loaded
|
||||
Revision 96202ae - Mon, 24 Feb 2014 22:23:12 -0500 - Log successful SASL auths
|
||||
Revision 2b0229d - Tue, 25 Feb 2014 03:22:55 +0100 - Update the italian language file
|
||||
Revision beaa319 - Mon, 24 Feb 2014 16:14:40 -0500 - Update Spanish translation, from Isaac Fontal <i_fontal@hotmail.com>
|
||||
Revision b6d771a - Mon, 24 Feb 2014 00:31:07 -0500 - Anope 2.0.0-rc4 Release
|
||||
Revision d3ed756 - Mon, 24 Feb 2014 00:30:57 -0500 - Update version.log (why do we keep this around?)
|
||||
Revision f830884 - Mon, 24 Feb 2014 00:30:47 -0500 - Package dlls in src/win32 on Windows
|
||||
Revision 1dfdf36 - Mon, 24 Feb 2014 00:06:38 -0500 - Fix m_ssl_gnutls to send its cert. Most of this is from Attila.
|
||||
Revision 4ac3ade - Sun, 23 Feb 2014 23:08:35 -0500 - Use a more reliable way to detect if services are running in anoperc
|
||||
Revision 212abeb - Sun, 23 Feb 2014 23:42:43 +0100 - webcpanel: Update copyright year. ns_cert: Bold code 2 -> 002.
|
||||
Revision 7d4427c - Sun, 23 Feb 2014 05:24:06 +0100 - Regenerated language files.
|
||||
Revision e836be4 - Sat, 22 Feb 2014 17:46:00 -0500 - Store a cert->account map and use it for SASL EXTERNAL and certfp auth
|
||||
Revision 1db5c55 - Sat, 22 Feb 2014 13:46:36 -0500 - Merge pull request #58 from attilamolnar/2.0+gnutlsdep
|
||||
Revision bb1b015 - Sat, 22 Feb 2014 16:59:10 +0100 - Make m_ssl_gnutls work with at least GnuTLS v2.8
|
||||
Revision e42684a - Sat, 22 Feb 2014 16:40:56 +0100 - Update italian translation, from Simos.
|
||||
Revision d7de7ee - Sat, 22 Feb 2014 15:58:36 +0100 - Italian language completed translation, first release
|
||||
Revision 0a390ad - Sat, 22 Feb 2014 15:56:34 +0100 - Regenerated language files, and updated dutch language file.
|
||||
Revision aa6b12c - Fri, 21 Feb 2014 21:54:01 -0500 - Fix Windows build
|
||||
Revision e2bd08f - Fri, 21 Feb 2014 20:50:23 -0500 - Add some missing serial updates in os_dns
|
||||
Revision 2047934 - Fri, 21 Feb 2014 19:57:31 -0500 - Regenerate Italian language file
|
||||
Revision e07dcbf - Fri, 21 Feb 2014 19:57:31 -0500 - Update italian translation, from Simos
|
||||
Revision e3a8a45 - Fri, 21 Feb 2014 19:49:29 -0500 - Merge pull request #56 from ShutterQuick/2.0+noxcrypt
|
||||
Revision f1ad7fd - Fri, 21 Feb 2014 20:41:41 +0000 - fix comment, activate not active
|
||||
Revision 43f2645 - Thu, 20 Feb 2014 20:07:38 +0000 - update help info
|
||||
Revision b6935e7 - Thu, 20 Feb 2014 11:42:20 -0800 - enc_bcrypt.cpp: Get rid of the libxcrypt dependency by including code from libxcrypt, and move enc_bcrypt out of extras
|
||||
Revision a3c8458 - Thu, 20 Feb 2014 17:11:11 +0000 - Updated services crontab location
|
||||
Revision 5933a5e - Tue, 18 Feb 2014 22:24:24 +0000 - Merge remote branch 'upstream/2.0' into 2.0
|
||||
Revision 109d8f4 - Tue, 18 Feb 2014 13:04:16 -0500 - Do not import forbids with wildcards in their names, how 1.8 treats wildcaded forbids depends on the IRCd
|
||||
Revision 1edb7e7 - Tue, 18 Feb 2014 12:59:37 -0500 - Merge pull request #54 from attilamolnar/2.0+webcpanelfix
|
||||
Revision 928e2e1 - Tue, 18 Feb 2014 12:57:31 -0500 - Fix loading noexpire channels in db_old
|
||||
Revision 5a140e4 - Tue, 18 Feb 2014 12:54:22 -0500 - Merge pull request #55 from attilamolnar/2.0+alphabet
|
||||
Revision f643939 - Tue, 18 Feb 2014 13:00:46 +0100 - Alphabetically order modules in modules.example.conf ('r' < 's' and 'w' < 'x')
|
||||
Revision 0db81ca - Mon, 17 Feb 2014 22:21:08 -0500 - Merge pull request #52 from attilamolnar/2.0+gnutls
|
||||
Revision 7f7144d - Mon, 17 Feb 2014 22:20:38 -0500 - Merge pull request #53 from attilamolnar/2.0+reuseaddrfix
|
||||
Revision 3883716 - Tue, 18 Feb 2014 03:28:02 +0100 - Turn BinarySocket::Write() into a no-op when called with l == 0
|
||||
Revision 5beea4e - Tue, 18 Feb 2014 03:27:12 +0100 - Fix TemplateFileServer writing empty messages resulting in zero length DataBlocks being created and later passed to SocketIO::Send()
|
||||
Revision 2d0fdb7 - Tue, 18 Feb 2014 02:31:01 +0100 - Fix setsockopt() with SO_REUSEADDR not working due to wrong argument type
|
||||
Revision 80588fb - Mon, 17 Feb 2014 19:43:19 -0500 - Fix os_ignore to work correctly with SQL
|
||||
Revision ef7dc94 - Mon, 17 Feb 2014 19:39:25 -0500 - Move most of the implementation details out of os_forbid.h, fixes crashing if a module adding a forbid is unloaded without removing the forbid
|
||||
Revision 7b4eec9 - Mon, 17 Feb 2014 13:53:45 -0500 - Remove docs/IRCD, it is very outdated and no longer correct at all
|
||||
Revision baff417 - Mon, 17 Feb 2014 13:53:04 -0500 - Move encryption.h to include/modules
|
||||
Revision 7074944 - Mon, 17 Feb 2014 13:39:49 -0500 - Fix not applying ipv[46]_cidr to connecting clients in os_session, #1573
|
||||
Revision 1c39d25 - Mon, 17 Feb 2014 01:12:01 +0100 - Add m_ssl_gnutls
|
||||
Revision f1c5c27 - Sun, 16 Feb 2014 23:49:57 +0000 - Merge branch '2.0', remote branch 'upstream/2.0' into 2.0
|
||||
Revision 9c0134e - Mon, 17 Feb 2014 00:41:36 +0100 - Rename m_ssl to m_ssl_openssl and update docs
|
||||
Revision 959fee5 - Sun, 16 Feb 2014 18:28:39 -0500 - Fix Windows build
|
||||
Revision 3854a55 - Sun, 16 Feb 2014 16:07:36 -0500 - Merge pull request #51 from ShutterQuick/2.0+oldforbid
|
||||
Revision ab1e0eb - Sun, 16 Feb 2014 12:56:27 -0800 - db_old.cpp: Correctly import forbidden nicks and chans
|
||||
Revision cffe864 - Sun, 16 Feb 2014 14:10:25 -0500 - Merge pull request #50 from ShutterQuick/bcrypt
|
||||
Revision bc15753 - Sun, 16 Feb 2014 11:07:37 -0800 - modules.example.conf: Update examples for bcrypt - also clearify that m_sasl_dh* requires openssl
|
||||
Revision a71d0f6 - Sun, 16 Feb 2014 11:07:36 -0800 - enc_bcrypt: Add module
|
||||
Revision 50d7bf7 - Fri, 14 Feb 2014 19:15:43 -0500 - Merge pull request #48 from ShutterQuick/2.0+nnghsasl
|
||||
Revision d44bcef - Fri, 14 Feb 2014 16:06:24 -0800 - modules.example.conf: Add info about m_sasl_dh-aes and m_sasl_dh-blowfish
|
||||
Revision c0ce71e - Fri, 14 Feb 2014 15:12:25 -0800 - m_sasl_dh-blowfish: Add module
|
||||
Revision 0eeb0ca - Fri, 14 Feb 2014 15:12:25 -0800 - m_sasl_dh-aes: Add module
|
||||
Revision b13bded - Fri, 14 Feb 2014 15:03:42 -0800 - sasl.h, m_sasl.cpp: Move IdentifyRequest to the header
|
||||
Revision 1b1180f - Fri, 14 Feb 2014 13:42:21 -0800 - base64.cpp: B64Decode(): Don't crash on "="
|
||||
Revision a4ecfa5 - Fri, 14 Feb 2014 13:05:01 -0800 - Anope::string: Add .data()
|
||||
Revision 3c8009b - Fri, 14 Feb 2014 13:05:01 -0800 - sasl.h, m_sasl.cpp: Add RemoveSession(), DeleteSessions(), and have active sessions closed when a Mechanism is unloaded
|
||||
Revision ca85df2 - Fri, 14 Feb 2014 11:10:20 -0500 - Don't convert XOP access entries to levels in db_old
|
||||
Revision 5dfa659 - Fri, 14 Feb 2014 11:09:53 -0500 - Do not sync channels in Channel::Reset if they are in the middle of syncing, and checkmodes in Channel::Sync. Fixes channel modes sometimes not being set if always_lower_ts is on
|
||||
Revision f428d61 - Thu, 13 Feb 2014 19:42:02 -0500 - Use better command access checking in webpanel for operserv/akill
|
||||
Revision fc50edf - Wed, 12 Feb 2014 14:49:22 -0500 - Disable m_sasl by default
|
||||
Revision 269c278 - Wed, 12 Feb 2014 14:39:41 -0500 - Add SASL EXTERNAL support. Thanks to ShutterQuick for fixing and testing.
|
||||
Revision 96fc940 - Tue, 11 Feb 2014 19:25:44 -0500 - Only trim newlines and carriage returns in BufferedSocket::GetLine
|
||||
Revision 8c8e6d4 - Tue, 11 Feb 2014 18:08:09 -0500 - Make initial registration notices with mail less repetitive
|
||||
Revision 22976b8 - Tue, 11 Feb 2014 17:33:28 -0500 - Fix flags +* or -* sometimes incorrectly reporting opers as overriding when they are not
|
||||
Revision 4dff710 - Tue, 11 Feb 2014 03:57:15 +0100 - ns_suspend: Show the setter of the suspension and the reason when manually unsuspending.
|
||||
Revision fe80d2c - Tue, 11 Feb 2014 02:26:00 +0100 - os_modinfo: Add ability to list only extra modules.
|
||||
Revision 16dac87 - Mon, 10 Feb 2014 10:03:38 -0500 - Regenerate anope.it_IT.po
|
||||
Revision 30c5956 - Mon, 10 Feb 2014 09:57:24 -0500 - Update Italian language translation
|
||||
Revision 6d61a84 - Sun, 9 Feb 2014 18:51:52 -0500 - Add an opertype priv "protected" to not allow services to kick a user. Also classify ulines as protected
|
||||
Revision f6b8596 - Sun, 9 Feb 2014 10:59:36 -0500 - Log memoserv/sendall
|
||||
Revision da6760f - Fri, 7 Feb 2014 13:28:07 -0500 - Properly convert suspended nicks and channels in db_old
|
||||
Revision ad962ad - Fri, 7 Feb 2014 13:12:57 -0500 - Allow other modules to suspend nicknames and channels without having to subclass suspendinfo
|
||||
Revision 5327bec - Fri, 7 Feb 2014 13:02:20 -0500 - Allow other modules to be able to view and modify cs and ns set_misc data
|
||||
Revision f43c99c - Fri, 7 Feb 2014 12:12:52 -0500 - Merge pull request #46 from ShutterQuick/patch-1
|
||||
Revision c0a491c - Fri, 7 Feb 2014 18:04:16 +0100 - Update cs_updown.cpp
|
||||
Revision 66cc965 - Wed, 5 Feb 2014 15:26:03 -0500 - Ignore nonblocking errnors on socket operations
|
||||
Revision 2440514 - Wed, 5 Feb 2014 08:46:56 -0500 - Document a little more accurrately the privilege stuff and document why the access lists behave as they do
|
||||
Revision fad1da8 - Wed, 5 Feb 2014 08:46:56 -0500 - Process mode changes in ns_ajoin before joining users, fixes not being able to ajoin users to +R channels on Unreal
|
||||
Revision bb0e2a9 - Wed, 5 Feb 2014 08:46:51 -0500 - Make it easier to use fantasy without botserv, and document it
|
||||
Revision 4f8c4f8 - Mon, 3 Feb 2014 10:05:13 -0500 - Actually just allow mode clear to take any mode name
|
||||
Revision 2595711 - Mon, 3 Feb 2014 08:41:27 -0500 - Fix typo in mode clear, exempts -> excepts
|
||||
Revision 9a88953 - Sun, 2 Feb 2014 03:21:02 -0500 - Apply the last commit to cs_list
|
||||
Revision 53f8db0 - Sat, 1 Feb 2014 11:42:08 -0800 - Merge pull request #44 from ShutterQuick/2.0+listfix
|
||||
Revision f94cb7f - Sat, 1 Feb 2014 11:24:52 -0800 - ns_list: Fix typo (NS_SUSPENDED -> SUSPENDED)
|
||||
Revision c30fb13 - Sat, 1 Feb 2014 11:12:39 -0800 - Merge pull request #43 from ShutterQuick/2.0+ajoinfix
|
||||
Revision 7926238 - Sat, 1 Feb 2014 10:55:12 -0800 - Improve IsChannelValid()
|
||||
Revision 211a944 - Sat, 1 Feb 2014 10:35:10 -0800 - ns_ajoin: Treat ',' as a separator.
|
||||
Revision cff6161 - Sat, 1 Feb 2014 10:31:17 -0800 - commasepstream: Add a allowempty param
|
||||
Revision 4455d43 - Fri, 31 Jan 2014 02:43:26 -0800 - Merge pull request #42 from ShutterQuick/2.0+saslfix
|
||||
Revision 405b41e - Fri, 31 Jan 2014 01:41:27 -0800 - protocol/(inspircd12/unreal/charybdis): Have SASL login in on the account name instead of nick alias
|
||||
Revision bacb276 - Tue, 28 Jan 2014 14:45:21 -0500 - Use TBURST on hybrid to set topics
|
||||
Revision 4c1f6b4 - Sun, 26 Jan 2014 16:08:23 -0800 - Merge pull request #40 from attilamolnar/2.0+csclonefix
|
||||
Revision 53a78c2 - Sun, 26 Jan 2014 20:06:36 +0100 - Fix cs_clone allowing users to clone a channel to itself
|
||||
Revision e61a283 - Sun, 26 Jan 2014 16:33:28 +0100 - Update language files.
|
||||
Revision c330219 - Sun, 26 Jan 2014 01:18:38 -0500 - Anope 2.0.0-rc3 Release
|
||||
Revision cd18459 - Sun, 26 Jan 2014 01:17:58 -0500 - Only have extras rerun config if it was successfully run before. Config can create the build directory even if cmake isn't found.
|
||||
Revision f28b114 - Sun, 26 Jan 2014 01:15:19 -0500 - Correct error message in gl_global to reference the right module
|
||||
Revision 87230c1 - Sun, 26 Jan 2014 01:14:58 -0500 - Fix extra space in the unknown command error message
|
||||
Revision a29b789 - Sun, 26 Jan 2014 01:14:28 -0500 - Use the SQLine reason in the kick reason for sqlined channels
|
||||
Revision e965bc3 - Sun, 26 Jan 2014 01:03:43 -0500 - Revert "Rename db_old hash plain -> none which is what 1.8 calls it"
|
||||
Revision 01780c9 - Sat, 25 Jan 2014 17:58:20 -0500 - Fix setname handler on unreal
|
||||
Revision 4d3363f - Tue, 21 Jan 2014 21:55:59 -0500 - Anope 2.0.0-rc2 Release
|
||||
Revision 75e27b6 - Tue, 21 Jan 2014 21:55:59 -0500 - Update version.log
|
||||
Revision fbaca3f - Tue, 21 Jan 2014 21:55:56 -0500 - Update language files
|
||||
Revision 81b01bb - Tue, 21 Jan 2014 21:10:06 -0500 - Fix missing colon in stats and top, fix smileys and actions count. Patch by bush.
|
||||
Revision 1027ec6 - Tue, 21 Jan 2014 17:33:57 -0500 - Made the chanstats confs try and look similar to every other configuration file
|
||||
Revision 4d9273e - Tue, 21 Jan 2014 17:20:15 -0500 - Unbreak account stuff from commit ccae59430ab50393f43ccc38a6a6c0c24191b601.
|
||||
|
||||
@@ -2,6 +2,8 @@ Anope Version 2.0.0
|
||||
-------------------
|
||||
options:passlen, enforceruser, enforcerhost, releasetimeout, and guestnickprefix moved to nickserv's module configuration
|
||||
options:hideregisteredcommands added
|
||||
m_ssl renamed to m_ssl_openssl
|
||||
mail:restrict removed
|
||||
|
||||
Anope Version 1.9.9
|
||||
-------------------
|
||||
|
||||
+7
-10
@@ -67,20 +67,17 @@ Note: You should also read the README and FAQ files!
|
||||
cause trouble on your network if passwords are not encrypted, or read
|
||||
the memos of any user.
|
||||
|
||||
If you see errors during this process, please mail us with the *complete*
|
||||
error output, and don't forget to mention your OS, compiler and C++ library
|
||||
versions.
|
||||
|
||||
Now go into the data directory (by default, ~/services/data). Copy the example
|
||||
Now go into the conf directory (by default, ~/services/conf). Copy the example
|
||||
configuration file (example.conf) to services.conf, and open the latter
|
||||
with your favorite text editor. It contains all the configuration
|
||||
directives Anope will use at startup. Read the instructions contained in
|
||||
the file carefully. Using the default values is NOT a good idea, and will
|
||||
most likely not work!
|
||||
|
||||
If you need help, you should subscribe to the Anope mailing list and mail
|
||||
there to get help from other users. See the README file for more
|
||||
information.
|
||||
If you need help, you should visit http://forum.anope.org/ or #anope on
|
||||
irc.anope.org. Provide *complete* error output, along with other relevant
|
||||
information eg. OS, compiler and C++ library versions.
|
||||
See the README file for more information.
|
||||
|
||||
2) Upgrading Anope
|
||||
|
||||
@@ -134,7 +131,7 @@ Note: You should also read the README and FAQ files!
|
||||
still running, and restart it if not.
|
||||
|
||||
First rename the example.chk script that is in Anope path (by default,
|
||||
this is ~/services/data) to services.chk and edit it. You'll need to
|
||||
this is ~/services/conf) to services.chk and edit it. You'll need to
|
||||
modify the CONFIGURATION part of the file. Then ensure that the file is
|
||||
marked as executable by typing chmod +x services.chk, and try to launch the
|
||||
script to see if it works (Anope must not be running when you do this ;))
|
||||
@@ -143,7 +140,7 @@ Note: You should also read the README and FAQ files!
|
||||
This will open the default text editor with the crontab file. Enter the
|
||||
following (with correct path):
|
||||
|
||||
*/5 * * * * /home/ircd/services/data/services.chk >/dev/null 2>&1
|
||||
*/5 * * * * /home/ircd/services/conf/services.chk >/dev/null 2>&1
|
||||
|
||||
The */5 at the beginning means "check every 5 minutes". You may replace
|
||||
the 5 with other another number if you want (but less than 60). Consult
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
How To Add IRCd Support
|
||||
-----------------------
|
||||
|
||||
1) Files to Edit
|
||||
2) The Code
|
||||
3) The IRCDVar struct
|
||||
4) Modes
|
||||
5) Functions / Events
|
||||
6) CAPAB/PROTOCTL
|
||||
7) IRCDProto Class
|
||||
|
||||
1) Files to Edit
|
||||
|
||||
When preparing to add supprt to Anope for your IRCd, you need to edit
|
||||
the following files
|
||||
|
||||
A) Make a copy of the .cpp file of the IRCd that matches the IRCd that
|
||||
you are attempting to add support for best.
|
||||
B) Add your IRCd into the supported IRCds in example.conf
|
||||
|
||||
2) The Code
|
||||
|
||||
Here is where the code of the .cpp file comes in. Be prepared to spend at
|
||||
least an hour, if not longer, going over the code and getting it right;
|
||||
Especially if you are setting up an ircd that is completely different
|
||||
than the one you used as a base. This section covers the majority of the
|
||||
code that is in use.
|
||||
|
||||
The first bit of code you will face is the IRCDVar structure, This is one
|
||||
of two structs which holds your IRCd information; This allows you to quickly
|
||||
setup your specific ircd.
|
||||
|
||||
IRCDVar myIrcd[] = { };
|
||||
|
||||
This struct contains your basic IRCd functions. Your base source file has
|
||||
the list of all available variables; note that you should not swap any
|
||||
around, or you will break stuff. Here is a brief description of the usage
|
||||
of each.
|
||||
|
||||
1) Name: This member tells Anope about the IRCD's name. It may contain
|
||||
text about it's name and version. This is used to identify the
|
||||
build on startup.
|
||||
|
||||
2) Pseudo Client Mode: This is the user mode set by Anope on all BotServ
|
||||
bots. Normally you want this to be a some form of
|
||||
service or bot flag; you can use + for no mode at
|
||||
all.
|
||||
|
||||
3) Max Channelmode Symbols: This is the total number of possible channel
|
||||
modes that can appear before a nick. Do
|
||||
remember to count each possible mode, so +ov
|
||||
is 2.
|
||||
|
||||
4) SVSNICK: Can the ircd use SVSNICK to change some ones nick? Otherwise,
|
||||
KILL is used. Use 1 for yes, 0 for no.
|
||||
|
||||
5) VHOST: Can a user's host be changed on the fly? Enabling this allow
|
||||
HostServ online. Use 1 for yes, 0 for no.
|
||||
|
||||
6) SNLINE: Does the IRCd support realname (geocs) bans? Use 1 for yes,
|
||||
0 for no.
|
||||
|
||||
7) SQLINE: Does the IRCd support nick bans? Use 1 for yes, 0 for no.
|
||||
|
||||
8) SZLINE: Does the IRCd support SZLINES? Use 1 for yes, 0 for no.
|
||||
|
||||
10) Join to Message: Services must join a channel to send any message to
|
||||
that channel (cannot override +n). Use 1 for yes,
|
||||
0 for no.
|
||||
|
||||
11) SQline Channels: The IRCd's supports banning channel names via
|
||||
SQLINES. Use 1 for yes, 0 for no.
|
||||
|
||||
12) Quit On Kill: When we (SVS)KILL a user, does the IRCd send back a
|
||||
QUIT message for that user? Use 1 for yes, 0 for no.
|
||||
|
||||
13) SVSMODE UNBAN: We can use SVSMODE to unban hosts from a channel. Use
|
||||
1 for yes, 0 for no.
|
||||
|
||||
14) Reverse: We can do a reverse check when unbanning. For use with
|
||||
DreamForge based IRCd's. Use 1 for yes, 0 for no.
|
||||
|
||||
15) vIdent: Support for including a user's ident in their vHost. Use
|
||||
1 for yes, 0 for no.
|
||||
|
||||
16) SVSHOLD: Support for temporarily 'holding' a nick, instead of using
|
||||
a nick enforcer client. Use 1 for yes, 0 for no.
|
||||
|
||||
17) TS on MODE: We need to send a timestamp when modes are being changed.
|
||||
Use 1 for yes, 0 for no.
|
||||
|
||||
18) Umode: We can use OperServ to change a user's mode. Use 1 for yes,
|
||||
0 for no.
|
||||
|
||||
19) OMODE: We can use OperServ to give some user a temporary O:LINE.
|
||||
Use 1 for yes, 0 for no.
|
||||
|
||||
20) No Knock Requires +i: Does the No Knock channel mode require invite
|
||||
only channels? Use 1 for yes, 0 for no.
|
||||
|
||||
21) SVSMODE UCMODE: Can we clear user channel modes with SVSMODE? Use
|
||||
1 for yes, 0 for no.
|
||||
|
||||
22) SGline Enforce: Does the IRCd enforce SNLINES for us or do we need to
|
||||
do so? Use 1 for yes, 0 for no.
|
||||
|
||||
23) TS6: Does the IRCd support TS6? Use 1 for yes, 0 for no.
|
||||
|
||||
24) Global TLD Prefix: Prefix used to send global messages, should probably
|
||||
be "$"
|
||||
|
||||
25) Max Modes: The max number of mode changes we can send in one line
|
||||
|
||||
3) Modes
|
||||
|
||||
Anope is told about modes in the protocol module.
|
||||
For the most part, the syntax for adding channel and user modes are:
|
||||
|
||||
ModeManager::AddUserMode(new UserMode(UMODE_NETADMIN, "UMODE_NETADMIN", 'N'));
|
||||
Where 'N' is the char for the mode, and UMODE_NETADMIN shows what the
|
||||
mode does. Or:
|
||||
|
||||
ModeManager::AddChannelMode(new ChannelMode(CMODE_BLOCKCOLOR, "CMODE_BLOCKCOLOR", 'c'));
|
||||
Where 'c' is the char for the mode and CMODE_BLOCKCOLOR shows what
|
||||
the mode does
|
||||
|
||||
A full list of valid mode names for the second param can be found
|
||||
in services.h in the enum for ChannelModeName and UserModeName
|
||||
If necessary, you can add additional modes to this list.
|
||||
|
||||
Adding simple modes with parameters is similar, instead adding a
|
||||
'new ChannelMode', use 'new ChannelModeParam', set the third optional
|
||||
arg of ChannelModeParam to false if the param should NOT be sent when unsetting
|
||||
it. Eg:
|
||||
|
||||
ModeManager::AddChannelMode(new ChannelModeParam(CMODE_JOINFLOOD, "CMODE_JOINFLOOD", 'j', true));
|
||||
|
||||
Anope will internally track the params, and they can be retrieved through
|
||||
Channel::GetParam();
|
||||
|
||||
If you want to make param validity checking for a mode, you must create a new
|
||||
class which inherits from ChannelModeParam and overload the IsValid function.
|
||||
Modes CMODE_OPERONLY, CMODE_ADMINONLY, and CMODE_REGISTERED already exist
|
||||
internally as classes, to overload the CanSet function to disable non opers
|
||||
from mlocking (or in CMODE_REGISTERED's case, anyone) from setting them.
|
||||
This should be added like:
|
||||
|
||||
ModeManager::AddChannelMode(new ChannelModeOper('O'));
|
||||
|
||||
4) Functions and Events
|
||||
|
||||
A brief word about functions and events. All events are captured by creating a Message struct
|
||||
with the name of the message and the callback function:
|
||||
|
||||
Message my_message("MESSAGE", do_my_messsage);
|
||||
|
||||
Each message should have a message handler if its important enough to be
|
||||
processed by services. All event functions should be formed like this:
|
||||
|
||||
bool do_my_message(const Anope::string &source, const std::vector<Anope::string> ¶ms)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
They will receive the source; this can be empty at times depending on the
|
||||
event. Next, params holds the arguments for the event. Events are likely to
|
||||
pass to various upper level event handlers; see the previous ircd source for
|
||||
how they handle these events.
|
||||
|
||||
5) CAPAB/PROTOCTL
|
||||
|
||||
Most IRCDs send a CAPAB or PROTOCTL line so that they can work out what
|
||||
the other end of the connection is capable of doing. The protocol module should
|
||||
handle all of these without the cores knowledge with the exception of the following:
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
Define | Description
|
||||
----------------|---------------------------------------------------------
|
||||
CAPAB_NOQUIT | NOQUIT protocol support
|
||||
CAPAB_TSMODE | Chanmodes are timestamped
|
||||
CAPAB_UNCONNECT | UNCONNECT protocol support
|
||||
CAPAB_QS | Quitstorm - same as NOQUIT
|
||||
|
||||
You can override the default OnCapab method in IRCdMessage if required.
|
||||
|
||||
6) IRCDProto Class
|
||||
|
||||
The IRCDProto class is set up like:
|
||||
|
||||
class MyIRCdProto : public IRCDProto { } ircdproto;
|
||||
|
||||
And told to Anope through the
|
||||
|
||||
pmodule_ircd_proto(&ircd_proto);
|
||||
|
||||
function.
|
||||
|
||||
This is used for sending out specific messages from Anope to your IRCd.
|
||||
A list of all of the valid function names to overload and their args
|
||||
are in services.h. If the protocol module you are editing is similar enough
|
||||
to the IRCd you are adding support for, many of these probably won't need to
|
||||
be changed.
|
||||
+4
-3
@@ -71,9 +71,10 @@ Anope for Windows
|
||||
our IRC Support channel for assistance.
|
||||
|
||||
Some Anope modules require third party libraries, such as m_mysql and
|
||||
m_ssl. If these libraries are installed in nonstandard locations, cmake
|
||||
will probably not find them and should be told where they are by passing
|
||||
additional search paths to the last question in Config, such as:
|
||||
the SSL modules. If these libraries are installed in nonstandard
|
||||
locations, cmake will probably not find them and should be told where
|
||||
they are by passing additional search paths to the last question in
|
||||
Config, such as:
|
||||
|
||||
-DEXTRA_INCLUDE:STRING=c:/openssl/include;c:/mysql/include
|
||||
-DEXTRA_LIBS:STRING=c:/openssl/lib;c:/mysql/lib
|
||||
|
||||
@@ -147,7 +147,7 @@ while (1)
|
||||
chop($input); # remove the trailing \n from the user input
|
||||
|
||||
if ($input eq "q") {
|
||||
if (-e "build") {
|
||||
if (-e "build/CMakeFiles") {
|
||||
if (-e "cmake-bin") {
|
||||
my $cmake_path = `find cmake-bin -name cmake -print0`;
|
||||
system($cmake_path, "build/.");
|
||||
|
||||
+9
-8
@@ -115,6 +115,7 @@ namespace Anope
|
||||
* The following functions return the various types of strings.
|
||||
*/
|
||||
inline const char *c_str() const { return this->_string.c_str(); }
|
||||
inline const char *data() const { return this->_string.data(); }
|
||||
inline std::string &str() { return this->_string; }
|
||||
inline const std::string &str() const { return this->_string; }
|
||||
inline ci::string ci_str() const { return ci::string(this->_string.c_str()); }
|
||||
@@ -159,24 +160,24 @@ namespace Anope
|
||||
* Trim leading and trailing white spaces from the string.
|
||||
*/
|
||||
|
||||
inline string& ltrim()
|
||||
inline string& ltrim(const Anope::string &what = " \t\r\n")
|
||||
{
|
||||
while (!this->_string.empty() && isspace(this->_string[0]))
|
||||
while (!this->_string.empty() && what.find(this->_string[0]) != Anope::string::npos)
|
||||
this->_string.erase(this->_string.begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline string& rtrim()
|
||||
inline string& rtrim(const Anope::string &what = " \t\r\n")
|
||||
{
|
||||
while (!this->_string.empty() && isspace(this->_string[this->_string.length() - 1]))
|
||||
while (!this->_string.empty() && what.find(this->_string[this->_string.length() - 1]) != Anope::string::npos)
|
||||
this->_string.erase(this->_string.length() - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline string& trim()
|
||||
inline string& trim(const Anope::string &what = " \t\r\n")
|
||||
{
|
||||
this->ltrim();
|
||||
this->rtrim();
|
||||
this->ltrim(what);
|
||||
this->rtrim(what);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -621,7 +622,7 @@ class commasepstream : public sepstream
|
||||
public:
|
||||
/** Initialize with comma seperator
|
||||
*/
|
||||
commasepstream(const Anope::string &source) : sepstream(source, ',') { }
|
||||
commasepstream(const Anope::string &source, bool allowempty = false) : sepstream(source, ',', allowempty) { }
|
||||
};
|
||||
|
||||
/** A derived form of sepstream, which seperates on spaces
|
||||
|
||||
@@ -60,6 +60,8 @@ class CoreExport BotInfo : public User, public Serializable
|
||||
|
||||
void GenerateUID();
|
||||
|
||||
void OnKill();
|
||||
|
||||
/** Change the nickname for the bot.
|
||||
* @param newnick The nick to change to
|
||||
*/
|
||||
|
||||
@@ -52,4 +52,5 @@ struct Exception;
|
||||
struct MemoInfo;
|
||||
struct ModeLock;
|
||||
struct Oper;
|
||||
namespace SASL { struct Message; }
|
||||
|
||||
|
||||
+1
-1
@@ -1010,7 +1010,7 @@ class CoreExport Module : public Extensible
|
||||
* mostly to ensure mlock/+r are set.
|
||||
* @param c The channel
|
||||
*/
|
||||
virtual void OnCheckModes(Channel *c) { throw NotImplementedException(); }
|
||||
virtual void OnCheckModes(Reference<Channel> &c) { throw NotImplementedException(); }
|
||||
|
||||
/** Called when a channel is synced.
|
||||
* Channels are synced after a sjoin is finished processing
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* (C) 2003-2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*
|
||||
*/
|
||||
|
||||
struct EntryMsg
|
||||
{
|
||||
Anope::string chan;
|
||||
Anope::string creator;
|
||||
Anope::string message;
|
||||
time_t when;
|
||||
|
||||
virtual ~EntryMsg() { }
|
||||
protected:
|
||||
EntryMsg() { }
|
||||
};
|
||||
|
||||
struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> >
|
||||
{
|
||||
protected:
|
||||
EntryMessageList() : Serialize::Checker<std::vector<EntryMsg *> >("EntryMsg") { }
|
||||
|
||||
public:
|
||||
virtual ~EntryMessageList()
|
||||
{
|
||||
for (unsigned i = (*this)->size(); i > 0; --i)
|
||||
delete (*this)->at(i - 1);
|
||||
}
|
||||
|
||||
virtual EntryMsg* Create() = 0;
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/* ChanServ core functions
|
||||
*
|
||||
* (C) 2003-2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*
|
||||
* Based on the original code of Epona by Lara.
|
||||
* Based on the original code of Services by Andy Church.
|
||||
*/
|
||||
|
||||
struct CSSuspendInfo
|
||||
{
|
||||
Anope::string chan, by, reason;
|
||||
time_t time, expires;
|
||||
|
||||
virtual ~CSSuspendInfo() { }
|
||||
protected:
|
||||
CSSuspendInfo() { }
|
||||
};
|
||||
@@ -60,3 +60,12 @@ struct NSCertList
|
||||
|
||||
virtual void Check() = 0;
|
||||
};
|
||||
|
||||
class CertService : public Service
|
||||
{
|
||||
public:
|
||||
CertService(Module *c) : Service(c, "CertService", "certs") { }
|
||||
|
||||
virtual NickCore* FindAccountFromCert(const Anope::string &cert) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ enum ForbidType
|
||||
FT_SIZE
|
||||
};
|
||||
|
||||
struct ForbidData : Serializable
|
||||
struct ForbidData
|
||||
{
|
||||
Anope::string mask;
|
||||
Anope::string creator;
|
||||
@@ -19,9 +19,9 @@ struct ForbidData : Serializable
|
||||
time_t expires;
|
||||
ForbidType type;
|
||||
|
||||
ForbidData() : Serializable("ForbidData") { }
|
||||
void Serialize(Serialize::Data &data) const anope_override;
|
||||
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
|
||||
virtual ~ForbidData() { }
|
||||
protected:
|
||||
ForbidData() : created(0), expires(0) { }
|
||||
};
|
||||
|
||||
class ForbidService : public Service
|
||||
@@ -33,6 +33,8 @@ class ForbidService : public Service
|
||||
|
||||
virtual void RemoveForbid(ForbidData *d) = 0;
|
||||
|
||||
virtual ForbidData* CreateForbid() = 0;
|
||||
|
||||
virtual ForbidData *FindForbid(const Anope::string &mask, ForbidType type) = 0;
|
||||
|
||||
virtual std::vector<ForbidData *> GetForbids() = 0;
|
||||
@@ -40,43 +42,5 @@ class ForbidService : public Service
|
||||
|
||||
static ServiceReference<ForbidService> forbid_service("ForbidService", "forbid");
|
||||
|
||||
void ForbidData::Serialize(Serialize::Data &data) const
|
||||
{
|
||||
data["mask"] << this->mask;
|
||||
data["creator"] << this->creator;
|
||||
data["reason"] << this->reason;
|
||||
data["created"] << this->created;
|
||||
data["expires"] << this->expires;
|
||||
data["type"] << this->type;
|
||||
}
|
||||
|
||||
Serializable* ForbidData::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
{
|
||||
if (!forbid_service)
|
||||
return NULL;
|
||||
|
||||
ForbidData *fb;
|
||||
if (obj)
|
||||
fb = anope_dynamic_static_cast<ForbidData *>(obj);
|
||||
else
|
||||
fb = new ForbidData;
|
||||
|
||||
data["mask"] >> fb->mask;
|
||||
data["creator"] >> fb->creator;
|
||||
data["reason"] >> fb->reason;
|
||||
data["created"] >> fb->created;
|
||||
data["expires"] >> fb->expires;
|
||||
unsigned int t;
|
||||
data["type"] >> t;
|
||||
fb->type = static_cast<ForbidType>(t);
|
||||
|
||||
if (t > FT_SIZE - 1)
|
||||
return NULL;
|
||||
|
||||
if (!obj)
|
||||
forbid_service->AddForbid(fb);
|
||||
return fb;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+10
-44
@@ -10,70 +10,36 @@
|
||||
*/
|
||||
|
||||
|
||||
struct IgnoreData : Serializable
|
||||
struct IgnoreData
|
||||
{
|
||||
Anope::string mask;
|
||||
Anope::string creator;
|
||||
Anope::string reason;
|
||||
time_t time; /* When do we stop ignoring them? */
|
||||
|
||||
IgnoreData() : Serializable("IgnoreData") { }
|
||||
void Serialize(Serialize::Data &data) const anope_override;
|
||||
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
|
||||
virtual ~IgnoreData() { }
|
||||
protected:
|
||||
IgnoreData() : time(0) { }
|
||||
};
|
||||
|
||||
class IgnoreService : public Service
|
||||
{
|
||||
protected:
|
||||
std::list<IgnoreData> ignores;
|
||||
|
||||
IgnoreService(Module *c) : Service(c, "IgnoreService", "ignore") { }
|
||||
|
||||
public:
|
||||
virtual IgnoreData* AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) = 0;
|
||||
virtual void AddIgnore(IgnoreData *) = 0;
|
||||
|
||||
virtual bool DelIgnore(const Anope::string &mask) = 0;
|
||||
virtual void DelIgnore(IgnoreData *) = 0;
|
||||
|
||||
inline void ClearIgnores() { this->ignores.clear(); }
|
||||
virtual void ClearIgnores() = 0;
|
||||
|
||||
virtual IgnoreData *Create() = 0;
|
||||
|
||||
virtual IgnoreData *Find(const Anope::string &mask) = 0;
|
||||
|
||||
inline std::list<IgnoreData> &GetIgnores() { return this->ignores; }
|
||||
virtual std::vector<IgnoreData *> &GetIgnores() = 0;
|
||||
};
|
||||
|
||||
static ServiceReference<IgnoreService> ignore_service("IgnoreService", "ignore");
|
||||
|
||||
void IgnoreData::Serialize(Serialize::Data &data) const
|
||||
{
|
||||
data["mask"] << this->mask;
|
||||
data["creator"] << this->creator;
|
||||
data["reason"] << this->reason;
|
||||
data["time"] << this->time;
|
||||
}
|
||||
|
||||
Serializable* IgnoreData::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
{
|
||||
if (!ignore_service)
|
||||
return NULL;
|
||||
|
||||
if (obj)
|
||||
{
|
||||
IgnoreData *ign = anope_dynamic_static_cast<IgnoreData *>(obj);
|
||||
data["mask"] >> ign->mask;
|
||||
data["creator"] >> ign->creator;
|
||||
data["reason"] >> ign->reason;
|
||||
data["time"] >> ign->time;
|
||||
return ign;
|
||||
}
|
||||
|
||||
Anope::string smask, screator, sreason;
|
||||
time_t t;
|
||||
|
||||
data["mask"] >> smask;
|
||||
data["creator"] >> screator;
|
||||
data["reason"] >> sreason;
|
||||
data["time"] >> t;
|
||||
|
||||
return ignore_service->AddIgnore(smask, screator, sreason, t);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
namespace SASL
|
||||
{
|
||||
struct Message
|
||||
{
|
||||
Anope::string source;
|
||||
Anope::string target;
|
||||
Anope::string type;
|
||||
Anope::string data;
|
||||
Anope::string ext;
|
||||
};
|
||||
|
||||
class Mechanism;
|
||||
struct Session;
|
||||
|
||||
class Service : public ::Service
|
||||
{
|
||||
public:
|
||||
Service(Module *o) : ::Service(o, "SASL::Service", "sasl") { }
|
||||
|
||||
virtual void ProcessMessage(const Message &) = 0;
|
||||
|
||||
virtual Anope::string GetAgent() = 0;
|
||||
|
||||
virtual Session* GetSession(const Anope::string &uid) = 0;
|
||||
|
||||
virtual void SendMessage(SASL::Session *session, const Anope::string &type, const Anope::string &data) = 0;
|
||||
|
||||
virtual void Succeed(Session *, NickCore *) = 0;
|
||||
virtual void Fail(Session *) = 0;
|
||||
virtual void SendMechs(Session *) = 0;
|
||||
virtual void DeleteSessions(Mechanism *, bool = false) = 0;
|
||||
virtual void RemoveSession(Session *) = 0;
|
||||
};
|
||||
|
||||
static ServiceReference<SASL::Service> sasl("SASL::Service", "sasl");
|
||||
|
||||
struct Session
|
||||
{
|
||||
time_t created;
|
||||
Anope::string uid;
|
||||
Reference<Mechanism> mech;
|
||||
|
||||
Session(Mechanism *m, const Anope::string &u) : created(Anope::CurTime), uid(u), mech(m) { }
|
||||
virtual ~Session()
|
||||
{
|
||||
if (sasl)
|
||||
sasl->RemoveSession(this);
|
||||
}
|
||||
};
|
||||
|
||||
/* PLAIN, EXTERNAL, etc */
|
||||
class Mechanism : public ::Service
|
||||
{
|
||||
public:
|
||||
Mechanism(Module *o, const Anope::string &sname) : Service(o, "SASL::Mechanism", sname) { }
|
||||
|
||||
virtual Session* CreateSession(const Anope::string &uid) { return new Session(this, uid); }
|
||||
|
||||
virtual void ProcessMessage(Session *session, const Message &) = 0;
|
||||
|
||||
virtual ~Mechanism()
|
||||
{
|
||||
if (sasl)
|
||||
sasl->DeleteSessions(this, true);
|
||||
}
|
||||
};
|
||||
|
||||
class IdentifyRequest : public ::IdentifyRequest
|
||||
{
|
||||
Anope::string uid;
|
||||
|
||||
public:
|
||||
IdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : ::IdentifyRequest(m, acc, pass), uid(id) { }
|
||||
|
||||
void OnSuccess() anope_override
|
||||
{
|
||||
if (!sasl)
|
||||
return;
|
||||
|
||||
NickAlias *na = NickAlias::Find(GetAccount());
|
||||
if (!na || na->nc->HasExt("NS_SUSPENDED"))
|
||||
return OnFail();
|
||||
|
||||
Session *s = sasl->GetSession(uid);
|
||||
if (s)
|
||||
{
|
||||
Log(Config->GetClient("NickServ")) << "A user identified to account " << this->GetAccount() << " using SASL";
|
||||
sasl->Succeed(s, na->nc);
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
|
||||
void OnFail() anope_override
|
||||
{
|
||||
if (!sasl)
|
||||
return;
|
||||
|
||||
Session *s = sasl->GetSession(uid);
|
||||
if (s)
|
||||
{
|
||||
sasl->Fail(s);
|
||||
delete s;
|
||||
}
|
||||
|
||||
Anope::string accountstatus;
|
||||
NickAlias *na = NickAlias::Find(GetAccount());
|
||||
if (!na)
|
||||
accountstatus = "nonexistent ";
|
||||
else if (na->nc->HasExt("NS_SUSPENDED"))
|
||||
accountstatus = "suspended ";
|
||||
|
||||
Log(Config->GetClient("NickServ")) << "A user failed to identify for " << accountstatus << "account " << this->GetAccount() << " using SASL";
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* (C) 2003-2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
struct MiscData
|
||||
{
|
||||
Anope::string object;
|
||||
Anope::string name;
|
||||
Anope::string data;
|
||||
|
||||
MiscData() { }
|
||||
virtual ~MiscData() { }
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* NickServ core functions
|
||||
*
|
||||
/*
|
||||
* (C) 2003-2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
@@ -9,12 +8,11 @@
|
||||
* Based on the original code of Services by Andy Church.
|
||||
*/
|
||||
|
||||
struct NSSuspendInfo
|
||||
struct SuspendInfo
|
||||
{
|
||||
Anope::string nick, by, reason;
|
||||
Anope::string what, by, reason;
|
||||
time_t when, expires;
|
||||
|
||||
virtual ~NSSuspendInfo() { }
|
||||
protected:
|
||||
NSSuspendInfo() { }
|
||||
SuspendInfo() { }
|
||||
virtual ~SuspendInfo() { }
|
||||
};
|
||||
@@ -111,6 +111,8 @@ class CoreExport IRCDProto : public Service
|
||||
virtual void SendSQLine(User *, const XLine *x) { }
|
||||
virtual void SendSQLineDel(const XLine *x) { }
|
||||
|
||||
virtual void SendKill(const MessageSource &source, const Anope::string &target, const Anope::string &reason);
|
||||
|
||||
/** Kills a user
|
||||
* @param source Who is doing the kill
|
||||
* @param user The user to be killed
|
||||
@@ -217,6 +219,9 @@ class CoreExport IRCDProto : public Service
|
||||
*/
|
||||
virtual void SendOper(User *u);
|
||||
|
||||
virtual void SendSASLMessage(const SASL::Message &) { }
|
||||
virtual void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) { }
|
||||
|
||||
virtual bool IsNickValid(const Anope::string &);
|
||||
virtual bool IsChannelValid(const Anope::string &);
|
||||
virtual bool IsIdentValid(const Anope::string &);
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
/** Anything that inherits from this class can be referred to
|
||||
* using ServiceReference. Any interfaces provided by modules,
|
||||
* such as commands, use this. This is also used for modules
|
||||
* that publish a service (m_ssl, etc).
|
||||
* that publish a service (m_ssl_openssl, etc).
|
||||
*/
|
||||
class CoreExport Service : public virtual Base
|
||||
{
|
||||
@@ -148,7 +148,7 @@ class ServiceReference : public Reference<T>
|
||||
* creates its own service type (that other modules must include the header file
|
||||
* for), as the core is not compiled with it so there is no RTTI for it.
|
||||
*/
|
||||
this->ref = static_cast<T *>(Service::FindService(this->type, this->name));
|
||||
this->ref = static_cast<T *>(::Service::FindService(this->type, this->name));
|
||||
if (this->ref)
|
||||
this->ref->AddReference(this);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ class CoreExport SocketEngine
|
||||
/** Read from sockets and do things
|
||||
*/
|
||||
static void Process();
|
||||
|
||||
static int GetLastError();
|
||||
static void SetLastError(int);
|
||||
|
||||
static bool IgnoreErrno();
|
||||
};
|
||||
|
||||
#endif // SOCKETENGINE_H
|
||||
|
||||
+1
-1
@@ -347,7 +347,7 @@ class CoreExport BinarySocket : public virtual Socket
|
||||
|
||||
/** Write data to the socket
|
||||
* @param buffer The data to write
|
||||
* @param l The length of the data
|
||||
* @param l The length of the data; if 0 then this function returns without doing anything
|
||||
*/
|
||||
virtual void Write(const char *buffer, size_t l);
|
||||
void Write(const char *message, ...);
|
||||
|
||||
+6
-4
@@ -92,6 +92,7 @@ class CoreExport User : public virtual Base, public Extensible, public CommandRe
|
||||
/* Last time this user sent an email */
|
||||
time_t lastmail;
|
||||
|
||||
protected:
|
||||
/** Create a new user object, initialising necessary fields and
|
||||
* adds it to the hash
|
||||
*
|
||||
@@ -102,19 +103,20 @@ class CoreExport User : public virtual Base, public Extensible, public CommandRe
|
||||
* @param sip The ip of the user
|
||||
* @param sserver The server of the user
|
||||
* @param srealname The realname/gecos of teh user
|
||||
* @param ssignon User's timestamp
|
||||
* @param ts User's timestamp
|
||||
* @param smodes User's modes
|
||||
* @param suid The unique identifier of the user.
|
||||
* @param nc The account the user is identified as, if any
|
||||
*/
|
||||
User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ssignon, const Anope::string &smodes, const Anope::string &suid, NickCore *nc);
|
||||
User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc);
|
||||
|
||||
protected:
|
||||
/** Destroy a user.
|
||||
*/
|
||||
virtual ~User();
|
||||
|
||||
public:
|
||||
static User* OnIntroduce(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc);
|
||||
|
||||
/** Update the nickname of a user record accordingly, should be
|
||||
* called from ircd protocol.
|
||||
* @param newnick The new username
|
||||
@@ -323,7 +325,7 @@ class CoreExport User : public virtual Base, public Extensible, public CommandRe
|
||||
/** Check if the user is protected from kicks and negative mode changes
|
||||
* @return true or false
|
||||
*/
|
||||
bool IsProtected() const;
|
||||
bool IsProtected();
|
||||
|
||||
/** Kill a user
|
||||
* @param source The user/server doing the kill
|
||||
|
||||
+406
-404
File diff suppressed because it is too large
Load Diff
+409
-404
File diff suppressed because it is too large
Load Diff
+410
-414
File diff suppressed because it is too large
Load Diff
+697
-775
File diff suppressed because it is too large
Load Diff
+418
-411
File diff suppressed because it is too large
Load Diff
+404
-402
File diff suppressed because it is too large
Load Diff
+3009
-3659
File diff suppressed because it is too large
Load Diff
+420
-419
File diff suppressed because it is too large
Load Diff
+404
-402
File diff suppressed because it is too large
Load Diff
+404
-402
File diff suppressed because it is too large
Load Diff
+411
-408
File diff suppressed because it is too large
Load Diff
+404
-402
File diff suppressed because it is too large
Load Diff
@@ -1038,8 +1038,8 @@ class BSKick : public Module
|
||||
|
||||
void check_ban(ChannelInfo *ci, User *u, KickerData *kd, int ttbtype)
|
||||
{
|
||||
/* Don't ban ulines */
|
||||
if (u->server->IsULined())
|
||||
/* Don't ban ulines or protected users */
|
||||
if (u->IsProtected())
|
||||
return;
|
||||
|
||||
BanData::Data &bd = this->GetBanData(u, ci->c);
|
||||
@@ -1065,7 +1065,7 @@ class BSKick : public Module
|
||||
va_list args;
|
||||
char buf[1024];
|
||||
|
||||
if (!ci || !ci->bi || !ci->c || !u || u->server->IsULined() || !ci->c->FindUser(u))
|
||||
if (!ci || !ci->bi || !ci->c || !u || u->IsProtected() || !ci->c->FindUser(u))
|
||||
return;
|
||||
|
||||
Anope::string fmt = Language::Translate(u, message);
|
||||
|
||||
@@ -49,6 +49,13 @@ public:
|
||||
source.Reply(CHAN_X_NOT_REGISTERED, target.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (ci == target_ci)
|
||||
{
|
||||
source.Reply(_("Cannot clone channel \002%s\002 to itself!"), target.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!source.IsFounder(ci) || !source.IsFounder(target_ci))
|
||||
{
|
||||
if (!source.HasPriv("chanserv/administration"))
|
||||
|
||||
@@ -10,27 +10,27 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/cs_entrymsg.h"
|
||||
|
||||
struct EntryMsg : Serializable
|
||||
struct EntryMsgImpl : EntryMsg, Serializable
|
||||
{
|
||||
Serialize::Reference<ChannelInfo> ci;
|
||||
Anope::string creator;
|
||||
Anope::string message;
|
||||
time_t when;
|
||||
|
||||
EntryMsg(ChannelInfo *c, const Anope::string &cname, const Anope::string &cmessage, time_t ct = Anope::CurTime) : Serializable("EntryMsg")
|
||||
EntryMsgImpl() : Serializable("EntryMsg")
|
||||
{
|
||||
this->ci = c;
|
||||
}
|
||||
|
||||
EntryMsgImpl(ChannelInfo *c, const Anope::string &cname, const Anope::string &cmessage, time_t ct = Anope::CurTime) : Serializable("EntryMsg")
|
||||
{
|
||||
this->chan = c->name;
|
||||
this->creator = cname;
|
||||
this->message = cmessage;
|
||||
this->when = ct;
|
||||
}
|
||||
|
||||
~EntryMsg();
|
||||
~EntryMsgImpl();
|
||||
|
||||
void Serialize(Serialize::Data &data) const anope_override
|
||||
{
|
||||
data["ci"] << this->ci->name;
|
||||
data["ci"] << this->chan;
|
||||
data["creator"] << this->creator;
|
||||
data["message"] << this->message;
|
||||
data.SetType("when", Serialize::Data::DT_INT); data["when"] << this->when;
|
||||
@@ -39,30 +39,33 @@ struct EntryMsg : Serializable
|
||||
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
|
||||
};
|
||||
|
||||
struct EntryMessageList : Serialize::Checker<std::vector<EntryMsg *> >
|
||||
struct EntryMessageListImpl : EntryMessageList
|
||||
{
|
||||
EntryMessageList(Extensible *) : Serialize::Checker<std::vector<EntryMsg *> >("EntryMsg") { }
|
||||
EntryMessageListImpl(Extensible *) { }
|
||||
|
||||
~EntryMessageList()
|
||||
EntryMsg* Create() anope_override
|
||||
{
|
||||
for (unsigned i = (*this)->size(); i > 0; --i)
|
||||
delete (*this)->at(i - 1);
|
||||
return new EntryMsgImpl();
|
||||
}
|
||||
};
|
||||
|
||||
EntryMsg::~EntryMsg()
|
||||
EntryMsgImpl::~EntryMsgImpl()
|
||||
{
|
||||
ChannelInfo *ci = ChannelInfo::Find(this->chan);
|
||||
if (!ci)
|
||||
return;
|
||||
|
||||
EntryMessageList *messages = ci->GetExt<EntryMessageList>("entrymsg");
|
||||
if (messages)
|
||||
{
|
||||
std::vector<EntryMsg *>::iterator it = std::find((*messages)->begin(), (*messages)->end(), this);
|
||||
if (it != (*messages)->end())
|
||||
(*messages)->erase(it);
|
||||
}
|
||||
if (!messages)
|
||||
return;
|
||||
|
||||
std::vector<EntryMsg *>::iterator it = std::find((*messages)->begin(), (*messages)->end(), this);
|
||||
if (it != (*messages)->end())
|
||||
(*messages)->erase(it);
|
||||
}
|
||||
|
||||
|
||||
Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
Serializable* EntryMsgImpl::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
{
|
||||
Anope::string sci, screator, smessage;
|
||||
time_t swhen;
|
||||
@@ -77,8 +80,8 @@ Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
|
||||
if (obj)
|
||||
{
|
||||
EntryMsg *msg = anope_dynamic_static_cast<EntryMsg *>(obj);
|
||||
msg->ci = ci;
|
||||
EntryMsgImpl *msg = anope_dynamic_static_cast<EntryMsgImpl *>(obj);
|
||||
msg->chan = ci->name;
|
||||
data["creator"] >> msg->creator;
|
||||
data["message"] >> msg->message;
|
||||
data["when"] >> msg->when;
|
||||
@@ -89,7 +92,7 @@ Serializable* EntryMsg::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
|
||||
data["when"] >> swhen;
|
||||
|
||||
EntryMsg *m = new EntryMsg(ci, screator, smessage, swhen);
|
||||
EntryMsgImpl *m = new EntryMsgImpl(ci, screator, smessage, swhen);
|
||||
(*messages)->push_back(m);
|
||||
return m;
|
||||
}
|
||||
@@ -139,7 +142,7 @@ class CommandEntryMessage : public Command
|
||||
source.Reply(_("The entry message list for \002%s\002 is full."), ci->name.c_str());
|
||||
else
|
||||
{
|
||||
(*messages)->push_back(new EntryMsg(ci, source.GetNick(), message));
|
||||
(*messages)->push_back(new EntryMsgImpl(ci, source.GetNick(), message));
|
||||
Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to add a message";
|
||||
source.Reply(_("Entry message added to \002%s\002"), ci->name.c_str());
|
||||
}
|
||||
@@ -257,13 +260,13 @@ class CommandEntryMessage : public Command
|
||||
class CSEntryMessage : public Module
|
||||
{
|
||||
CommandEntryMessage commandentrymsg;
|
||||
ExtensibleItem<EntryMessageList> eml;
|
||||
ExtensibleItem<EntryMessageListImpl> eml;
|
||||
Serialize::Type entrymsg_type;
|
||||
|
||||
public:
|
||||
CSEntryMessage(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
commandentrymsg(this),
|
||||
eml(this, "entrymsg"), entrymsg_type("EntryMsg", EntryMsg::Unserialize)
|
||||
eml(this, "entrymsg"), entrymsg_type("EntryMsg", EntryMsgImpl::Unserialize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -175,21 +175,26 @@ class CommandCSFlags : public Command
|
||||
}
|
||||
|
||||
Privilege *p = NULL;
|
||||
int add = 1;
|
||||
bool add = true;
|
||||
for (size_t i = 0; i < flags.length(); ++i)
|
||||
{
|
||||
char f = flags[i];
|
||||
switch (f)
|
||||
{
|
||||
case '+':
|
||||
add = 1;
|
||||
add = true;
|
||||
break;
|
||||
case '-':
|
||||
add = 0;
|
||||
add = false;
|
||||
break;
|
||||
case '*':
|
||||
for (std::map<Anope::string, char>::iterator it = defaultFlags.begin(), it_end = defaultFlags.end(); it != it_end; ++it)
|
||||
{
|
||||
bool has = current_flags.count(it->second);
|
||||
// If we are adding a flag they already have or removing one they don't have, don't bother
|
||||
if (add == has)
|
||||
continue;
|
||||
|
||||
if (!u_access.HasPriv(it->first) && !u_access.founder)
|
||||
{
|
||||
if (source.HasPriv("chanserv/access/modify"))
|
||||
@@ -197,9 +202,10 @@ class CommandCSFlags : public Command
|
||||
else
|
||||
continue;
|
||||
}
|
||||
if (add == 1)
|
||||
|
||||
if (add)
|
||||
current_flags.insert(it->second);
|
||||
else if (add == 0)
|
||||
else
|
||||
current_flags.erase(it->second);
|
||||
}
|
||||
break;
|
||||
@@ -225,9 +231,9 @@ class CommandCSFlags : public Command
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add == 1)
|
||||
if (add)
|
||||
current_flags.insert(f);
|
||||
else if (add == 0)
|
||||
else
|
||||
current_flags.erase(f);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -73,13 +73,14 @@ class CommandCSInvite : public Command
|
||||
if (u2 != u)
|
||||
{
|
||||
source.Reply(_("\002%s\002 has been invited to \002%s\002."), u2->nick.c_str(), c->name.c_str());
|
||||
u2->SendMessage(ci->WhoSends(), _("You have been invited to \002%s\002 by \002%s\002."), c->name.c_str(), source.GetNick().c_str());
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << u2->nick;
|
||||
}
|
||||
else
|
||||
{
|
||||
u2->SendMessage(ci->WhoSends(), _("You have been invited to \002%s\002."), c->name.c_str());
|
||||
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci);
|
||||
}
|
||||
u2->SendMessage(ci->WhoSends(), _("You have been invited to \002%s\002."), c->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class CommandCSList : public Command
|
||||
spacesepstream keywords(params[1]);
|
||||
while (keywords.GetToken(keyword))
|
||||
{
|
||||
if (keyword.equals_ci("CS_SUSPENDED"))
|
||||
if (keyword.equals_ci("SUSPENDED"))
|
||||
suspended = true;
|
||||
if (keyword.equals_ci("NOEXPIRE"))
|
||||
channoexpire = true;
|
||||
|
||||
@@ -640,26 +640,37 @@ class CommandCSMode : public Command
|
||||
new_params.push_back("SET");
|
||||
new_params.push_back("-*");
|
||||
this->DoSet(source, ci, new_params);
|
||||
return;
|
||||
}
|
||||
else if (param.equals_ci("BANS") || param.equals_ci("EXEMPTS") || param.equals_ci("INVITEOVERRIDES") || param.equals_ci("VOICES") || param.equals_ci("HALFOPS") || param.equals_ci("OPS"))
|
||||
{
|
||||
const Anope::string &mname = param.upper().substr(0, param.length() - 1);
|
||||
ChannelMode *cm = ModeManager::FindChannelModeByName(mname);
|
||||
if (cm == NULL)
|
||||
{
|
||||
source.Reply(_("Your IRCD does not support %s."), mname.upper().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Anope::string> new_params;
|
||||
new_params.push_back(params[0]);
|
||||
new_params.push_back("SET");
|
||||
new_params.push_back("-" + stringify(cm->mchar));
|
||||
new_params.push_back("*");
|
||||
this->DoSet(source, ci, new_params);
|
||||
}
|
||||
ChannelMode *cm;
|
||||
if (param.length() == 1)
|
||||
cm = ModeManager::FindChannelModeByChar(param[0]);
|
||||
else
|
||||
this->SendSyntax(source);
|
||||
{
|
||||
cm = ModeManager::FindChannelModeByName(param.upper());
|
||||
if (!cm)
|
||||
cm = ModeManager::FindChannelModeByName(param.substr(0, param.length() - 1).upper());
|
||||
}
|
||||
|
||||
if (!cm)
|
||||
{
|
||||
source.Reply(_("There is no such mode %s."), param.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (cm->type != MODE_STATUS && cm->type != MODE_LIST)
|
||||
{
|
||||
source.Reply(_("Mode %s is not a status or list mode."), param.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Anope::string> new_params;
|
||||
new_params.push_back(params[0]);
|
||||
new_params.push_back("SET");
|
||||
new_params.push_back("-" + stringify(cm->mchar));
|
||||
new_params.push_back("*");
|
||||
this->DoSet(source, ci, new_params);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -725,8 +736,8 @@ class CommandCSMode : public Command
|
||||
" Clears all extended bans that start with ~c:\n"
|
||||
" \n"
|
||||
"The \002%s CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be\n"
|
||||
"one of bans, exempts, inviteoverrides, ops, halfops, or voices. If \037what\037 is not given then all\n"
|
||||
"basic modes are removed."),
|
||||
"any mode name. Examples include bans, excepts, inviteoverrides, ops, halfops, and voices. If \037what\037\n"
|
||||
"is not given then all basic modes are removed."),
|
||||
source.command.upper().c_str(), source.command.upper().c_str(), source.command.upper().c_str());
|
||||
return true;
|
||||
}
|
||||
@@ -891,9 +902,9 @@ class CSMode : public Module
|
||||
}
|
||||
}
|
||||
|
||||
void OnCheckModes(Channel *c) anope_override
|
||||
void OnCheckModes(Reference<Channel> &c) anope_override
|
||||
{
|
||||
if (!c->ci)
|
||||
if (!c || !c->ci)
|
||||
return;
|
||||
|
||||
ModeLocks *locks = modelocks.Get(c->ci);
|
||||
@@ -908,9 +919,9 @@ class CSMode : public Module
|
||||
if (cm->type == MODE_REGULAR)
|
||||
{
|
||||
if (!c->HasMode(cm->name) && ml->set)
|
||||
c->SetMode(NULL, cm);
|
||||
c->SetMode(NULL, cm, "", false);
|
||||
else if (c->HasMode(cm->name) && !ml->set)
|
||||
c->RemoveMode(NULL, cm);
|
||||
c->RemoveMode(NULL, cm, "", false);
|
||||
}
|
||||
else if (cm->type == MODE_PARAM)
|
||||
{
|
||||
@@ -921,21 +932,21 @@ class CSMode : public Module
|
||||
c->GetParam(cm->name, param);
|
||||
|
||||
if (!c->HasMode(cm->name) || (!param.empty() && !ml->param.empty() && !param.equals_cs(ml->param)))
|
||||
c->SetMode(NULL, cm, ml->param);
|
||||
c->SetMode(NULL, cm, ml->param, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->HasMode(cm->name))
|
||||
c->RemoveMode(NULL, cm);
|
||||
c->RemoveMode(NULL, cm, "", false);
|
||||
}
|
||||
|
||||
}
|
||||
else if (cm->type == MODE_LIST || cm->type == MODE_STATUS)
|
||||
{
|
||||
if (ml->set)
|
||||
c->SetMode(NULL, cm, ml->param);
|
||||
c->SetMode(NULL, cm, ml->param, false);
|
||||
else
|
||||
c->RemoveMode(NULL, cm, ml->param);
|
||||
c->RemoveMode(NULL, cm, ml->param, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-16
@@ -1163,18 +1163,27 @@ class CSSet : public Module
|
||||
return;
|
||||
|
||||
bool created;
|
||||
Channel *c = Channel::FindOrCreate(ci->name, created, ci->time_registered);
|
||||
if (!ci->bi)
|
||||
{
|
||||
BotInfo *ChanServ = Config->GetClient("ChanServ");
|
||||
if (ChanServ)
|
||||
ChanServ->Assign(NULL, ci);
|
||||
}
|
||||
Channel *c = Channel::FindOrCreate(ci->name, created);
|
||||
|
||||
if (ci->bi && !c->FindUser(ci->bi))
|
||||
ChannelMode *cm = ModeManager::FindChannelModeByName("PERM");
|
||||
if (cm)
|
||||
{
|
||||
ChannelStatus status(BotModes());
|
||||
ci->bi->Join(c, &status);
|
||||
c->SetMode(NULL, cm);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ci->bi)
|
||||
{
|
||||
BotInfo *ChanServ = Config->GetClient("ChanServ");
|
||||
if (ChanServ)
|
||||
ChanServ->Assign(NULL, ci);
|
||||
}
|
||||
|
||||
if (ci->bi && !c->FindUser(ci->bi))
|
||||
{
|
||||
ChannelStatus status(BotModes());
|
||||
ci->bi->Join(c, &status);
|
||||
}
|
||||
}
|
||||
|
||||
if (created)
|
||||
@@ -1280,12 +1289,6 @@ class CSSet : public Module
|
||||
{
|
||||
if (c->ci)
|
||||
persist.Unset(c->ci);
|
||||
|
||||
if (c->CheckDelete())
|
||||
{
|
||||
delete c;
|
||||
return EVENT_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->ci && mode->type != MODE_STATUS && !c->syncing && Me->IsSynced())
|
||||
@@ -1319,6 +1322,7 @@ class CSSet : public Module
|
||||
if (noautoop.HasExt(chan->ci))
|
||||
give_modes = false;
|
||||
if (secureops.HasExt(chan->ci))
|
||||
// This overrides what chanserv does because it is loaded after chanserv
|
||||
take_modes = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/set_misc.h"
|
||||
|
||||
static Module *me;
|
||||
|
||||
@@ -16,25 +17,33 @@ static std::map<Anope::string, Anope::string> descriptions;
|
||||
|
||||
struct CSMiscData;
|
||||
static Anope::map<ExtensibleItem<CSMiscData> *> items;
|
||||
static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name);
|
||||
|
||||
struct CSMiscData : Serializable
|
||||
static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name) anope_override
|
||||
{
|
||||
Serialize::Reference<ChannelInfo> ci;
|
||||
Anope::string name;
|
||||
Anope::string data;
|
||||
ExtensibleItem<CSMiscData>* &it = items[name];
|
||||
if (!it)
|
||||
try
|
||||
{
|
||||
it = new ExtensibleItem<CSMiscData>(me, name);
|
||||
}
|
||||
catch (const ModuleException &) { }
|
||||
return it;
|
||||
}
|
||||
|
||||
CSMiscData(Extensible *obj) : Serializable("CSMiscData"), ci(anope_dynamic_static_cast<ChannelInfo *>(obj))
|
||||
{
|
||||
}
|
||||
struct CSMiscData : MiscData, Serializable
|
||||
{
|
||||
CSMiscData(Extensible *obj) : Serializable("CSMiscData") { }
|
||||
|
||||
CSMiscData(ChannelInfo *c, const Anope::string &n, const Anope::string &d) : Serializable("CSMiscData"), ci(c), name(n), data(d)
|
||||
CSMiscData(ChannelInfo *c, const Anope::string &n, const Anope::string &d) : Serializable("CSMiscData")
|
||||
{
|
||||
object = c->name;
|
||||
name = n;
|
||||
data = d;
|
||||
}
|
||||
|
||||
void Serialize(Serialize::Data &sdata) const anope_override
|
||||
{
|
||||
sdata["ci"] << this->ci->name;
|
||||
sdata["ci"] << this->object;
|
||||
sdata["name"] << this->name;
|
||||
sdata["data"] << this->data;
|
||||
}
|
||||
@@ -55,7 +64,7 @@ struct CSMiscData : Serializable
|
||||
if (obj)
|
||||
{
|
||||
d = anope_dynamic_static_cast<CSMiscData *>(obj);
|
||||
d->ci = ci;
|
||||
d->object = ci->name;
|
||||
data["name"] >> d->name;
|
||||
data["data"] >> d->data;
|
||||
}
|
||||
@@ -70,18 +79,6 @@ struct CSMiscData : Serializable
|
||||
}
|
||||
};
|
||||
|
||||
static ExtensibleItem<CSMiscData> *GetItem(const Anope::string &name)
|
||||
{
|
||||
ExtensibleItem<CSMiscData>* &it = items[name];
|
||||
if (!it)
|
||||
try
|
||||
{
|
||||
it = new ExtensibleItem<CSMiscData>(me, name);
|
||||
}
|
||||
catch (const ModuleException &) { }
|
||||
return it;
|
||||
}
|
||||
|
||||
static Anope::string GetAttribute(const Anope::string &command)
|
||||
{
|
||||
size_t sp = command.rfind(' ');
|
||||
@@ -119,7 +116,7 @@ class CommandCSSetMisc : public Command
|
||||
if (MOD_RESULT == EVENT_STOP)
|
||||
return;
|
||||
|
||||
if (MOD_RESULT != EVENT_ALLOW && source.permission.empty() && !source.AccessFor(ci).HasPriv("SET"))
|
||||
if (MOD_RESULT != EVENT_ALLOW && !source.AccessFor(ci).HasPriv("SET") && source.permission.empty() && !source.HasPriv("chanserv/administration"))
|
||||
{
|
||||
source.Reply(ACCESS_DENIED);
|
||||
return;
|
||||
@@ -134,11 +131,13 @@ class CommandCSSetMisc : public Command
|
||||
if (!param.empty())
|
||||
{
|
||||
item->Set(ci, CSMiscData(ci, key, param));
|
||||
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to change it to " << param;
|
||||
source.Reply(CHAN_SETTING_CHANGED, scommand.c_str(), ci->name.c_str(), params[1].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
item->Unset(ci);
|
||||
Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to unset it";
|
||||
source.Reply(CHAN_SETTING_UNSET, scommand.c_str(), ci->name.c_str());
|
||||
}
|
||||
}
|
||||
@@ -165,16 +164,22 @@ class CommandCSSetMisc : public Command
|
||||
|
||||
class CSSetMisc : public Module
|
||||
{
|
||||
Serialize::Type csmiscdata_type;
|
||||
CommandCSSetMisc commandcssetmisc;
|
||||
Serialize::Type csmiscdata_type;
|
||||
|
||||
public:
|
||||
CSSetMisc(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
csmiscdata_type("CSMiscData", CSMiscData::Unserialize), commandcssetmisc(this)
|
||||
commandcssetmisc(this), csmiscdata_type("CSMiscData", CSMiscData::Unserialize)
|
||||
{
|
||||
me = this;
|
||||
}
|
||||
|
||||
~CSSetMisc()
|
||||
{
|
||||
for (Anope::map<ExtensibleItem<CSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
descriptions.clear();
|
||||
@@ -201,7 +206,7 @@ class CSSetMisc : public Module
|
||||
for (Anope::map<ExtensibleItem<CSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it)
|
||||
{
|
||||
ExtensibleItem<CSMiscData> *e = it->second;
|
||||
CSMiscData *data = e->Get(ci);
|
||||
MiscData *data = e->Get(ci);
|
||||
|
||||
if (data != NULL)
|
||||
info[e->name.substr(12).replace_all_cs("_", " ")] = data->data;
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/cs_suspend.h"
|
||||
#include "modules/suspend.h"
|
||||
|
||||
struct CSSuspendInfoImpl : CSSuspendInfo, Serializable
|
||||
struct CSSuspendInfo : SuspendInfo, Serializable
|
||||
{
|
||||
CSSuspendInfoImpl(Extensible *) : Serializable("CSSuspendInfo") { }
|
||||
CSSuspendInfo(Extensible *) : Serializable("CSSuspendInfo") { }
|
||||
|
||||
void Serialize(Serialize::Data &data) const anope_override
|
||||
{
|
||||
data["chan"] << chan;
|
||||
data["chan"] << what;
|
||||
data["by"] << by;
|
||||
data["reason"] << reason;
|
||||
data["time"] << time;
|
||||
data["time"] << when;
|
||||
data["expires"] << expires;
|
||||
}
|
||||
|
||||
@@ -30,21 +30,21 @@ struct CSSuspendInfoImpl : CSSuspendInfo, Serializable
|
||||
Anope::string schan;
|
||||
data["chan"] >> schan;
|
||||
|
||||
CSSuspendInfoImpl *si;
|
||||
CSSuspendInfo *si;
|
||||
if (obj)
|
||||
si = anope_dynamic_static_cast<CSSuspendInfoImpl *>(obj);
|
||||
si = anope_dynamic_static_cast<CSSuspendInfo *>(obj);
|
||||
else
|
||||
{
|
||||
ChannelInfo *ci = ChannelInfo::Find(schan);
|
||||
if (!ci)
|
||||
return NULL;
|
||||
si = ci->Extend<CSSuspendInfoImpl>("CS_SUSPENDED");
|
||||
data["chan"] >> si->chan;
|
||||
si = ci->Extend<CSSuspendInfo>("CS_SUSPENDED");
|
||||
data["chan"] >> si->what;
|
||||
}
|
||||
|
||||
data["by"] >> si->by;
|
||||
data["reason"] >> si->reason;
|
||||
data["time"] >> si->time;
|
||||
data["time"] >> si->when;
|
||||
data["expires"] >> si->expires;
|
||||
return si;
|
||||
}
|
||||
@@ -99,10 +99,10 @@ class CommandCSSuspend : public Command
|
||||
}
|
||||
|
||||
CSSuspendInfo *si = ci->Extend<CSSuspendInfo>("CS_SUSPENDED");
|
||||
si->chan = ci->name;
|
||||
si->what = ci->name;
|
||||
si->by = source.GetNick();
|
||||
si->reason = reason;
|
||||
si->time = Anope::CurTime;
|
||||
si->when = Anope::CurTime;
|
||||
si->expires = expiry_secs ? expiry_secs + Anope::CurTime : 0;
|
||||
|
||||
if (ci->c)
|
||||
@@ -121,7 +121,7 @@ class CommandCSSuspend : public Command
|
||||
ci->c->Kick(NULL, users[i], "%s", !reason.empty() ? reason.c_str() : Language::Translate(users[i], _("This channel has been suspended.")));
|
||||
}
|
||||
|
||||
Log(LOG_ADMIN, source, this, ci) << " (" << (!reason.empty() ? reason : "No reason") << "), expires on " << (expiry_secs ? Anope::strftime(Anope::CurTime + expiry_secs) : "never");
|
||||
Log(LOG_ADMIN, source, this, ci) << "(" << (!reason.empty() ? reason : "No reason") << "), expires on " << (expiry_secs ? Anope::strftime(Anope::CurTime + expiry_secs) : "never");
|
||||
source.Reply(_("Channel \002%s\002 is now suspended."), ci->name.c_str());
|
||||
|
||||
FOREACH_MOD(OnChanSuspend, (ci));
|
||||
@@ -173,7 +173,7 @@ class CommandCSUnSuspend : public Command
|
||||
return;
|
||||
}
|
||||
|
||||
Log(LOG_ADMIN, source, this, ci) << " which was suspended by " << si->by << " for: " << (!si->reason.empty() ? si->reason : "No reason");
|
||||
Log(LOG_ADMIN, source, this, ci) << "which was suspended by " << si->by << " for: " << (!si->reason.empty() ? si->reason : "No reason");
|
||||
|
||||
ci->Shrink<CSSuspendInfo>("CS_SUSPENDED");
|
||||
|
||||
@@ -198,13 +198,13 @@ class CSSuspend : public Module
|
||||
{
|
||||
CommandCSSuspend commandcssuspend;
|
||||
CommandCSUnSuspend commandcsunsuspend;
|
||||
ExtensibleItem<CSSuspendInfoImpl> suspend;
|
||||
ExtensibleItem<CSSuspendInfo> suspend;
|
||||
Serialize::Type suspend_type;
|
||||
|
||||
public:
|
||||
CSSuspend(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
commandcssuspend(this), commandcsunsuspend(this), suspend(this, "CS_SUSPENDED"),
|
||||
suspend_type("CSSuspendInfo", CSSuspendInfoImpl::Unserialize)
|
||||
suspend_type("CSSuspendInfo", CSSuspendInfo::Unserialize)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -218,8 +218,8 @@ class CSSuspend : public Module
|
||||
info[_("Suspended by")] = si->by;
|
||||
if (!si->reason.empty())
|
||||
info[_("Suspend reason")] = si->reason;
|
||||
if (si->time)
|
||||
info[_("Suspended on")] = Anope::strftime(si->time, source.GetAccount(), true);
|
||||
if (si->when)
|
||||
info[_("Suspended on")] = Anope::strftime(si->when, source.GetAccount(), true);
|
||||
if (si->expires)
|
||||
info[_("Suspension expires")] = Anope::strftime(si->expires, source.GetAccount(), true);
|
||||
}
|
||||
|
||||
@@ -130,8 +130,8 @@ class CommandCSDown : public Command
|
||||
{
|
||||
ChanUserContainer *cu = c->FindUser(u);
|
||||
if (cu != NULL)
|
||||
for (size_t i = 0; i < cu->status.Modes().length(); ++i)
|
||||
c->RemoveMode(NULL, ModeManager::FindChannelModeByChar(cu->status.Modes()[i]), u->GetUID());
|
||||
for (size_t i = cu->status.Modes().length(); i > 0;)
|
||||
c->RemoveMode(NULL, ModeManager::FindChannelModeByChar(cu->status.Modes()[--i]), u->GetUID());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -27,7 +27,7 @@ class CommandGLGlobal : public Command
|
||||
const Anope::string &msg = params[0];
|
||||
|
||||
if (!GService)
|
||||
source.Reply("No global reference, is gl_main loaded?");
|
||||
source.Reply("No global reference, is global loaded?");
|
||||
else
|
||||
{
|
||||
Log(LOG_ADMIN, source, this);
|
||||
|
||||
@@ -13,21 +13,31 @@
|
||||
|
||||
class CommandHSGroup : public Command
|
||||
{
|
||||
bool setting;
|
||||
|
||||
public:
|
||||
void Sync(const NickAlias *na)
|
||||
{
|
||||
if (setting)
|
||||
return;
|
||||
|
||||
if (!na || !na->HasVhost())
|
||||
return;
|
||||
|
||||
|
||||
setting = true;
|
||||
for (unsigned i = 0; i < na->nc->aliases->size(); ++i)
|
||||
{
|
||||
NickAlias *nick = na->nc->aliases->at(i);
|
||||
if (nick)
|
||||
{
|
||||
nick->SetVhost(na->GetVhostIdent(), na->GetVhostHost(), na->GetVhostCreator());
|
||||
FOREACH_MOD(OnSetVhost, (nick));
|
||||
}
|
||||
}
|
||||
setting = false;
|
||||
}
|
||||
|
||||
public:
|
||||
CommandHSGroup(Module *creator) : Command(creator, "hostserv/group", 0, 0)
|
||||
CommandHSGroup(Module *creator) : Command(creator, "hostserv/group", 0, 0), setting(false)
|
||||
{
|
||||
this->SetDesc(_("Syncs the vhost for all nicks in a group"));
|
||||
}
|
||||
@@ -69,12 +79,36 @@ class CommandHSGroup : public Command
|
||||
class HSGroup : public Module
|
||||
{
|
||||
CommandHSGroup commandhsgroup;
|
||||
bool syncongroup;
|
||||
bool synconset;
|
||||
|
||||
public:
|
||||
HSGroup(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
commandhsgroup(this)
|
||||
{
|
||||
}
|
||||
|
||||
void OnSetVhost(NickAlias *na) anope_override
|
||||
{
|
||||
if (!synconset)
|
||||
return;
|
||||
|
||||
commandhsgroup.Sync(na);
|
||||
}
|
||||
|
||||
void OnNickGroup(User *u, NickAlias *na) anope_override
|
||||
{
|
||||
if (!syncongroup)
|
||||
return;
|
||||
|
||||
commandhsgroup.Sync(na);
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
Configuration::Block *block = conf->GetModule(this);
|
||||
syncongroup = block->Get<bool>("syncongroup");
|
||||
synconset = block->Get<bool>("synconset");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ class CommandMSSendAll : public Command
|
||||
|
||||
const Anope::string &text = params[0];
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to send " << text;
|
||||
|
||||
for (nickcore_map::const_iterator it = NickCoreList->begin(), it_end = NickCoreList->end(); it != it_end; ++it)
|
||||
{
|
||||
const NickCore *nc = it->second;
|
||||
|
||||
@@ -118,51 +118,108 @@ class CommandNSAJoin : public Command
|
||||
}
|
||||
}
|
||||
|
||||
void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &chan, const Anope::string &key)
|
||||
void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &chans, const Anope::string &keys)
|
||||
{
|
||||
AJoinList *channels = nc->Require<AJoinList>("ajoinlist");
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < (*channels)->size(); ++i)
|
||||
if ((*channels)->at(i)->channel.equals_ci(chan))
|
||||
break;
|
||||
|
||||
if ((*channels)->size() >= Config->GetModule(this->owner)->Get<unsigned>("ajoinmax"))
|
||||
source.Reply(_("Sorry, the maximum of %d auto join entries has been reached."), Config->GetModule(this->owner)->Get<unsigned>("ajoinmax"));
|
||||
else if (i != (*channels)->size())
|
||||
source.Reply(_("%s is already on %s's auto join list."), chan.c_str(), nc->display.c_str());
|
||||
else if (IRCD->IsChannelValid(chan) == false)
|
||||
source.Reply(CHAN_X_INVALID, chan.c_str());
|
||||
else
|
||||
Anope::string addedchans;
|
||||
Anope::string alreadyadded;
|
||||
Anope::string invalidkey;
|
||||
commasepstream ksep(keys, true);
|
||||
commasepstream csep(chans);
|
||||
for (Anope::string chan, key; csep.GetToken(chan);)
|
||||
{
|
||||
AJoinEntry *entry = new AJoinEntry(nc);
|
||||
entry->owner = nc;
|
||||
entry->channel = chan;
|
||||
entry->key = key;
|
||||
(*channels)->push_back(entry);
|
||||
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to ADD channel " << chan << " to " << nc->display;
|
||||
source.Reply(_("%s added to %s's auto join list."), chan.c_str(), nc->display.c_str());
|
||||
ksep.GetToken(key);
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < (*channels)->size(); ++i)
|
||||
if ((*channels)->at(i)->channel.equals_ci(chan))
|
||||
break;
|
||||
|
||||
if ((*channels)->size() >= Config->GetModule(this->owner)->Get<unsigned>("ajoinmax"))
|
||||
{
|
||||
source.Reply(_("Sorry, the maximum of %d auto join entries has been reached."), Config->GetModule(this->owner)->Get<unsigned>("ajoinmax"));
|
||||
return;
|
||||
}
|
||||
else if (i != (*channels)->size())
|
||||
alreadyadded += chan + ", ";
|
||||
else if (IRCD->IsChannelValid(chan) == false)
|
||||
source.Reply(CHAN_X_INVALID, chan.c_str());
|
||||
else
|
||||
{
|
||||
Channel *c = Channel::Find(chan);
|
||||
Anope::string k;
|
||||
if (c && c->GetParam("KEY", k) && key != k)
|
||||
{
|
||||
invalidkey += chan + ", ";
|
||||
continue;
|
||||
}
|
||||
|
||||
AJoinEntry *entry = new AJoinEntry(nc);
|
||||
entry->owner = nc;
|
||||
entry->channel = chan;
|
||||
entry->key = key;
|
||||
(*channels)->push_back(entry);
|
||||
addedchans += chan + ", ";
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyadded.empty())
|
||||
{
|
||||
alreadyadded = alreadyadded.substr(0, alreadyadded.length() - 2);
|
||||
source.Reply(_("%s is already on %s's auto join list."), alreadyadded.c_str(), nc->display.c_str());
|
||||
}
|
||||
|
||||
if (!invalidkey.empty())
|
||||
{
|
||||
invalidkey = invalidkey.substr(0, invalidkey.length() - 2);
|
||||
source.Reply(_("%s had an invalid key specified, and was thus ignored."), invalidkey.c_str());
|
||||
}
|
||||
|
||||
if (addedchans.empty())
|
||||
return;
|
||||
|
||||
addedchans = addedchans.substr(0, addedchans.length() - 2);
|
||||
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to ADD channel " << addedchans << " to " << nc->display;
|
||||
source.Reply(_("%s added to %s's auto join list."), addedchans.c_str(), nc->display.c_str());
|
||||
}
|
||||
|
||||
void DoDel(CommandSource &source, NickCore *nc, const Anope::string &chan)
|
||||
void DoDel(CommandSource &source, NickCore *nc, const Anope::string &chans)
|
||||
{
|
||||
AJoinList *channels = nc->Require<AJoinList>("ajoinlist");
|
||||
Anope::string delchans;
|
||||
Anope::string notfoundchans;
|
||||
commasepstream sep(chans);
|
||||
|
||||
unsigned i = 0;
|
||||
for (; i < (*channels)->size(); ++i)
|
||||
if ((*channels)->at(i)->channel.equals_ci(chan))
|
||||
break;
|
||||
|
||||
if (i == (*channels)->size())
|
||||
source.Reply(_("%s was not found on %s's auto join list."), chan.c_str(), nc->display.c_str());
|
||||
else
|
||||
for (Anope::string chan; sep.GetToken(chan);)
|
||||
{
|
||||
delete (*channels)->at(i);
|
||||
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to DELETE channel " << chan << " from " << nc->display;
|
||||
source.Reply(_("%s was removed from %s's auto join list."), chan.c_str(), nc->display.c_str());
|
||||
unsigned i = 0;
|
||||
for (; i < (*channels)->size(); ++i)
|
||||
if ((*channels)->at(i)->channel.equals_ci(chan))
|
||||
break;
|
||||
|
||||
if (i == (*channels)->size())
|
||||
notfoundchans += chan + ", ";
|
||||
else
|
||||
{
|
||||
delete (*channels)->at(i);
|
||||
delchans += chan + ", ";
|
||||
}
|
||||
}
|
||||
|
||||
if (!notfoundchans.empty())
|
||||
{
|
||||
notfoundchans = notfoundchans.substr(0, notfoundchans.length() - 2);
|
||||
source.Reply(_("%s was not found on %s's auto join list."), notfoundchans.c_str(), nc->display.c_str());
|
||||
}
|
||||
|
||||
if (delchans.empty())
|
||||
return;
|
||||
|
||||
delchans = delchans.substr(0, delchans.length() - 2);
|
||||
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to DELETE channel " << delchans << " from " << nc->display;
|
||||
source.Reply(_("%s was removed from %s's auto join list."), delchans.c_str(), nc->display.c_str());
|
||||
|
||||
if ((*channels)->empty())
|
||||
nc->Shrink<AJoinList>("ajoinlist");
|
||||
}
|
||||
@@ -265,7 +322,10 @@ class NSAJoin : public Module
|
||||
|
||||
AJoinList *channels = u->Account()->GetExt<AJoinList>("ajoinlist");
|
||||
if (channels == NULL)
|
||||
channels = u->Account()->Extend<AJoinList>("ajoinlist");
|
||||
return;
|
||||
|
||||
/* Set +r now, so we can ajoin users into +R channels */
|
||||
ModeManager::ProcessModes();
|
||||
|
||||
for (unsigned i = 0; i < (*channels)->size(); ++i)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,21 @@
|
||||
#include "module.h"
|
||||
#include "modules/ns_cert.h"
|
||||
|
||||
static Anope::hash_map<NickCore *> certmap;
|
||||
|
||||
struct CertServiceImpl : CertService
|
||||
{
|
||||
CertServiceImpl(Module *o) : CertService(o) { }
|
||||
|
||||
NickCore* FindAccountFromCert(const Anope::string &cert) anope_override
|
||||
{
|
||||
Anope::hash_map<NickCore *>::iterator it = certmap.find(cert);
|
||||
if (it != certmap.end())
|
||||
return it->second;
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
struct NSCertListImpl : NSCertList
|
||||
{
|
||||
Serialize::Reference<NickCore> nc;
|
||||
@@ -20,6 +35,11 @@ struct NSCertListImpl : NSCertList
|
||||
public:
|
||||
NSCertListImpl(Extensible *obj) : nc(anope_dynamic_static_cast<NickCore *>(obj)) { }
|
||||
|
||||
~NSCertListImpl()
|
||||
{
|
||||
ClearCert();
|
||||
}
|
||||
|
||||
/** Add an entry to the nick's certificate list
|
||||
*
|
||||
* @param entry The fingerprint to add to the cert list
|
||||
@@ -29,6 +49,7 @@ struct NSCertListImpl : NSCertList
|
||||
void AddCert(const Anope::string &entry) anope_override
|
||||
{
|
||||
this->certs.push_back(entry);
|
||||
certmap[entry] = nc;
|
||||
FOREACH_MOD(OnNickAddCert, (this->nc, entry));
|
||||
}
|
||||
|
||||
@@ -75,6 +96,7 @@ struct NSCertListImpl : NSCertList
|
||||
if (it != this->certs.end())
|
||||
{
|
||||
FOREACH_MOD(OnNickEraseCert, (this->nc, entry));
|
||||
certmap.erase(entry);
|
||||
this->certs.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -86,6 +108,8 @@ struct NSCertListImpl : NSCertList
|
||||
void ClearCert() anope_override
|
||||
{
|
||||
FOREACH_MOD(OnNickClearCert, (this->nc));
|
||||
for (unsigned i = 0; i < certs.size(); ++i)
|
||||
certmap.erase(certs[i]);
|
||||
this->certs.clear();
|
||||
}
|
||||
|
||||
@@ -124,9 +148,14 @@ struct NSCertListImpl : NSCertList
|
||||
Anope::string buf;
|
||||
data["cert"] >> buf;
|
||||
spacesepstream sep(buf);
|
||||
for (unsigned i = 0; i < c->certs.size(); ++i)
|
||||
certmap.erase(c->certs[i]);
|
||||
c->certs.clear();
|
||||
while (sep.GetToken(buf))
|
||||
{
|
||||
c->certs.push_back(buf);
|
||||
certmap[buf] = n;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -134,28 +163,28 @@ struct NSCertListImpl : NSCertList
|
||||
class CommandNSCert : public Command
|
||||
{
|
||||
private:
|
||||
void DoAdd(CommandSource &source, NickCore *nc, const Anope::string &certfp)
|
||||
void DoAdd(CommandSource &source, NickCore *nc, Anope::string certfp)
|
||||
{
|
||||
NSCertList *cl = nc->Require<NSCertList>("certificates");
|
||||
unsigned max = Config->GetModule(this->owner)->Get<unsigned>("max", "5");
|
||||
|
||||
if (cl->GetCertCount() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax", "5"))
|
||||
if (cl->GetCertCount() >= max)
|
||||
{
|
||||
source.Reply(_("Sorry, the maximum of %d certificate entries has been reached."), Config->GetModule(this->owner)->Get<unsigned>("accessmax"));
|
||||
source.Reply(_("Sorry, the maximum of %d certificate entries has been reached."), max);
|
||||
return;
|
||||
}
|
||||
|
||||
if (certfp.empty())
|
||||
if (source.GetAccount() == nc)
|
||||
{
|
||||
if (source.GetUser() && !source.GetUser()->fingerprint.empty() && !cl->FindCert(source.GetUser()->fingerprint))
|
||||
{
|
||||
cl->AddCert(source.GetUser()->fingerprint);
|
||||
Log(LOG_COMMAND, source, this) << "to ADD its current certificate fingerprint " << source.GetUser()->fingerprint;
|
||||
source.Reply(_("\002%s\002 added to your certificate list."), source.GetUser()->fingerprint.c_str());
|
||||
}
|
||||
else
|
||||
this->OnSyntaxError(source, "ADD");
|
||||
User *u = source.GetUser();
|
||||
|
||||
return;
|
||||
if (!u || u->fingerprint.empty())
|
||||
{
|
||||
source.Reply(_("You are not using a client certificate."));
|
||||
return;
|
||||
}
|
||||
|
||||
certfp = u->fingerprint;
|
||||
}
|
||||
|
||||
if (cl->FindCert(certfp))
|
||||
@@ -164,26 +193,31 @@ class CommandNSCert : public Command
|
||||
return;
|
||||
}
|
||||
|
||||
if (certmap.find(certfp) != certmap.end())
|
||||
{
|
||||
source.Reply(_("Fingerprint \002%s\002 is already in use."), certfp.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
cl->AddCert(certfp);
|
||||
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to ADD certificate fingerprint " << certfp << " to " << nc->display;
|
||||
source.Reply(_("\002%s\002 added to %s's certificate list."), certfp.c_str(), nc->display.c_str());
|
||||
}
|
||||
|
||||
void DoDel(CommandSource &source, NickCore *nc, const Anope::string &certfp)
|
||||
void DoDel(CommandSource &source, NickCore *nc, Anope::string certfp)
|
||||
{
|
||||
NSCertList *cl = nc->Require<NSCertList>("certificates");
|
||||
|
||||
if (certfp.empty())
|
||||
{
|
||||
if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl->FindCert(source.GetUser()->fingerprint))
|
||||
{
|
||||
cl->EraseCert(source.GetUser()->fingerprint);
|
||||
Log(LOG_COMMAND, source, this) << "to DELETE its current certificate fingerprint " << source.GetUser()->fingerprint;
|
||||
source.Reply(_("\002%s\002 deleted from your certificate list."), source.GetUser()->fingerprint.c_str());
|
||||
}
|
||||
else
|
||||
this->OnSyntaxError(source, "DEL");
|
||||
User *u = source.GetUser();
|
||||
if (u)
|
||||
certfp = u->fingerprint;
|
||||
}
|
||||
|
||||
if (certfp.empty())
|
||||
{
|
||||
this->OnSyntaxError(source, "DEL");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -221,7 +255,7 @@ class CommandNSCert : public Command
|
||||
CommandNSCert(Module *creator) : Command(creator, "nickserv/cert", 1, 3)
|
||||
{
|
||||
this->SetDesc(_("Modify the nickname client certificate list"));
|
||||
this->SetSyntax(_("ADD [\037nickname\037] \037fingerprint\037"));
|
||||
this->SetSyntax(_("ADD [\037nickname\037] [\037fingerprint\037]"));
|
||||
this->SetSyntax(_("DEL [\037nickname\037] \037fingerprint\037"));
|
||||
this->SetSyntax(_("LIST [\037nickname\037]"));
|
||||
}
|
||||
@@ -308,10 +342,11 @@ class NSCert : public Module
|
||||
{
|
||||
CommandNSCert commandnscert;
|
||||
NSCertListImpl::ExtensibleItem certs;
|
||||
CertServiceImpl cs;
|
||||
|
||||
public:
|
||||
NSCert(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
commandnscert(this), certs(this, "certificates")
|
||||
commandnscert(this), certs(this, "certificates"), cs(this)
|
||||
{
|
||||
if (!IRCD || !IRCD->CanCertFP)
|
||||
throw ModuleException("Your IRCd does not support ssl client certificates");
|
||||
@@ -319,22 +354,22 @@ class NSCert : public Module
|
||||
|
||||
void OnFingerprint(User *u) anope_override
|
||||
{
|
||||
NickAlias *na = NickAlias::Find(u->nick);
|
||||
BotInfo *NickServ = Config->GetClient("NickServ");
|
||||
if (!NickServ || !na)
|
||||
return;
|
||||
if (u->IsIdentified() && u->Account() == na->nc)
|
||||
return;
|
||||
if (na->nc->HasExt("NS_SUSPENDED"))
|
||||
if (!NickServ || u->IsIdentified())
|
||||
return;
|
||||
|
||||
NSCertList *cl = certs.Get(na->nc);
|
||||
if (!cl || !cl->FindCert(u->fingerprint))
|
||||
NickCore *nc = cs.FindAccountFromCert(u->fingerprint);
|
||||
if (!nc || nc->HasExt("NS_SUSPENDED"))
|
||||
return;
|
||||
|
||||
u->Identify(na);
|
||||
u->SendMessage(NickServ, _("SSL certificate fingerprint accepted, you are now identified."));
|
||||
Log(NickServ) << u->GetMask() << " automatically identified for account " << na->nc->display << " via SSL certificate fingerprint";
|
||||
NickAlias *na = NickAlias::Find(u->nick);
|
||||
if (na && na->nc == nc)
|
||||
u->Identify(na);
|
||||
else
|
||||
u->Login(nc);
|
||||
|
||||
u->SendMessage(NickServ, _("SSL certificate fingerprint accepted, you are now identified to \002%s\002."), nc->display.c_str());
|
||||
Log(NickServ) << u->GetMask() << " automatically identified for account " << nc->display << " via SSL certificate fingerprint";
|
||||
}
|
||||
|
||||
EventReturn OnNickValidate(User *u, NickAlias *na) anope_override
|
||||
|
||||
@@ -72,10 +72,10 @@ class NSGroupRequest : public IdentifyRequest
|
||||
class CommandNSGroup : public Command
|
||||
{
|
||||
public:
|
||||
CommandNSGroup(Module *creator) : Command(creator, "nickserv/group", 1, 2)
|
||||
CommandNSGroup(Module *creator) : Command(creator, "nickserv/group", 0, 2)
|
||||
{
|
||||
this->SetDesc(_("Join a group"));
|
||||
this->SetSyntax(_("\037target\037 \037password\037"));
|
||||
this->SetSyntax(_("\037[target]\037 \037[password]\037"));
|
||||
this->AllowUnregistered(true);
|
||||
this->RequireUser(true);
|
||||
}
|
||||
@@ -83,7 +83,23 @@ class CommandNSGroup : public Command
|
||||
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
||||
{
|
||||
User *u = source.GetUser();
|
||||
const Anope::string &nick = params[0];
|
||||
|
||||
Anope::string nick;
|
||||
if (params.empty())
|
||||
{
|
||||
NickCore* core = u->Account();
|
||||
if (core)
|
||||
nick = core->display;
|
||||
}
|
||||
else
|
||||
nick = params[0];
|
||||
|
||||
if (nick.empty())
|
||||
{
|
||||
this->SendSyntax(source);
|
||||
return;
|
||||
}
|
||||
|
||||
const Anope::string &pass = params.size() > 1 ? params[1] : "";
|
||||
|
||||
if (Anope::ReadOnly)
|
||||
@@ -297,14 +313,25 @@ class CommandNSGList : public Command
|
||||
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Nick")).AddColumn(_("Expires"));
|
||||
time_t nickserv_expire = Config->GetModule("nickserv")->Get<time_t>("expire");
|
||||
time_t nickserv_expire = Config->GetModule("nickserv")->Get<time_t>("expire", "21d"),
|
||||
unconfirmed_expire = Config->GetModule("nickserv")->Get<time_t>("unconfirmedexpire", "1d");
|
||||
for (unsigned i = 0; i < nc->aliases->size(); ++i)
|
||||
{
|
||||
const NickAlias *na2 = nc->aliases->at(i);
|
||||
|
||||
Anope::string expires;
|
||||
if (na2->HasExt("NS_NO_EXPIRE"))
|
||||
expires = "Does not expire";
|
||||
else if (!nickserv_expire || Anope::NoExpire)
|
||||
;
|
||||
else if (na2->nc->HasExt("UNCONFIRMED") && unconfirmed_expire)
|
||||
expires = Anope::strftime(na2->time_registered + unconfirmed_expire, source.GetAccount());
|
||||
else
|
||||
expires = Anope::strftime(na2->last_seen + nickserv_expire, source.GetAccount());
|
||||
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Nick"] = na2->nick;
|
||||
entry["Expires"] = (na2->HasExt("NS_NO_EXPIRE") || !nickserv_expire || Anope::NoExpire) ? "Does not expire" : Anope::strftime(na2->last_seen + nickserv_expire, source.GetAccount());
|
||||
entry["Expires"] = expires;
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class CommandNSList : public Command
|
||||
{
|
||||
if (keyword.equals_ci("NOEXPIRE"))
|
||||
nsnoexpire = true;
|
||||
if (keyword.equals_ci("NS_SUSPENDED"))
|
||||
if (keyword.equals_ci("SUSPENDED"))
|
||||
suspended = true;
|
||||
if (keyword.equals_ci("UNCONFIRMED"))
|
||||
unconfirmed = true;
|
||||
|
||||
@@ -130,12 +130,6 @@ class CommandNSRegister : public Command
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsregister.equals_ci("mail") && email.empty())
|
||||
{
|
||||
source.Reply(_("You must specify an email address."));
|
||||
return;
|
||||
}
|
||||
|
||||
time_t nickregdelay = Config->GetModule(this->owner)->Get<time_t>("nickregdelay");
|
||||
time_t reg_delay = Config->GetModule("nickserv")->Get<time_t>("regdelay");
|
||||
if (u && !u->HasMode("OPER") && nickregdelay && Anope::CurTime - u->timestamp < nickregdelay)
|
||||
@@ -222,15 +216,10 @@ class CommandNSRegister : public Command
|
||||
}
|
||||
else if (nsregister.equals_ci("mail"))
|
||||
{
|
||||
nc->Extend<bool>("UNCONFIRMED");
|
||||
if (SendRegmail(u, na, source.service))
|
||||
if (!email.empty())
|
||||
{
|
||||
time_t unconfirmed_expire = Config->GetModule("ns_register")->Get<time_t>("unconfirmedexpire", "1d");
|
||||
BotInfo *bi;
|
||||
Anope::string cmd;
|
||||
if (Command::FindCommandFromService("nickserv/confirm", bi, cmd))
|
||||
source.Reply(_("A passcode has been sent to %s, please type \002%s%s %s <passcode>\002 to confirm your email address."), email.c_str(), Config->StrictPrivmsg.c_str(), bi->nick.c_str(), cmd.c_str());
|
||||
source.Reply(_("If you do not confirm your email address within %s your account will expire."), Anope::Duration(unconfirmed_expire, source.GetAccount()).c_str());
|
||||
nc->Extend<bool>("UNCONFIRMED");
|
||||
SendRegmail(NULL, na, source.service);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,12 +357,12 @@ class NSRegister : public Module
|
||||
if (nsregister.equals_ci("admin"))
|
||||
u->SendMessage(NickServ, _("All new accounts must be validated by an administrator. Please wait for your registration to be confirmed."));
|
||||
else
|
||||
u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered."));
|
||||
u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you."));
|
||||
const NickAlias *this_na = NickAlias::Find(u->Account()->display);
|
||||
time_t time_registered = Anope::CurTime - this_na->time_registered;
|
||||
time_t unconfirmed_expire = Config->GetModule(this)->Get<time_t>("unconfirmedexpire", "1d");
|
||||
if (unconfirmed_expire > time_registered)
|
||||
u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s"), Anope::Duration(unconfirmed_expire - time_registered, u->Account()).c_str());
|
||||
u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s."), Anope::Duration(unconfirmed_expire - time_registered, u->Account()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,9 +27,7 @@ class CommandNSResetPass : public Command
|
||||
{
|
||||
const NickAlias *na;
|
||||
|
||||
if (Config->GetBlock("mail")->Get<bool>("restrict") && !source.HasCommand("nickserv/resetpass"))
|
||||
source.Reply(ACCESS_DENIED);
|
||||
else if (!(na = NickAlias::Find(params[0])))
|
||||
if (!(na = NickAlias::Find(params[0])))
|
||||
source.Reply(NICK_X_NOT_REGISTERED, params[0].c_str());
|
||||
else if (!na->nc->email.equals_ci(params[1]))
|
||||
source.Reply(_("Incorrect email address."));
|
||||
|
||||
@@ -449,6 +449,12 @@ class CommandNSSetEmail : public Command
|
||||
}
|
||||
NickCore *nc = na->nc;
|
||||
|
||||
if (nc->HasExt("UNCONFIRMED"))
|
||||
{
|
||||
source.Reply(_("You may not change the email of an unconfirmed account."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (param.empty() && Config->GetModule("nickserv")->Get<bool>("forceemail", "yes"))
|
||||
{
|
||||
source.Reply(_("You cannot unset the e-mail on this network."));
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/set_misc.h"
|
||||
|
||||
static Module *me;
|
||||
|
||||
@@ -17,25 +18,33 @@ static std::map<Anope::string, Anope::string> descriptions;
|
||||
|
||||
struct NSMiscData;
|
||||
static Anope::map<ExtensibleItem<NSMiscData> *> items;
|
||||
static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name);
|
||||
|
||||
struct NSMiscData : Serializable
|
||||
static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name)
|
||||
{
|
||||
Serialize::Reference<NickCore> nc;
|
||||
Anope::string name;
|
||||
Anope::string data;
|
||||
ExtensibleItem<NSMiscData>* &it = items[name];
|
||||
if (!it)
|
||||
try
|
||||
{
|
||||
it = new ExtensibleItem<NSMiscData>(me, name);
|
||||
}
|
||||
catch (const ModuleException &) { }
|
||||
return it;
|
||||
}
|
||||
|
||||
NSMiscData(Extensible *obj) : Serializable("NSMiscData"), nc(anope_dynamic_static_cast<NickCore *>(obj))
|
||||
{
|
||||
}
|
||||
struct NSMiscData : MiscData, Serializable
|
||||
{
|
||||
NSMiscData(Extensible *) : Serializable("NSMiscData") { }
|
||||
|
||||
NSMiscData(NickCore *ncore, const Anope::string &n, const Anope::string &d) : Serializable("NSMiscData"), nc(ncore), name(n), data(d)
|
||||
NSMiscData(NickCore *ncore, const Anope::string &n, const Anope::string &d) : Serializable("NSMiscData")
|
||||
{
|
||||
object = ncore->display;
|
||||
name = n;
|
||||
data = d;
|
||||
}
|
||||
|
||||
void Serialize(Serialize::Data &sdata) const anope_override
|
||||
{
|
||||
sdata["nc"] << this->nc->display;
|
||||
sdata["nc"] << this->object;
|
||||
sdata["name"] << this->name;
|
||||
sdata["data"] << this->data;
|
||||
}
|
||||
@@ -52,11 +61,11 @@ struct NSMiscData : Serializable
|
||||
if (nc == NULL)
|
||||
return NULL;
|
||||
|
||||
NSMiscData *d;
|
||||
NSMiscData *d = NULL;
|
||||
if (obj)
|
||||
{
|
||||
d = anope_dynamic_static_cast<NSMiscData *>(obj);
|
||||
d->nc = nc;
|
||||
d->object = nc->display;
|
||||
data["name"] >> d->name;
|
||||
data["data"] >> d->data;
|
||||
}
|
||||
@@ -65,26 +74,12 @@ struct NSMiscData : Serializable
|
||||
ExtensibleItem<NSMiscData> *item = GetItem(sname);
|
||||
if (item)
|
||||
d = item->Set(nc, NSMiscData(nc, sname, sdata));
|
||||
else
|
||||
d = NULL;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
};
|
||||
|
||||
static ExtensibleItem<NSMiscData> *GetItem(const Anope::string &name)
|
||||
{
|
||||
ExtensibleItem<NSMiscData>* &it = items[name];
|
||||
if (!it)
|
||||
try
|
||||
{
|
||||
it = new ExtensibleItem<NSMiscData>(me, name);
|
||||
}
|
||||
catch (const ModuleException &) { }
|
||||
return it;
|
||||
}
|
||||
|
||||
static Anope::string GetAttribute(const Anope::string &command)
|
||||
{
|
||||
size_t sp = command.rfind(' ');
|
||||
@@ -182,17 +177,23 @@ class CommandNSSASetMisc : public CommandNSSetMisc
|
||||
|
||||
class NSSetMisc : public Module
|
||||
{
|
||||
Serialize::Type nsmiscdata_type;
|
||||
CommandNSSetMisc commandnssetmisc;
|
||||
CommandNSSASetMisc commandnssasetmisc;
|
||||
Serialize::Type nsmiscdata_type;
|
||||
|
||||
public:
|
||||
NSSetMisc(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
nsmiscdata_type("NSMiscData", NSMiscData::Unserialize), commandnssetmisc(this), commandnssasetmisc(this)
|
||||
commandnssetmisc(this), commandnssasetmisc(this), nsmiscdata_type("NSMiscData", NSMiscData::Unserialize)
|
||||
{
|
||||
me = this;
|
||||
}
|
||||
|
||||
~NSSetMisc()
|
||||
{
|
||||
for (Anope::map<ExtensibleItem<NSMiscData> *>::iterator it = items.begin(); it != items.end(); ++it)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
descriptions.clear();
|
||||
|
||||
@@ -10,17 +10,17 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/ns_suspend.h"
|
||||
#include "modules/suspend.h"
|
||||
|
||||
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
|
||||
|
||||
struct NSSuspendInfoImpl : NSSuspendInfo, Serializable
|
||||
struct NSSuspendInfo : SuspendInfo, Serializable
|
||||
{
|
||||
NSSuspendInfoImpl(Extensible *) : Serializable("NSSuspendInfo") { }
|
||||
NSSuspendInfo(Extensible *) : Serializable("NSSuspendInfo") { }
|
||||
|
||||
void Serialize(Serialize::Data &data) const anope_override
|
||||
{
|
||||
data["nick"] << nick;
|
||||
data["nick"] << what;
|
||||
data["by"] << by;
|
||||
data["reason"] << reason;
|
||||
data["time"] << when;
|
||||
@@ -32,16 +32,16 @@ struct NSSuspendInfoImpl : NSSuspendInfo, Serializable
|
||||
Anope::string snick;
|
||||
data["nick"] >> snick;
|
||||
|
||||
NSSuspendInfoImpl *si;
|
||||
NSSuspendInfo *si;
|
||||
if (obj)
|
||||
si = anope_dynamic_static_cast<NSSuspendInfoImpl *>(obj);
|
||||
si = anope_dynamic_static_cast<NSSuspendInfo *>(obj);
|
||||
else
|
||||
{
|
||||
NickAlias *na = NickAlias::Find(snick);
|
||||
if (!na)
|
||||
return NULL;
|
||||
si = na->nc->Extend<NSSuspendInfoImpl>("NS_SUSPENDED");
|
||||
data["nick"] >> si->nick;
|
||||
si = na->nc->Extend<NSSuspendInfo>("NS_SUSPENDED");
|
||||
data["nick"] >> si->what;
|
||||
}
|
||||
|
||||
data["by"] >> si->by;
|
||||
@@ -110,7 +110,7 @@ class CommandNSSuspend : public Command
|
||||
NickCore *nc = na->nc;
|
||||
|
||||
NSSuspendInfo *si = nc->Extend<NSSuspendInfo>("NS_SUSPENDED");
|
||||
si->nick = nc->display;
|
||||
si->what = nc->display;
|
||||
si->by = source.GetNick();
|
||||
si->reason = reason;
|
||||
si->when = Anope::CurTime;
|
||||
@@ -181,9 +181,12 @@ class CommandNSUnSuspend : public Command
|
||||
return;
|
||||
}
|
||||
|
||||
NSSuspendInfo *si = na->nc->GetExt<NSSuspendInfo>("NS_SUSPENDED");
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "for " << na->nick << " which was suspended by " << (!si->by.empty() ? si->by : "(none)") << " for: " << (!si->reason.empty() ? si->reason : "No reason");
|
||||
|
||||
na->nc->Shrink<NSSuspendInfo>("NS_SUSPENDED");
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "for " << na->nick;
|
||||
source.Reply(_("Nick %s is now released."), nick.c_str());
|
||||
|
||||
FOREACH_MOD(OnNickUnsuspended, (na));
|
||||
@@ -202,13 +205,13 @@ class NSSuspend : public Module
|
||||
{
|
||||
CommandNSSuspend commandnssuspend;
|
||||
CommandNSUnSuspend commandnsunsuspend;
|
||||
ExtensibleItem<NSSuspendInfoImpl> suspend;
|
||||
ExtensibleItem<NSSuspendInfo> suspend;
|
||||
Serialize::Type suspend_type;
|
||||
|
||||
public:
|
||||
NSSuspend(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
commandnssuspend(this), commandnsunsuspend(this), suspend(this, "NS_SUSPENDED"),
|
||||
suspend_type("NSSuspendInfo", NSSuspendInfoImpl::Unserialize)
|
||||
suspend_type("NSSuspendInfo", NSSuspendInfo::Unserialize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -322,6 +322,12 @@ class CommandOSDNS : public Command
|
||||
s->zones.erase(z->name);
|
||||
}
|
||||
|
||||
if (dnsmanager)
|
||||
{
|
||||
dnsmanager->UpdateSerial();
|
||||
dnsmanager->Notify(z->name);
|
||||
}
|
||||
|
||||
source.Reply(_("Zone %s removed."), z->name.c_str());
|
||||
delete z;
|
||||
}
|
||||
@@ -357,6 +363,12 @@ class CommandOSDNS : public Command
|
||||
z->servers.insert(s->GetName());
|
||||
s->zones.insert(zone);
|
||||
|
||||
if (dnsmanager)
|
||||
{
|
||||
dnsmanager->UpdateSerial();
|
||||
dnsmanager->Notify(zone);
|
||||
}
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to add server " << s->GetName() << " to zone " << z->name;
|
||||
|
||||
source.Reply(_("Server %s added to zone %s."), s->GetName().c_str(), z->name.c_str());
|
||||
@@ -398,6 +410,12 @@ class CommandOSDNS : public Command
|
||||
|
||||
z->servers.insert(s->GetName());
|
||||
s->zones.insert(z->name);
|
||||
|
||||
if (dnsmanager)
|
||||
{
|
||||
dnsmanager->UpdateSerial();
|
||||
dnsmanager->Notify(z->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,6 +448,12 @@ class CommandOSDNS : public Command
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to remove server " << s->GetName() << " from zone " << z->name;
|
||||
|
||||
if (dnsmanager)
|
||||
{
|
||||
dnsmanager->UpdateSerial();
|
||||
dnsmanager->Notify(z->name);
|
||||
}
|
||||
|
||||
z->servers.erase(s->GetName());
|
||||
source.Reply(_("Removed server %s from zone %s."), s->GetName().c_str(), z->name.c_str());
|
||||
return;
|
||||
@@ -450,6 +474,9 @@ class CommandOSDNS : public Command
|
||||
if (Anope::ReadOnly)
|
||||
source.Reply(READ_ONLY_MODE);
|
||||
|
||||
if (dnsmanager)
|
||||
dnsmanager->UpdateSerial();
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to delete server " << s->GetName();
|
||||
source.Reply(_("Removed server %s."), s->GetName().c_str());
|
||||
delete s;
|
||||
|
||||
@@ -14,6 +14,51 @@
|
||||
|
||||
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
|
||||
|
||||
struct ForbidDataImpl : ForbidData, Serializable
|
||||
{
|
||||
ForbidDataImpl() : Serializable("ForbidData") { }
|
||||
void Serialize(Serialize::Data &data) const anope_override;
|
||||
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
|
||||
};
|
||||
|
||||
void ForbidDataImpl::Serialize(Serialize::Data &data) const
|
||||
{
|
||||
data["mask"] << this->mask;
|
||||
data["creator"] << this->creator;
|
||||
data["reason"] << this->reason;
|
||||
data["created"] << this->created;
|
||||
data["expires"] << this->expires;
|
||||
data["type"] << this->type;
|
||||
}
|
||||
|
||||
Serializable* ForbidDataImpl::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
{
|
||||
if (!forbid_service)
|
||||
return NULL;
|
||||
|
||||
ForbidDataImpl *fb;
|
||||
if (obj)
|
||||
fb = anope_dynamic_static_cast<ForbidDataImpl *>(obj);
|
||||
else
|
||||
fb = new ForbidDataImpl();
|
||||
|
||||
data["mask"] >> fb->mask;
|
||||
data["creator"] >> fb->creator;
|
||||
data["reason"] >> fb->reason;
|
||||
data["created"] >> fb->created;
|
||||
data["expires"] >> fb->expires;
|
||||
unsigned int t;
|
||||
data["type"] >> t;
|
||||
fb->type = static_cast<ForbidType>(t);
|
||||
|
||||
if (t > FT_SIZE - 1)
|
||||
return NULL;
|
||||
|
||||
if (!obj)
|
||||
forbid_service->AddForbid(fb);
|
||||
return fb;
|
||||
}
|
||||
|
||||
class MyForbidService : public ForbidService
|
||||
{
|
||||
Serialize::Checker<std::vector<ForbidData *>[FT_SIZE - 1]> forbid_data;
|
||||
@@ -43,6 +88,11 @@ class MyForbidService : public ForbidService
|
||||
delete d;
|
||||
}
|
||||
|
||||
ForbidData *CreateForbid() anope_override
|
||||
{
|
||||
return new ForbidDataImpl();
|
||||
}
|
||||
|
||||
ForbidData *FindForbid(const Anope::string &mask, ForbidType ftype) anope_override
|
||||
{
|
||||
for (unsigned i = this->forbids(ftype).size(); i > 0; --i)
|
||||
@@ -157,7 +207,7 @@ class CommandOSForbid : public Command
|
||||
bool created = false;
|
||||
if (d == NULL)
|
||||
{
|
||||
d = new ForbidData();
|
||||
d = new ForbidDataImpl();
|
||||
created = true;
|
||||
}
|
||||
|
||||
@@ -379,7 +429,7 @@ class OSForbid : public Module
|
||||
|
||||
public:
|
||||
OSForbid(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
forbidService(this), forbiddata_type("ForbidData", ForbidData::Unserialize), commandosforbid(this)
|
||||
forbidService(this), forbiddata_type("ForbidData", ForbidDataImpl::Unserialize), commandosforbid(this)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
+104
-60
@@ -12,61 +12,94 @@
|
||||
#include "module.h"
|
||||
#include "modules/os_ignore.h"
|
||||
|
||||
struct IgnoreDataImpl : IgnoreData, Serializable
|
||||
{
|
||||
IgnoreDataImpl() : Serializable("IgnoreData") { }
|
||||
~IgnoreDataImpl();
|
||||
void Serialize(Serialize::Data &data) const anope_override;
|
||||
static Serializable* Unserialize(Serializable *obj, Serialize::Data &data);
|
||||
};
|
||||
|
||||
IgnoreDataImpl::~IgnoreDataImpl()
|
||||
{
|
||||
if (ignore_service)
|
||||
ignore_service->DelIgnore(this);
|
||||
}
|
||||
|
||||
void IgnoreDataImpl::Serialize(Serialize::Data &data) const
|
||||
{
|
||||
data["mask"] << this->mask;
|
||||
data["creator"] << this->creator;
|
||||
data["reason"] << this->reason;
|
||||
data["time"] << this->time;
|
||||
}
|
||||
|
||||
Serializable* IgnoreDataImpl::Unserialize(Serializable *obj, Serialize::Data &data)
|
||||
{
|
||||
if (!ignore_service)
|
||||
return NULL;
|
||||
|
||||
IgnoreDataImpl *ign;
|
||||
if (obj)
|
||||
ign = anope_dynamic_static_cast<IgnoreDataImpl *>(obj);
|
||||
else
|
||||
{
|
||||
ign = new IgnoreDataImpl();
|
||||
ignore_service->AddIgnore(ign);
|
||||
}
|
||||
|
||||
data["mask"] >> ign->mask;
|
||||
data["creator"] >> ign->creator;
|
||||
data["reason"] >> ign->reason;
|
||||
data["time"] >> ign->time;
|
||||
|
||||
return ign;
|
||||
}
|
||||
|
||||
|
||||
class OSIgnoreService : public IgnoreService
|
||||
{
|
||||
public:
|
||||
OSIgnoreService(Module *o) : IgnoreService(o) { }
|
||||
Serialize::Checker<std::vector<IgnoreData *> > ignores;
|
||||
|
||||
IgnoreData* AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) anope_override
|
||||
public:
|
||||
OSIgnoreService(Module *o) : IgnoreService(o), ignores("IgnoreData") { }
|
||||
|
||||
void AddIgnore(IgnoreData *ign) anope_override
|
||||
{
|
||||
/* Check if we already got an identical entry. */
|
||||
IgnoreData *ign = this->Find(mask);
|
||||
if (ign != NULL)
|
||||
ignores->push_back(ign);
|
||||
}
|
||||
|
||||
void DelIgnore(IgnoreData *ign) anope_override
|
||||
{
|
||||
std::vector<IgnoreData *>::iterator it = std::find(ignores->begin(), ignores->end(), ign);
|
||||
if (it != ignores->end())
|
||||
ignores->erase(it);
|
||||
}
|
||||
|
||||
void ClearIgnores() anope_override
|
||||
{
|
||||
for (unsigned i = ignores->size(); i > 0; --i)
|
||||
{
|
||||
if (!delta)
|
||||
ign->time = 0;
|
||||
else
|
||||
ign->time = Anope::CurTime + delta;
|
||||
return ign;
|
||||
}
|
||||
/* Create new entry.. */
|
||||
else
|
||||
{
|
||||
IgnoreData newign;
|
||||
newign.mask = mask;
|
||||
newign.creator = creator;
|
||||
newign.reason = reason;
|
||||
newign.time = delta ? Anope::CurTime + delta : 0;
|
||||
this->ignores.push_back(newign);
|
||||
return &this->ignores.back();
|
||||
IgnoreData *ign = ignores->at(i - 1);
|
||||
delete ign;
|
||||
}
|
||||
}
|
||||
|
||||
bool DelIgnore(const Anope::string &mask) anope_override
|
||||
IgnoreData *Create() anope_override
|
||||
{
|
||||
for (std::list<IgnoreData>::iterator it = this->ignores.begin(), it_end = this->ignores.end(); it != it_end; ++it)
|
||||
{
|
||||
IgnoreData &idn = *it;
|
||||
if (idn.mask.equals_ci(mask))
|
||||
{
|
||||
this->ignores.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return new IgnoreDataImpl();
|
||||
}
|
||||
|
||||
IgnoreData *Find(const Anope::string &mask) anope_override
|
||||
{
|
||||
User *u = User::Find(mask, true);
|
||||
std::list<IgnoreData>::iterator ign = this->ignores.begin(), ign_end = this->ignores.end();
|
||||
std::vector<IgnoreData *>::iterator ign = this->ignores->begin(), ign_end = this->ignores->end();
|
||||
|
||||
if (u)
|
||||
{
|
||||
for (; ign != ign_end; ++ign)
|
||||
{
|
||||
Entry ignore_mask("", ign->mask);
|
||||
Entry ignore_mask("", (*ign)->mask);
|
||||
if (ignore_mask.Matches(u, true))
|
||||
break;
|
||||
}
|
||||
@@ -94,26 +127,31 @@ class OSIgnoreService : public IgnoreService
|
||||
tmp = mask + "!*@*";
|
||||
|
||||
for (; ign != ign_end; ++ign)
|
||||
if (Anope::Match(tmp, ign->mask, false, true))
|
||||
if (Anope::Match(tmp, (*ign)->mask, false, true))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check whether the entry has timed out */
|
||||
if (ign != ign_end)
|
||||
{
|
||||
IgnoreData &id = *ign;
|
||||
IgnoreData *id = *ign;
|
||||
|
||||
if (id.time && !Anope::NoExpire && id.time <= Anope::CurTime)
|
||||
if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime)
|
||||
{
|
||||
Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id.mask;
|
||||
this->ignores.erase(ign);
|
||||
Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask;
|
||||
delete id;
|
||||
}
|
||||
else
|
||||
return &id;
|
||||
return id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<IgnoreData *> &GetIgnores() anope_override
|
||||
{
|
||||
return *ignores;
|
||||
}
|
||||
};
|
||||
|
||||
class CommandOSIgnore : public Command
|
||||
@@ -183,7 +221,13 @@ class CommandOSIgnore : public Command
|
||||
if (Anope::ReadOnly)
|
||||
source.Reply(READ_ONLY_MODE);
|
||||
|
||||
ignore_service->AddIgnore(mask, source.GetNick(), reason, t);
|
||||
IgnoreData *ign = new IgnoreDataImpl();
|
||||
ign->mask = mask;
|
||||
ign->creator = source.GetNick();
|
||||
ign->reason = reason;
|
||||
ign->time = t ? Anope::CurTime + t : 0;
|
||||
|
||||
ignore_service->AddIgnore(ign);
|
||||
if (!t)
|
||||
{
|
||||
source.Reply(_("\002%s\002 will now permanently be ignored."), mask.c_str());
|
||||
@@ -202,18 +246,15 @@ class CommandOSIgnore : public Command
|
||||
if (!ignore_service)
|
||||
return;
|
||||
|
||||
std::list<IgnoreData> &ignores = ignore_service->GetIgnores();
|
||||
|
||||
for (std::list<IgnoreData>::iterator it = ignores.begin(), next_it; it != ignores.end(); it = next_it)
|
||||
std::vector<IgnoreData *> &ignores = ignore_service->GetIgnores();
|
||||
for (unsigned i = ignores.size(); i > 0; --i)
|
||||
{
|
||||
IgnoreData &id = *it;
|
||||
next_it = it;
|
||||
++next_it;
|
||||
IgnoreData *id = ignores[i - 1];
|
||||
|
||||
if (id.time && !Anope::NoExpire && id.time <= Anope::CurTime)
|
||||
if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime)
|
||||
{
|
||||
Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id.mask;
|
||||
ignores.erase(it);
|
||||
Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask;
|
||||
delete id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,15 +264,16 @@ class CommandOSIgnore : public Command
|
||||
{
|
||||
ListFormatter list(source.GetAccount());
|
||||
list.AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Reason")).AddColumn(_("Expires"));
|
||||
for (std::list<IgnoreData>::const_iterator ign = ignores.begin(), ign_end = ignores.end(); ign != ign_end; ++ign)
|
||||
|
||||
for (unsigned i = ignores.size(); i > 0; --i)
|
||||
{
|
||||
const IgnoreData &ignore = *ign;
|
||||
const IgnoreData *ignore = ignores[i - 1];
|
||||
|
||||
ListFormatter::ListEntry entry;
|
||||
entry["Mask"] = ignore.mask;
|
||||
entry["Creator"] = ignore.creator;
|
||||
entry["Reason"] = ignore.reason;
|
||||
entry["Expires"] = Anope::Expires(ignore.time, source.GetAccount());
|
||||
entry["Mask"] = ignore->mask;
|
||||
entry["Creator"] = ignore->creator;
|
||||
entry["Reason"] = ignore->reason;
|
||||
entry["Expires"] = Anope::Expires(ignore->time, source.GetAccount());
|
||||
list.AddEntry(entry);
|
||||
}
|
||||
|
||||
@@ -264,13 +306,15 @@ class CommandOSIgnore : public Command
|
||||
return;
|
||||
}
|
||||
|
||||
if (ignore_service->DelIgnore(mask))
|
||||
IgnoreData *ign = ignore_service->Find(mask);
|
||||
if (ign)
|
||||
{
|
||||
if (Anope::ReadOnly)
|
||||
source.Reply(READ_ONLY_MODE);
|
||||
|
||||
Log(LOG_ADMIN, source, this) << "to remove an ignore on " << mask;
|
||||
source.Reply(_("\002%s\002 will no longer be ignored."), mask.c_str());
|
||||
delete ign;
|
||||
}
|
||||
else
|
||||
source.Reply(_("\002%s\002 not found on ignore list."), mask.c_str());
|
||||
@@ -355,7 +399,7 @@ class OSIgnore : public Module
|
||||
|
||||
public:
|
||||
OSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
ignoredata_type("IgnoreData", IgnoreData::Unserialize), osignoreservice(this), commandosignore(this)
|
||||
ignoredata_type("IgnoreData", IgnoreDataImpl::Unserialize), osignoreservice(this), commandosignore(this)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ class CommandOSModList : public Command
|
||||
CommandOSModList(Module *creator) : Command(creator, "operserv/modlist", 0, 1)
|
||||
{
|
||||
this->SetDesc(_("List loaded modules"));
|
||||
this->SetSyntax(_("[all|third|vendor|database|encryption|pseudoclient|protocol]"));
|
||||
this->SetSyntax("[all|third|vendor|extra|database|encryption|pseudoclient|protocol]");
|
||||
}
|
||||
|
||||
void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
||||
@@ -90,14 +90,16 @@ class CommandOSModList : public Command
|
||||
else
|
||||
Log(LOG_ADMIN, source, this);
|
||||
|
||||
bool third = false, extra = false, vendor = false, database = false, encryption = false, pseudoclient = false, protocol = false;
|
||||
bool third = false, vendor = false, extra = false, database = false, encryption = false, pseudoclient = false, protocol = false;
|
||||
|
||||
if (param.equals_ci("all"))
|
||||
third = extra = vendor = database = encryption = pseudoclient = protocol = true;
|
||||
third = vendor = extra = database = encryption = pseudoclient = protocol = true;
|
||||
else if (param.equals_ci("third"))
|
||||
third = true;
|
||||
else if (param.equals_ci("vendor"))
|
||||
vendor = true;
|
||||
else if (param.equals_ci("extra"))
|
||||
extra = true;
|
||||
else if (param.equals_ci("database"))
|
||||
database = true;
|
||||
else if (param.equals_ci("encryption"))
|
||||
@@ -108,7 +110,7 @@ class CommandOSModList : public Command
|
||||
protocol = true;
|
||||
else
|
||||
third = extra = database = encryption = protocol = true;
|
||||
|
||||
|
||||
Module *protomod = ModuleManager::FindFirstOf(PROTOCOL);
|
||||
|
||||
source.Reply(_("Current module list:"));
|
||||
@@ -149,13 +151,6 @@ class CommandOSModList : public Command
|
||||
mtype += ", ";
|
||||
mtype += "Database";
|
||||
}
|
||||
if (m->type & VENDOR)
|
||||
{
|
||||
show |= vendor;
|
||||
if (!mtype.empty())
|
||||
mtype += ", ";
|
||||
mtype += "Vendor";
|
||||
}
|
||||
if (m->type & EXTRA)
|
||||
{
|
||||
show |= extra;
|
||||
@@ -163,6 +158,13 @@ class CommandOSModList : public Command
|
||||
mtype += ", ";
|
||||
mtype += "Extra";
|
||||
}
|
||||
if (m->type & VENDOR)
|
||||
{
|
||||
show |= vendor;
|
||||
if (!mtype.empty())
|
||||
mtype += ", ";
|
||||
mtype += "Vendor";
|
||||
}
|
||||
if (m->type & THIRD)
|
||||
{
|
||||
show |= third;
|
||||
|
||||
@@ -668,7 +668,7 @@ class OSSession : public Module
|
||||
if (u->Quitting() || !session_limit || exempt || !u->server || u->server->IsULined())
|
||||
return;
|
||||
|
||||
cidr u_ip(u->ip);
|
||||
cidr u_ip(u->ip, u->ip.find(':') != Anope::string::npos ? ipv6_cidr : ipv4_cidr);
|
||||
if (!u_ip.valid())
|
||||
return;
|
||||
|
||||
@@ -767,7 +767,7 @@ class OSSession : public Module
|
||||
if (!e->expires || e->expires > Anope::CurTime)
|
||||
continue;
|
||||
BotInfo *OperServ = Config->GetClient("OperServ");
|
||||
Log(OperServ, "expire/exception") << "Session exception for " << e->mask << "has expired.";
|
||||
Log(OperServ, "expire/exception") << "Session exception for " << e->mask << " has expired.";
|
||||
this->ss.DelException(e);
|
||||
delete e;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class CommandOSSVSJoin : public Command
|
||||
Channel *c = Channel::Find(params[1]);
|
||||
if (target == NULL)
|
||||
source.Reply(NICK_X_NOT_IN_USE, params[0].c_str());
|
||||
else if (target->IsProtected() || target->server == Me)
|
||||
else if (source.GetUser() != target && (target->IsProtected() || target->server == Me))
|
||||
source.Reply(ACCESS_DENIED);
|
||||
else if (!IRCD->IsChannelValid(params[1]))
|
||||
source.Reply(CHAN_X_INVALID, params[1].c_str());
|
||||
@@ -135,7 +135,7 @@ class CommandOSSVSPart : public Command
|
||||
Channel *c = Channel::Find(params[1]);
|
||||
if (target == NULL)
|
||||
source.Reply(NICK_X_NOT_IN_USE, params[0].c_str());
|
||||
else if (target->IsProtected() || target->server == Me)
|
||||
else if (source.GetUser() != target && (target->IsProtected() || target->server == Me))
|
||||
source.Reply(ACCESS_DENIED);
|
||||
else if (!c)
|
||||
source.Reply(CHAN_X_NOT_IN_USE, params[1].c_str());
|
||||
|
||||
@@ -221,7 +221,7 @@ class DBFlatFile : public Module, public Pipe
|
||||
|
||||
const Anope::string &db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db");
|
||||
|
||||
std::fstream fd(db_name.c_str(), std::ios_base::in);
|
||||
std::fstream fd(db_name.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
if (!fd.is_open())
|
||||
{
|
||||
Log(this) << "Unable to open " << db_name << " for reading!";
|
||||
@@ -310,7 +310,7 @@ class DBFlatFile : public Module, public Pipe
|
||||
if (Anope::IsFile(db_name))
|
||||
rename(db_name.c_str(), (db_name + ".tmp").c_str());
|
||||
|
||||
std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream(db_name.c_str(), std::ios_base::out | std::ios_base::trunc);
|
||||
std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream(db_name.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
|
||||
|
||||
if (!fs->is_open())
|
||||
Log(this) << "Unable to open " << db_name << " for writing";
|
||||
@@ -382,7 +382,7 @@ class DBFlatFile : public Module, public Pipe
|
||||
else
|
||||
db_name = Anope::DataDir + "/" + Config->GetModule(this)->Get<const Anope::string>("database", "anope.db");
|
||||
|
||||
std::fstream fd(db_name.c_str(), std::ios_base::in);
|
||||
std::fstream fd(db_name.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
if (!fd.is_open())
|
||||
{
|
||||
Log(this) << "Unable to open " << db_name << " for reading!";
|
||||
|
||||
+159
-21
@@ -14,6 +14,9 @@
|
||||
#include "modules/cs_mode.h"
|
||||
#include "modules/bs_badwords.h"
|
||||
#include "modules/os_news.h"
|
||||
#include "modules/suspend.h"
|
||||
#include "modules/os_forbid.h"
|
||||
#include "modules/cs_entrymsg.h"
|
||||
|
||||
#define READ(x) \
|
||||
if (true) \
|
||||
@@ -48,6 +51,7 @@ else \
|
||||
#define OLD_NI_AUTOOP 0x00080000 /* Autoop nickname in channels */
|
||||
|
||||
#define OLD_NS_NO_EXPIRE 0x0004 /* nick won't expire */
|
||||
#define OLD_NS_VERBOTEN 0x0002
|
||||
|
||||
#define OLD_CI_KEEPTOPIC 0x00000001
|
||||
#define OLD_CI_SECUREOPS 0x00000002
|
||||
@@ -56,7 +60,7 @@ else \
|
||||
#define OLD_CI_RESTRICTED 0x00000010
|
||||
#define OLD_CI_PEACE 0x00000020
|
||||
#define OLD_CI_SECURE 0x00000040
|
||||
#define OLD_CI_FORBIDDEN 0x00000080
|
||||
#define OLD_CI_VERBOTEN 0x00000080
|
||||
#define OLD_CI_ENCRYPTEDPW 0x00000100
|
||||
#define OLD_CI_NO_EXPIRE 0x00000200
|
||||
#define OLD_CI_MEMO_HARDMAX 0x00000400
|
||||
@@ -138,7 +142,7 @@ enum
|
||||
LANG_PL /* Polish */
|
||||
};
|
||||
|
||||
static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status)
|
||||
static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status, uint32_t *limit, Anope::string *key)
|
||||
{
|
||||
ModeLocks *ml = ci->Require<ModeLocks>("modelocks");
|
||||
for (unsigned i = 0; i < (sizeof(mlock_infos) / sizeof(mlock_info)); ++i)
|
||||
@@ -146,7 +150,14 @@ static void process_mlock(ChannelInfo *ci, uint32_t lock, bool status)
|
||||
{
|
||||
ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock_infos[i].c);
|
||||
if (cm && ml)
|
||||
ml->SetMLock(cm, status);
|
||||
{
|
||||
if (limit && mlock_infos[i].c == 'l')
|
||||
ml->SetMLock(cm, status, stringify(*limit));
|
||||
else if (key && mlock_infos[i].c == 'k')
|
||||
ml->SetMLock(cm, status, *key);
|
||||
else
|
||||
ml->SetMLock(cm, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,6 +434,7 @@ int read_int32(int32_t *ret, dbFILE *f)
|
||||
|
||||
static void LoadNicks()
|
||||
{
|
||||
ServiceReference<ForbidService> forbid("ForbidService", "forbid");
|
||||
dbFILE *f = open_db_read("NickServ", "nick.db", 14);
|
||||
if (f == NULL)
|
||||
return;
|
||||
@@ -441,7 +453,7 @@ static void LoadNicks()
|
||||
|
||||
char pwbuf[32];
|
||||
READ(read_buffer(pwbuf, f));
|
||||
if (hashm == "none")
|
||||
if (hashm == "plain")
|
||||
my_b64_encode(pwbuf, nc->pass);
|
||||
else if (hashm == "md5" || hashm == "oldmd5")
|
||||
nc->pass = Hex(pwbuf, 16);
|
||||
@@ -495,7 +507,12 @@ static void LoadNicks()
|
||||
if (u32 & OLD_NI_HIDE_STATUS)
|
||||
nc->Extend<bool>("HIDE_STATUS");
|
||||
if (u32 & OLD_NI_SUSPENDED)
|
||||
nc->Extend<bool>("NS_SUSPENDED");
|
||||
{
|
||||
SuspendInfo si;
|
||||
si.what = nc->display;
|
||||
si.when = si.expires = 0;
|
||||
nc->Extend("NS_SUSPENDED", si);
|
||||
}
|
||||
if (!(u32 & OLD_NI_AUTOOP))
|
||||
nc->Extend<bool>("AUTOOP");
|
||||
|
||||
@@ -607,6 +624,33 @@ static void LoadNicks()
|
||||
Log() << "Skipping coreless nick " << nick << " with core " << core;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tmpu16 & OLD_NS_VERBOTEN)
|
||||
{
|
||||
if (!forbid)
|
||||
{
|
||||
delete nc;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nc->display.find_first_of("?*") != Anope::string::npos)
|
||||
{
|
||||
delete nc;
|
||||
continue;
|
||||
}
|
||||
|
||||
ForbidData *d = forbid->CreateForbid();
|
||||
d->mask = nc->display;
|
||||
d->creator = last_usermask;
|
||||
d->reason = last_realname;
|
||||
d->expires = 0;
|
||||
d->created = 0;
|
||||
d->type = FT_NICK;
|
||||
delete nc;
|
||||
forbid->AddForbid(d);
|
||||
continue;
|
||||
}
|
||||
|
||||
NickAlias *na = new NickAlias(nick, nc);
|
||||
na->last_usermask = last_usermask;
|
||||
na->last_realname = last_realname;
|
||||
@@ -691,6 +735,7 @@ static void LoadBots()
|
||||
|
||||
static void LoadChannels()
|
||||
{
|
||||
ServiceReference<ForbidService> forbid("ForbidService", "forbid");
|
||||
dbFILE *f = open_db_read("ChanServ", "chan.db", 16);
|
||||
if (f == NULL)
|
||||
return;
|
||||
@@ -755,7 +800,7 @@ static void LoadChannels()
|
||||
if (tmpu32 & OLD_CI_SECURE)
|
||||
ci->Extend<bool>("CS_SECURE");
|
||||
if (tmpu32 & OLD_CI_NO_EXPIRE)
|
||||
ci->Extend<bool>("CI_NO_EXPIRE");
|
||||
ci->Extend<bool>("CS_NO_EXPIRE");
|
||||
if (tmpu32 & OLD_CI_MEMO_HARDMAX)
|
||||
ci->Extend<bool>("MEMO_HARDMAX");
|
||||
if (tmpu32 & OLD_CI_SECUREFOUNDER)
|
||||
@@ -764,11 +809,20 @@ static void LoadChannels()
|
||||
ci->Extend<bool>("SIGNKICK");
|
||||
if (tmpu32 & OLD_CI_SIGNKICK_LEVEL)
|
||||
ci->Extend<bool>("SIGNKICK_LEVEL");
|
||||
if (tmpu32 & OLD_CI_SUSPENDED)
|
||||
ci->Extend<bool>("CS_SUSPENDED");
|
||||
|
||||
READ(read_string(buffer, f));
|
||||
READ(read_string(buffer, f));
|
||||
Anope::string forbidby, forbidreason;
|
||||
READ(read_string(forbidby, f));
|
||||
READ(read_string(forbidreason, f));
|
||||
if (tmpu32 & OLD_CI_SUSPENDED)
|
||||
{
|
||||
SuspendInfo si;
|
||||
si.what = ci->name;
|
||||
si.by = forbidby;
|
||||
si.reason = forbidreason;
|
||||
si.when = si.expires = 0;
|
||||
ci->Extend("CS_SUSPENDED", si);
|
||||
}
|
||||
bool forbid_chan = tmpu32 & OLD_CI_VERBOTEN;
|
||||
|
||||
int16_t tmp16;
|
||||
READ(read_int16(&tmp16, f));
|
||||
@@ -791,7 +845,8 @@ static void LoadChannels()
|
||||
ci->SetLevel(GetLevelName(j), level);
|
||||
}
|
||||
|
||||
ServiceReference<AccessProvider> provider("AccessProvider", "access/access");
|
||||
bool xop = tmpu32 & OLD_CI_XOP;
|
||||
ServiceReference<AccessProvider> provider_access("AccessProvider", "access/access"), provider_xop("AccessProvider", "access/xop");
|
||||
uint16_t tmpu16;
|
||||
READ(read_uint16(&tmpu16, f));
|
||||
for (uint16_t j = 0; j < tmpu16; ++j)
|
||||
@@ -800,14 +855,45 @@ static void LoadChannels()
|
||||
READ(read_uint16(&in_use, f));
|
||||
if (in_use)
|
||||
{
|
||||
ChanAccess *access = provider ? provider->Create() : NULL;
|
||||
ChanAccess *access = NULL;
|
||||
|
||||
if (xop)
|
||||
{
|
||||
if (provider_xop)
|
||||
access = provider_xop->Create();
|
||||
}
|
||||
else
|
||||
if (provider_access)
|
||||
access = provider_access->Create();
|
||||
|
||||
if (access)
|
||||
access->ci = ci;
|
||||
|
||||
int16_t level;
|
||||
READ(read_int16(&level, f));
|
||||
if (access)
|
||||
access->AccessUnserialize(stringify(level));
|
||||
{
|
||||
if (xop)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case 3:
|
||||
access->AccessUnserialize("VOP");
|
||||
break;
|
||||
case 4:
|
||||
access->AccessUnserialize("HOP");
|
||||
break;
|
||||
case 5:
|
||||
access->AccessUnserialize("AOP");
|
||||
break;
|
||||
case 10:
|
||||
access->AccessUnserialize("SOP");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
access->AccessUnserialize(stringify(level));
|
||||
}
|
||||
|
||||
Anope::string mask;
|
||||
READ(read_string(mask, f));
|
||||
@@ -848,9 +934,11 @@ static void LoadChannels()
|
||||
READ(read_uint32(&tmpu32, f)); // mlock off
|
||||
ci->Extend<uint32_t>("mlock_off", tmpu32);
|
||||
READ(read_uint32(&tmpu32, f)); // mlock limit
|
||||
READ(read_string(buffer, f));
|
||||
READ(read_string(buffer, f));
|
||||
READ(read_string(buffer, f));
|
||||
ci->Extend<uint32_t>("mlock_limit", tmpu32);
|
||||
READ(read_string(buffer, f)); // key
|
||||
ci->Extend<Anope::string>("mlock_key", buffer);
|
||||
READ(read_string(buffer, f)); // +f
|
||||
READ(read_string(buffer, f)); // +L
|
||||
|
||||
READ(read_int16(&tmp16, f));
|
||||
READ(read_int16(&ci->memos.memomax, f));
|
||||
@@ -870,6 +958,21 @@ static void LoadChannels()
|
||||
}
|
||||
|
||||
READ(read_string(buffer, f));
|
||||
if (!buffer.empty())
|
||||
{
|
||||
EntryMessageList *eml = ci->Require<EntryMessageList>("entrymsg");
|
||||
if (eml)
|
||||
{
|
||||
EntryMsg *e = eml->Create();
|
||||
|
||||
e->chan = ci->name;
|
||||
e->creator = "Unknown";
|
||||
e->message = buffer;
|
||||
e->when = Anope::CurTime;
|
||||
|
||||
(*eml)->push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
READ(read_string(buffer, f));
|
||||
ci->bi = BotInfo::Find(buffer);
|
||||
@@ -957,6 +1060,32 @@ static void LoadChannels()
|
||||
}
|
||||
}
|
||||
|
||||
if (forbid_chan)
|
||||
{
|
||||
if (!forbid)
|
||||
{
|
||||
delete ci;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ci->name.find_first_of("?*") != Anope::string::npos)
|
||||
{
|
||||
delete ci;
|
||||
continue;
|
||||
}
|
||||
|
||||
ForbidData *d = forbid->CreateForbid();
|
||||
d->mask = ci->name;
|
||||
d->creator = forbidby;
|
||||
d->reason = forbidreason;
|
||||
d->expires = 0;
|
||||
d->created = 0;
|
||||
d->type = FT_CHAN;
|
||||
delete ci;
|
||||
forbid->AddForbid(d);
|
||||
continue;
|
||||
}
|
||||
|
||||
Log(LOG_DEBUG) << "Loaded channel " << ci->name;
|
||||
}
|
||||
|
||||
@@ -1166,17 +1295,18 @@ static void LoadNews()
|
||||
|
||||
class DBOld : public Module
|
||||
{
|
||||
PrimitiveExtensibleItem<uint32_t> mlock_on, mlock_off;
|
||||
PrimitiveExtensibleItem<uint32_t> mlock_on, mlock_off, mlock_limit;
|
||||
PrimitiveExtensibleItem<Anope::string> mlock_key;
|
||||
|
||||
public:
|
||||
DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR),
|
||||
mlock_on(this, "mlock_on"), mlock_off(this, "mlock_off")
|
||||
mlock_on(this, "mlock_on"), mlock_off(this, "mlock_off"), mlock_limit(this, "mlock_limit"), mlock_key(this, "mlock_key")
|
||||
{
|
||||
|
||||
|
||||
hashm = Config->GetModule(this)->Get<const Anope::string>("hash");
|
||||
|
||||
if (hashm != "md5" && hashm != "oldmd5" && hashm != "sha1" && hashm != "none" && hashm != "sha256")
|
||||
if (hashm != "md5" && hashm != "oldmd5" && hashm != "sha1" && hashm != "plain" && hashm != "sha256")
|
||||
throw ModuleException("Invalid hash method");
|
||||
}
|
||||
|
||||
@@ -1198,20 +1328,28 @@ class DBOld : public Module
|
||||
for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it)
|
||||
{
|
||||
ChannelInfo *ci = it->second;
|
||||
uint32_t *limit = mlock_limit.Get(ci);
|
||||
Anope::string *key = mlock_key.Get(ci);
|
||||
|
||||
uint32_t *u = mlock_on.Get(ci);
|
||||
if (u)
|
||||
{
|
||||
process_mlock(ci, *u, true);
|
||||
process_mlock(ci, *u, true, limit, key);
|
||||
mlock_on.Unset(ci);
|
||||
}
|
||||
|
||||
u = mlock_off.Get(ci);
|
||||
if (u)
|
||||
{
|
||||
process_mlock(ci, *u, false);
|
||||
process_mlock(ci, *u, false, limit, key);
|
||||
mlock_off.Unset(ci);
|
||||
}
|
||||
|
||||
mlock_limit.Unset(ci);
|
||||
mlock_key.Unset(ci);
|
||||
|
||||
if (ci->c)
|
||||
ci->c->CheckModes();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,962 @@
|
||||
/* Module for providing bcrypt hashing
|
||||
*
|
||||
* (C) 2003-2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* This program is free but copyrighted software; see the file COPYING for
|
||||
* details.
|
||||
*
|
||||
* Most of the code in this file is taken from
|
||||
* http://openwall.com/crypt/crypt_blowfish-1.2.tar.gz
|
||||
*/
|
||||
|
||||
/*
|
||||
* The crypt_blowfish homepage is:
|
||||
*
|
||||
* http://www.openwall.com/crypt/
|
||||
*
|
||||
* This code comes from John the Ripper password cracker, with reentrant
|
||||
* and crypt(3) interfaces added, but optimizations specific to password
|
||||
* cracking removed.
|
||||
*
|
||||
* Written by Solar Designer <solar at openwall.com> in 1998-2011.
|
||||
* No copyright is claimed, and the software is hereby placed in the public
|
||||
* domain. In case this attempt to disclaim copyright and place the software
|
||||
* in the public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 1998-2011 Solar Designer and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* It is my intent that you should be able to use this on your system,
|
||||
* as part of a software package, or anywhere else to improve security,
|
||||
* ensure compatibility, or for any other purpose. I would appreciate
|
||||
* it if you give credit where it is due and keep your modifications in
|
||||
* the public domain as well, but I don't require that in order to let
|
||||
* you place this code and any modifications you make under a license
|
||||
* of your choice.
|
||||
*
|
||||
* This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix
|
||||
* "$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
|
||||
* ideas. The password hashing algorithm was designed by David Mazieres
|
||||
* <dm at lcs.mit.edu>. For more information on the level of compatibility,
|
||||
* prefer refer to the comments in BF_set_key() below and to the included
|
||||
* crypt(3) man page.
|
||||
*
|
||||
* There's a paper on the algorithm that explains its design decisions:
|
||||
*
|
||||
* http://www.usenix.org/events/usenix99/provos.html
|
||||
*
|
||||
* Some of the tricks in BF_ROUND might be inspired by Eric Young's
|
||||
* Blowfish library (I can't be sure if I would think of something if I
|
||||
* hadn't seen his code).
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __i386__
|
||||
#define BF_SCALE 1
|
||||
#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
|
||||
#define BF_SCALE 1
|
||||
#else
|
||||
#define BF_SCALE 0
|
||||
#endif
|
||||
|
||||
typedef unsigned int BF_word;
|
||||
typedef signed int BF_word_signed;
|
||||
|
||||
/* Number of Blowfish rounds, this is also hardcoded into a few places */
|
||||
#define BF_N 16
|
||||
|
||||
typedef BF_word BF_key[BF_N + 2];
|
||||
|
||||
typedef struct {
|
||||
BF_word S[4][0x100];
|
||||
BF_key P;
|
||||
} BF_ctx;
|
||||
|
||||
/*
|
||||
* Magic IV for 64 Blowfish encryptions that we do at the end.
|
||||
* The string is "OrpheanBeholderScryDoubt" on big-endian.
|
||||
*/
|
||||
static BF_word BF_magic_w[6] = {
|
||||
0x4F727068, 0x65616E42, 0x65686F6C,
|
||||
0x64657253, 0x63727944, 0x6F756274
|
||||
};
|
||||
|
||||
/*
|
||||
* P-box and S-box tables initialized with digits of Pi.
|
||||
*/
|
||||
static BF_ctx BF_init_state = {
|
||||
{
|
||||
{
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
||||
}, {
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
||||
}, {
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
||||
}, {
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
}
|
||||
}, {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned char BF_itoa64[64 + 1] =
|
||||
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
static unsigned char BF_atoi64[0x60] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
|
||||
64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
|
||||
64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
|
||||
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
|
||||
};
|
||||
|
||||
#define BF_safe_atoi64(dst, src) \
|
||||
{ \
|
||||
tmp = (unsigned char)(src); \
|
||||
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
|
||||
tmp = BF_atoi64[tmp]; \
|
||||
if (tmp > 63) return -1; \
|
||||
(dst) = tmp; \
|
||||
}
|
||||
|
||||
static int BF_decode(BF_word *dst, const char *src, int size)
|
||||
{
|
||||
unsigned char *dptr = (unsigned char *)dst;
|
||||
unsigned char *end = dptr + size;
|
||||
const unsigned char *sptr = (const unsigned char *)src;
|
||||
unsigned int tmp, c1, c2, c3, c4;
|
||||
|
||||
do {
|
||||
BF_safe_atoi64(c1, *sptr++);
|
||||
BF_safe_atoi64(c2, *sptr++);
|
||||
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
||||
if (dptr >= end) break;
|
||||
|
||||
BF_safe_atoi64(c3, *sptr++);
|
||||
*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
|
||||
if (dptr >= end) break;
|
||||
|
||||
BF_safe_atoi64(c4, *sptr++);
|
||||
*dptr++ = ((c3 & 0x03) << 6) | c4;
|
||||
} while (dptr < end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BF_encode(char *dst, const BF_word *src, int size)
|
||||
{
|
||||
const unsigned char *sptr = (const unsigned char *)src;
|
||||
const unsigned char *end = sptr + size;
|
||||
unsigned char *dptr = (unsigned char *)dst;
|
||||
unsigned int c1, c2;
|
||||
|
||||
do {
|
||||
c1 = *sptr++;
|
||||
*dptr++ = BF_itoa64[c1 >> 2];
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (sptr >= end) {
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *sptr++;
|
||||
c1 |= c2 >> 4;
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (sptr >= end) {
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
break;
|
||||
}
|
||||
|
||||
c2 = *sptr++;
|
||||
c1 |= c2 >> 6;
|
||||
*dptr++ = BF_itoa64[c1];
|
||||
*dptr++ = BF_itoa64[c2 & 0x3f];
|
||||
} while (sptr < end);
|
||||
}
|
||||
|
||||
static void BF_swap(BF_word *x, int count)
|
||||
{
|
||||
static int endianness_check = 1;
|
||||
char *is_little_endian = (char *)&endianness_check;
|
||||
BF_word tmp;
|
||||
|
||||
if (*is_little_endian)
|
||||
do {
|
||||
tmp = *x;
|
||||
tmp = (tmp << 16) | (tmp >> 16);
|
||||
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
#if BF_SCALE
|
||||
/* Architectures which can shift addresses left by 2 bits with no extra cost */
|
||||
#define BF_ROUND(L, R, N) \
|
||||
tmp1 = L & 0xFF; \
|
||||
tmp2 = L >> 8; \
|
||||
tmp2 &= 0xFF; \
|
||||
tmp3 = L >> 16; \
|
||||
tmp3 &= 0xFF; \
|
||||
tmp4 = L >> 24; \
|
||||
tmp1 = data.ctx.S[3][tmp1]; \
|
||||
tmp2 = data.ctx.S[2][tmp2]; \
|
||||
tmp3 = data.ctx.S[1][tmp3]; \
|
||||
tmp3 += data.ctx.S[0][tmp4]; \
|
||||
tmp3 ^= tmp2; \
|
||||
R ^= data.ctx.P[N + 1]; \
|
||||
tmp3 += tmp1; \
|
||||
R ^= tmp3;
|
||||
#else
|
||||
/* Architectures with no complicated addressing modes supported */
|
||||
#define BF_INDEX(S, i) \
|
||||
(*((BF_word *)(((unsigned char *)S) + (i))))
|
||||
#define BF_ROUND(L, R, N) \
|
||||
tmp1 = L & 0xFF; \
|
||||
tmp1 <<= 2; \
|
||||
tmp2 = L >> 6; \
|
||||
tmp2 &= 0x3FC; \
|
||||
tmp3 = L >> 14; \
|
||||
tmp3 &= 0x3FC; \
|
||||
tmp4 = L >> 22; \
|
||||
tmp4 &= 0x3FC; \
|
||||
tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
|
||||
tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
|
||||
tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
|
||||
tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
|
||||
tmp3 ^= tmp2; \
|
||||
R ^= data.ctx.P[N + 1]; \
|
||||
tmp3 += tmp1; \
|
||||
R ^= tmp3;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encrypt one block, BF_N is hardcoded here.
|
||||
*/
|
||||
#define BF_ENCRYPT \
|
||||
L ^= data.ctx.P[0]; \
|
||||
BF_ROUND(L, R, 0); \
|
||||
BF_ROUND(R, L, 1); \
|
||||
BF_ROUND(L, R, 2); \
|
||||
BF_ROUND(R, L, 3); \
|
||||
BF_ROUND(L, R, 4); \
|
||||
BF_ROUND(R, L, 5); \
|
||||
BF_ROUND(L, R, 6); \
|
||||
BF_ROUND(R, L, 7); \
|
||||
BF_ROUND(L, R, 8); \
|
||||
BF_ROUND(R, L, 9); \
|
||||
BF_ROUND(L, R, 10); \
|
||||
BF_ROUND(R, L, 11); \
|
||||
BF_ROUND(L, R, 12); \
|
||||
BF_ROUND(R, L, 13); \
|
||||
BF_ROUND(L, R, 14); \
|
||||
BF_ROUND(R, L, 15); \
|
||||
tmp4 = R; \
|
||||
R = L; \
|
||||
L = tmp4 ^ data.ctx.P[BF_N + 1];
|
||||
|
||||
#define BF_body() \
|
||||
L = R = 0; \
|
||||
ptr = data.ctx.P; \
|
||||
do { \
|
||||
ptr += 2; \
|
||||
BF_ENCRYPT; \
|
||||
*(ptr - 2) = L; \
|
||||
*(ptr - 1) = R; \
|
||||
} while (ptr < &data.ctx.P[BF_N + 2]); \
|
||||
\
|
||||
ptr = data.ctx.S[0]; \
|
||||
do { \
|
||||
ptr += 2; \
|
||||
BF_ENCRYPT; \
|
||||
*(ptr - 2) = L; \
|
||||
*(ptr - 1) = R; \
|
||||
} while (ptr < &data.ctx.S[3][0xFF]);
|
||||
|
||||
static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
|
||||
unsigned char flags)
|
||||
{
|
||||
const char *ptr = key;
|
||||
unsigned int bug, i, j;
|
||||
BF_word safety, sign, diff, tmp[2];
|
||||
|
||||
/*
|
||||
* There was a sign extension bug in older revisions of this function. While
|
||||
* we would have liked to simply fix the bug and move on, we have to provide
|
||||
* a backwards compatibility feature (essentially the bug) for some systems and
|
||||
* a safety measure for some others. The latter is needed because for certain
|
||||
* multiple inputs to the buggy algorithm there exist easily found inputs to
|
||||
* the correct algorithm that produce the same hash. Thus, we optionally
|
||||
* deviate from the correct algorithm just enough to avoid such collisions.
|
||||
* While the bug itself affected the majority of passwords containing
|
||||
* characters with the 8th bit set (although only a percentage of those in a
|
||||
* collision-producing way), the anti-collision safety measure affects
|
||||
* only a subset of passwords containing the '\xff' character (not even all of
|
||||
* those passwords, just some of them). This character is not found in valid
|
||||
* UTF-8 sequences and is rarely used in popular 8-bit character encodings.
|
||||
* Thus, the safety measure is unlikely to cause much annoyance, and is a
|
||||
* reasonable tradeoff to use when authenticating against existing hashes that
|
||||
* are not reliably known to have been computed with the correct algorithm.
|
||||
*
|
||||
* We use an approach that tries to minimize side-channel leaks of password
|
||||
* information - that is, we mostly use fixed-cost bitwise operations instead
|
||||
* of branches or table lookups. (One conditional branch based on password
|
||||
* length remains. It is not part of the bug aftermath, though, and is
|
||||
* difficult and possibly unreasonable to avoid given the use of C strings by
|
||||
* the caller, which results in similar timing leaks anyway.)
|
||||
*
|
||||
* For actual implementation, we set an array index in the variable "bug"
|
||||
* (0 means no bug, 1 means sign extension bug emulation) and a flag in the
|
||||
* variable "safety" (bit 16 is set when the safety measure is requested).
|
||||
* Valid combinations of settings are:
|
||||
*
|
||||
* Prefix "$2a$": bug = 0, safety = 0x10000
|
||||
* Prefix "$2x$": bug = 1, safety = 0
|
||||
* Prefix "$2y$": bug = 0, safety = 0
|
||||
*/
|
||||
bug = (unsigned int)flags & 1;
|
||||
safety = ((BF_word)flags & 2) << 15;
|
||||
|
||||
sign = diff = 0;
|
||||
|
||||
for (i = 0; i < BF_N + 2; i++) {
|
||||
tmp[0] = tmp[1] = 0;
|
||||
for (j = 0; j < 4; j++) {
|
||||
tmp[0] <<= 8;
|
||||
tmp[0] |= (unsigned char)*ptr; /* correct */
|
||||
tmp[1] <<= 8;
|
||||
tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
|
||||
/*
|
||||
* Sign extension in the first char has no effect - nothing to overwrite yet,
|
||||
* and those extra 24 bits will be fully shifted out of the 32-bit word. For
|
||||
* chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
|
||||
* extension in tmp[1] occurs. Once this flag is set, it remains set.
|
||||
*/
|
||||
if (j)
|
||||
sign |= tmp[1] & 0x80;
|
||||
if (!*ptr)
|
||||
ptr = key;
|
||||
else
|
||||
ptr++;
|
||||
}
|
||||
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
|
||||
|
||||
expanded[i] = tmp[bug];
|
||||
initial[i] = BF_init_state.P[i] ^ tmp[bug];
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, "diff" is zero iff the correct and buggy algorithms produced
|
||||
* exactly the same result. If so and if "sign" is non-zero, which indicates
|
||||
* that there was a non-benign sign extension, this means that we have a
|
||||
* collision between the correctly computed hash for this password and a set of
|
||||
* passwords that could be supplied to the buggy algorithm. Our safety measure
|
||||
* is meant to protect from such many-buggy to one-correct collisions, by
|
||||
* deviating from the correct algorithm in such cases. Let's check for this.
|
||||
*/
|
||||
diff |= diff >> 16; /* still zero iff exact match */
|
||||
diff &= 0xffff; /* ditto */
|
||||
diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
|
||||
sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
|
||||
sign &= ~diff & safety; /* action needed? */
|
||||
|
||||
/*
|
||||
* If we have determined that we need to deviate from the correct algorithm,
|
||||
* flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
|
||||
* let's stick to it now. It came out of the approach we used above, and it's
|
||||
* not any worse than any other choice we could make.)
|
||||
*
|
||||
* It is crucial that we don't do the same to the expanded key used in the main
|
||||
* Eksblowfish loop. By doing it to only one of these two, we deviate from a
|
||||
* state that could be directly specified by a password to the buggy algorithm
|
||||
* (and to the fully correct one as well, but that's a side-effect).
|
||||
*/
|
||||
initial[0] ^= sign;
|
||||
}
|
||||
|
||||
static char *BF_crypt(const char *key, const char *setting,
|
||||
char *output, int size,
|
||||
BF_word min)
|
||||
{
|
||||
static const unsigned char flags_by_subtype[26] =
|
||||
{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
|
||||
struct {
|
||||
BF_ctx ctx;
|
||||
BF_key expanded_key;
|
||||
union {
|
||||
BF_word salt[4];
|
||||
BF_word output[6];
|
||||
} binary;
|
||||
} data;
|
||||
BF_word L, R;
|
||||
BF_word tmp1, tmp2, tmp3, tmp4;
|
||||
BF_word *ptr;
|
||||
BF_word count;
|
||||
int i;
|
||||
|
||||
if (size < 7 + 22 + 31 + 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (setting[0] != '$' ||
|
||||
setting[1] != '2' ||
|
||||
setting[2] < 'a' || setting[2] > 'z' ||
|
||||
!flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
|
||||
setting[3] != '$' ||
|
||||
setting[4] < '0' || setting[4] > '3' ||
|
||||
setting[5] < '0' || setting[5] > '9' ||
|
||||
(setting[4] == '3' && setting[5] > '1') ||
|
||||
setting[6] != '$') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
|
||||
if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
|
||||
return NULL;
|
||||
}
|
||||
BF_swap(data.binary.salt, 4);
|
||||
|
||||
BF_set_key(key, data.expanded_key, data.ctx.P,
|
||||
flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
|
||||
|
||||
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
|
||||
|
||||
L = R = 0;
|
||||
for (i = 0; i < BF_N + 2; i += 2) {
|
||||
L ^= data.binary.salt[i & 2];
|
||||
R ^= data.binary.salt[(i & 2) + 1];
|
||||
BF_ENCRYPT;
|
||||
data.ctx.P[i] = L;
|
||||
data.ctx.P[i + 1] = R;
|
||||
}
|
||||
|
||||
ptr = data.ctx.S[0];
|
||||
do {
|
||||
ptr += 4;
|
||||
L ^= data.binary.salt[(BF_N + 2) & 3];
|
||||
R ^= data.binary.salt[(BF_N + 3) & 3];
|
||||
BF_ENCRYPT;
|
||||
*(ptr - 4) = L;
|
||||
*(ptr - 3) = R;
|
||||
|
||||
L ^= data.binary.salt[(BF_N + 4) & 3];
|
||||
R ^= data.binary.salt[(BF_N + 5) & 3];
|
||||
BF_ENCRYPT;
|
||||
*(ptr - 2) = L;
|
||||
*(ptr - 1) = R;
|
||||
} while (ptr < &data.ctx.S[3][0xFF]);
|
||||
|
||||
do {
|
||||
int done;
|
||||
|
||||
for (i = 0; i < BF_N + 2; i += 2) {
|
||||
data.ctx.P[i] ^= data.expanded_key[i];
|
||||
data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
|
||||
}
|
||||
|
||||
done = 0;
|
||||
do {
|
||||
BF_body();
|
||||
if (done)
|
||||
break;
|
||||
done = 1;
|
||||
|
||||
tmp1 = data.binary.salt[0];
|
||||
tmp2 = data.binary.salt[1];
|
||||
tmp3 = data.binary.salt[2];
|
||||
tmp4 = data.binary.salt[3];
|
||||
for (i = 0; i < BF_N; i += 4) {
|
||||
data.ctx.P[i] ^= tmp1;
|
||||
data.ctx.P[i + 1] ^= tmp2;
|
||||
data.ctx.P[i + 2] ^= tmp3;
|
||||
data.ctx.P[i + 3] ^= tmp4;
|
||||
}
|
||||
data.ctx.P[16] ^= tmp1;
|
||||
data.ctx.P[17] ^= tmp2;
|
||||
} while (1);
|
||||
} while (--count);
|
||||
|
||||
for (i = 0; i < 6; i += 2) {
|
||||
L = BF_magic_w[i];
|
||||
R = BF_magic_w[i + 1];
|
||||
|
||||
count = 64;
|
||||
do {
|
||||
BF_ENCRYPT;
|
||||
} while (--count);
|
||||
|
||||
data.binary.output[i] = L;
|
||||
data.binary.output[i + 1] = R;
|
||||
}
|
||||
|
||||
memcpy(output, setting, 7 + 22 - 1);
|
||||
output[7 + 22 - 1] = BF_itoa64[(int)
|
||||
BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
|
||||
|
||||
/* This has to be bug-compatible with the original implementation, so
|
||||
* only encode 23 of the 24 bytes. :-) */
|
||||
BF_swap(data.binary.output, 6);
|
||||
BF_encode(&output[7 + 22], data.binary.output, 23);
|
||||
output[7 + 22 + 31] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
int _crypt_output_magic(const char *setting, char *output, int size)
|
||||
{
|
||||
if (size < 3)
|
||||
return -1;
|
||||
|
||||
output[0] = '*';
|
||||
output[1] = '0';
|
||||
output[2] = '\0';
|
||||
|
||||
if (setting[0] == '*' && setting[1] == '0')
|
||||
output[1] = '1';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Please preserve the runtime self-test. It serves two purposes at once:
|
||||
*
|
||||
* 1. We really can't afford the risk of producing incompatible hashes e.g.
|
||||
* when there's something like gcc bug 26587 again, whereas an application or
|
||||
* library integrating this code might not also integrate our external tests or
|
||||
* it might not run them after every build. Even if it does, the miscompile
|
||||
* might only occur on the production build, but not on a testing build (such
|
||||
* as because of different optimization settings). It is painful to recover
|
||||
* from incorrectly-computed hashes - merely fixing whatever broke is not
|
||||
* enough. Thus, a proactive measure like this self-test is needed.
|
||||
*
|
||||
* 2. We don't want to leave sensitive data from our actual password hash
|
||||
* computation on the stack or in registers. Previous revisions of the code
|
||||
* would do explicit cleanups, but simply running the self-test after hash
|
||||
* computation is more reliable.
|
||||
*
|
||||
* The performance cost of this quick self-test is around 0.6% at the "$2a$08"
|
||||
* setting.
|
||||
*/
|
||||
char *_crypt_blowfish_rn(const char *key, const char *setting,
|
||||
char *output, int size)
|
||||
{
|
||||
_crypt_output_magic(setting, output, size);
|
||||
return BF_crypt(key, setting, output, size, 16);
|
||||
}
|
||||
|
||||
char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
|
||||
const char *input, int size, char *output, int output_size)
|
||||
{
|
||||
if (size < 16 || output_size < 7 + 22 + 1 ||
|
||||
(count && (count < 4 || count > 31)) ||
|
||||
prefix[0] != '$' || prefix[1] != '2' ||
|
||||
(prefix[2] != 'a' && prefix[2] != 'y')) {
|
||||
if (output_size > 0) output[0] = '\0';
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!count) count = 5;
|
||||
|
||||
output[0] = '$';
|
||||
output[1] = '2';
|
||||
output[2] = prefix[2];
|
||||
output[3] = '$';
|
||||
output[4] = '0' + count / 10;
|
||||
output[5] = '0' + count % 10;
|
||||
output[6] = '$';
|
||||
|
||||
BF_encode(&output[7], (const BF_word *)input, 16);
|
||||
output[7 + 22] = '\0';
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Start Anope-specific code
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/encryption.h"
|
||||
|
||||
class EBCRYPT : public Module
|
||||
{
|
||||
unsigned int rounds;
|
||||
|
||||
Anope::string Salt()
|
||||
{
|
||||
char entropy[16];
|
||||
for (unsigned int i = 0; i < sizeof(entropy); i++)
|
||||
entropy[i] = static_cast<char>(rand() % 0xFF);
|
||||
|
||||
char salt[32];
|
||||
if (!_crypt_gensalt_blowfish_rn("$2a$", rounds, entropy, sizeof(entropy), salt, sizeof(salt)))
|
||||
return "";
|
||||
return salt;
|
||||
}
|
||||
|
||||
Anope::string Generate(const Anope::string& data, const Anope::string& salt)
|
||||
{
|
||||
char hash[64];
|
||||
_crypt_blowfish_rn(data.c_str(), salt.c_str(), hash, sizeof(hash));
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool Compare(const Anope::string& string, const Anope::string& hash)
|
||||
{
|
||||
Anope::string ret = Generate(string, hash);
|
||||
if (ret.empty())
|
||||
return false;
|
||||
|
||||
return (ret == hash);
|
||||
}
|
||||
|
||||
public:
|
||||
EBCRYPT(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, ENCRYPTION | VENDOR | EXTRA),
|
||||
rounds(10)
|
||||
{
|
||||
// Test a pre-calculated hash
|
||||
bool test = Compare("Test!", "$2a$10$x9AQFAQScY0v9KF2suqkEOepsHFrG.CXHbIXI.1F28SfSUb56A/7K");
|
||||
|
||||
Anope::string salt;
|
||||
Anope::string hash;
|
||||
// Make sure it's working
|
||||
if (!test || (salt = Salt()).empty() || (hash = Generate("Test!", salt)).empty() || !Compare("Test!", hash))
|
||||
throw ModuleException("BCrypt could not load!");
|
||||
}
|
||||
|
||||
EventReturn OnEncrypt(const Anope::string &src, Anope::string &dest) anope_override
|
||||
{
|
||||
dest = "bcrypt:" + Generate(src, Salt());
|
||||
Log(LOG_DEBUG_2) << "(enc_bcrypt) hashed password from [" << src << "] to [" << dest << "]";
|
||||
return EVENT_ALLOW;
|
||||
}
|
||||
|
||||
void OnCheckAuthentication(User *, IdentifyRequest *req) anope_override
|
||||
{
|
||||
const NickAlias *na = NickAlias::Find(req->GetAccount());
|
||||
if (na == NULL)
|
||||
return;
|
||||
NickCore *nc = na->nc;
|
||||
|
||||
size_t pos = nc->pass.find(':');
|
||||
if (pos == Anope::string::npos)
|
||||
return;
|
||||
Anope::string hash_method(nc->pass.begin(), nc->pass.begin() + pos);
|
||||
if (hash_method != "bcrypt")
|
||||
return;
|
||||
|
||||
if (Compare(req->GetPassword(), nc->pass.substr(7)))
|
||||
{
|
||||
/* if we are NOT the first module in the list,
|
||||
* we want to re-encrypt the pass with the new encryption
|
||||
*/
|
||||
|
||||
unsigned int hashrounds = 0;
|
||||
try
|
||||
{
|
||||
size_t roundspos = nc->pass.find('$', 11);
|
||||
if (roundspos == Anope::string::npos)
|
||||
throw ConvertException("Could not find hashrounds");
|
||||
|
||||
hashrounds = convertTo<unsigned int>(nc->pass.substr(11, roundspos - 11));
|
||||
}
|
||||
catch (const ConvertException &)
|
||||
{
|
||||
Log(this) << "Could not get the round size of a hash. This is probably a bug. Hash: " << nc->pass;
|
||||
}
|
||||
|
||||
if (ModuleManager::FindFirstOf(ENCRYPTION) != this || (hashrounds && hashrounds != rounds))
|
||||
Anope::Encrypt(req->GetPassword(), nc->pass);
|
||||
req->Success(this);
|
||||
}
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
Configuration::Block *block = conf->GetModule(this);
|
||||
rounds = block->Get<unsigned int>("rounds", "10");
|
||||
|
||||
if (rounds == 0)
|
||||
{
|
||||
rounds = 10;
|
||||
Log(this) << "Rounds can't be 0! Setting ignored.";
|
||||
}
|
||||
else if (rounds < 10)
|
||||
{
|
||||
Log(this) << "10 to 12 rounds is recommended.";
|
||||
}
|
||||
else if (rounds >= 32)
|
||||
{
|
||||
rounds = 10;
|
||||
Log(this) << "The maximum number of rounds supported is 31. Ignoring setting and using 10.";
|
||||
}
|
||||
else if (rounds >= 14)
|
||||
{
|
||||
Log(this) << "Are you sure you want to use " << stringify(rounds) << " in your bcrypt settings? This is very CPU intensive! Recommended rounds is 10-12.";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(EBCRYPT)
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "encryption.h"
|
||||
#include "modules/encryption.h"
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "encryption.h"
|
||||
#include "modules/encryption.h"
|
||||
|
||||
static ServiceReference<Encryption::Provider> md5("Encryption::Provider", "md5");
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ A million repetitions of "a"
|
||||
/* #define LITTLE_ENDIAN * This should be #define'd if true. */
|
||||
|
||||
#include "module.h"
|
||||
#include "encryption.h"
|
||||
#include "modules/encryption.h"
|
||||
|
||||
union CHAR64LONG16
|
||||
{
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "encryption.h"
|
||||
#include "modules/encryption.h"
|
||||
|
||||
static const unsigned SHA256_DIGEST_SIZE = 256 / 8;
|
||||
static const unsigned SHA256_BLOCK_SIZE = 512 / 8;
|
||||
|
||||
+78
-26
@@ -12,6 +12,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
int port;
|
||||
Anope::string admin_binddn;
|
||||
Anope::string admin_pass;
|
||||
time_t timeout;
|
||||
|
||||
LDAP *con;
|
||||
|
||||
@@ -70,20 +71,26 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
}
|
||||
|
||||
public:
|
||||
typedef std::map<int, LDAPInterface *> query_queue;
|
||||
typedef std::map<LDAPQuery, std::pair<time_t, LDAPInterface *> > query_queue;
|
||||
typedef std::vector<std::pair<LDAPInterface *, LDAPResult *> > result_queue;
|
||||
query_queue queries;
|
||||
result_queue results;
|
||||
|
||||
LDAPService(Module *o, const Anope::string &n, const Anope::string &s, int po, const Anope::string &b, const Anope::string &p) : LDAPProvider(o, n), server(s), port(po), admin_binddn(b), admin_pass(p), last_connect(0)
|
||||
LDAPService(Module *o, const Anope::string &n, const Anope::string &s, int po, const Anope::string &b, const Anope::string &p, time_t t) : LDAPProvider(o, n), server(s), port(po), admin_binddn(b), admin_pass(p), timeout(t), last_connect(0)
|
||||
{
|
||||
int i = ldap_initialize(&this->con, this->server.c_str());
|
||||
if (i != LDAP_SUCCESS)
|
||||
throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
|
||||
|
||||
const int version = LDAP_VERSION3;
|
||||
i = ldap_set_option(this->con, LDAP_OPT_PROTOCOL_VERSION, &version);
|
||||
if (i != LDAP_OPT_SUCCESS)
|
||||
throw LDAPException("Unable to set protocol version for " + this->name + ": " + ldap_err2string(i));
|
||||
|
||||
const struct timeval tv = { 0, 0 };
|
||||
i = ldap_set_option(this->con, LDAP_OPT_NETWORK_TIMEOUT, &tv);
|
||||
if (i != LDAP_OPT_SUCCESS)
|
||||
throw LDAPException("Unable to set timeout for " + this->name + ": " + ldap_err2string(i));
|
||||
}
|
||||
|
||||
~LDAPService()
|
||||
@@ -92,15 +99,25 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
|
||||
for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end; ++it)
|
||||
{
|
||||
ldap_abandon_ext(this->con, it->first, NULL, NULL);
|
||||
it->second->OnDelete();
|
||||
LDAPQuery msgid = it->first;
|
||||
LDAPInterface *i = it->second.second;
|
||||
|
||||
ldap_abandon_ext(this->con, msgid, NULL, NULL);
|
||||
if (i)
|
||||
i->OnDelete();
|
||||
}
|
||||
this->queries.clear();
|
||||
|
||||
for (result_queue::iterator it = this->results.begin(), it_end = this->results.end(); it != it_end; ++it)
|
||||
{
|
||||
it->second->error = "LDAP Interface is going away";
|
||||
it->first->OnError(*it->second);
|
||||
LDAPInterface *i = it->first;
|
||||
LDAPResult *r = it->second;
|
||||
|
||||
r->error = "LDAP Interface is going away";
|
||||
if (i)
|
||||
i->OnError(*r);
|
||||
|
||||
delete r;
|
||||
}
|
||||
this->results.clear();
|
||||
|
||||
@@ -137,7 +154,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
if (i != NULL)
|
||||
{
|
||||
this->Lock();
|
||||
this->queries[msgid] = i;
|
||||
this->queries[msgid] = std::make_pair(Anope::CurTime, i);
|
||||
this->Unlock();
|
||||
}
|
||||
this->Wakeup();
|
||||
@@ -164,7 +181,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
}
|
||||
|
||||
this->Lock();
|
||||
this->queries[msgid] = i;
|
||||
this->queries[msgid] = std::make_pair(Anope::CurTime, i);
|
||||
this->Unlock();
|
||||
this->Wakeup();
|
||||
|
||||
@@ -192,7 +209,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
if (i != NULL)
|
||||
{
|
||||
this->Lock();
|
||||
this->queries[msgid] = i;
|
||||
this->queries[msgid] = std::make_pair(Anope::CurTime, i);
|
||||
this->Unlock();
|
||||
}
|
||||
this->Wakeup();
|
||||
@@ -219,7 +236,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
if (i != NULL)
|
||||
{
|
||||
this->Lock();
|
||||
this->queries[msgid] = i;
|
||||
this->queries[msgid] = std::make_pair(Anope::CurTime, i);
|
||||
this->Unlock();
|
||||
}
|
||||
this->Wakeup();
|
||||
@@ -248,7 +265,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
if (i != NULL)
|
||||
{
|
||||
this->Lock();
|
||||
this->queries[msgid] = i;
|
||||
this->queries[msgid] = std::make_pair(Anope::CurTime, i);
|
||||
this->Unlock();
|
||||
}
|
||||
this->Wakeup();
|
||||
@@ -256,6 +273,33 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
return msgid;
|
||||
}
|
||||
|
||||
private:
|
||||
void Timeout()
|
||||
{
|
||||
this->Lock();
|
||||
for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end;)
|
||||
{
|
||||
LDAPQuery msgid = it->first;
|
||||
time_t created = it->second.first;
|
||||
LDAPInterface *i = it->second.second;
|
||||
++it;
|
||||
|
||||
if (Anope::CurTime > created + timeout)
|
||||
{
|
||||
LDAPResult *ldap_result = new LDAPResult();
|
||||
ldap_result->id = msgid;
|
||||
ldap_result->error = "Query timed out";
|
||||
|
||||
this->queries.erase(msgid);
|
||||
this->results.push_back(std::make_pair(i, ldap_result));
|
||||
|
||||
me->Notify();
|
||||
}
|
||||
}
|
||||
this->Unlock();
|
||||
}
|
||||
|
||||
public:
|
||||
void Run() anope_override
|
||||
{
|
||||
while (!this->GetExitState())
|
||||
@@ -265,14 +309,15 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
this->Lock();
|
||||
this->Wait();
|
||||
this->Unlock();
|
||||
if (this->GetExitState())
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
this->Timeout();
|
||||
|
||||
struct timeval tv = { 1, 0 };
|
||||
LDAPMessage *result;
|
||||
int rtype = ldap_result(this->con, LDAP_RES_ANY, 1, &tv, &result);
|
||||
if (rtype <= 0 || this->GetExitState())
|
||||
if (rtype <= 0)
|
||||
continue;
|
||||
|
||||
int cur_id = ldap_msgid(result);
|
||||
@@ -286,7 +331,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
|
||||
ldap_msgfree(result);
|
||||
continue;
|
||||
}
|
||||
LDAPInterface *i = it->second;
|
||||
LDAPInterface *i = it->second.second;
|
||||
this->queries.erase(it);
|
||||
|
||||
this->Unlock();
|
||||
@@ -459,10 +504,11 @@ class ModuleLDAP : public Module, public Pipe
|
||||
int port = ldap->Get<int>("port", "389");
|
||||
const Anope::string &admin_binddn = ldap->Get<const Anope::string>("admin_binddn");
|
||||
const Anope::string &admin_password = ldap->Get<const Anope::string>("admin_password");
|
||||
time_t timeout = ldap->Get<time_t>("timeout", "5");
|
||||
|
||||
try
|
||||
{
|
||||
LDAPService *ss = new LDAPService(this, connname, server, port, admin_binddn, admin_password);
|
||||
LDAPService *ss = new LDAPService(this, connname, server, port, admin_binddn, admin_password, timeout);
|
||||
ss->Start();
|
||||
this->LDAPServices.insert(std::make_pair(connname, ss));
|
||||
|
||||
@@ -484,11 +530,11 @@ class ModuleLDAP : public Module, public Pipe
|
||||
s->Lock();
|
||||
for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();)
|
||||
{
|
||||
int msgid = it2->first;
|
||||
LDAPInterface *i = it2->second;
|
||||
LDAPQuery msgid = it2->first;
|
||||
LDAPInterface *i = it2->second.second;
|
||||
++it2;
|
||||
|
||||
if (i->owner == m)
|
||||
if (i && i->owner == m)
|
||||
{
|
||||
i->OnDelete();
|
||||
s->queries.erase(msgid);
|
||||
@@ -499,7 +545,7 @@ class ModuleLDAP : public Module, public Pipe
|
||||
LDAPInterface *li = s->results[i - 1].first;
|
||||
LDAPResult *r = s->results[i - 1].second;
|
||||
|
||||
if (li->owner == m)
|
||||
if (li && li->owner == m)
|
||||
{
|
||||
s->results.erase(s->results.begin() + i - 1);
|
||||
delete r;
|
||||
@@ -515,9 +561,9 @@ class ModuleLDAP : public Module, public Pipe
|
||||
{
|
||||
LDAPService *s = it->second;
|
||||
|
||||
LDAPService::result_queue results;
|
||||
s->Lock();
|
||||
LDAPService::result_queue results = s->results;
|
||||
s->results.clear();
|
||||
results.swap(s->results);
|
||||
s->Unlock();
|
||||
|
||||
for (unsigned i = 0; i < results.size(); ++i)
|
||||
@@ -525,10 +571,16 @@ class ModuleLDAP : public Module, public Pipe
|
||||
LDAPInterface *li = results[i].first;
|
||||
LDAPResult *r = results[i].second;
|
||||
|
||||
if (!r->error.empty())
|
||||
li->OnError(*r);
|
||||
else
|
||||
li->OnResult(*r);
|
||||
if (li != NULL)
|
||||
{
|
||||
if (!r->getError().empty())
|
||||
{
|
||||
Log(this) << "Error running LDAP query: " << r->getError();
|
||||
li->OnError(*r);
|
||||
}
|
||||
else
|
||||
li->OnResult(*r);
|
||||
}
|
||||
|
||||
delete r;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/* RequiredLibraries: ssl,crypto */
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sasl.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
using namespace SASL;
|
||||
|
||||
class DHAES : public Mechanism
|
||||
{
|
||||
void Err(Session* sess, BIGNUM* key = NULL)
|
||||
{
|
||||
if (key)
|
||||
BN_free(key);
|
||||
|
||||
sasl->Fail(sess);
|
||||
delete sess;
|
||||
}
|
||||
|
||||
public:
|
||||
struct DHAESSession : SASL::Session
|
||||
{
|
||||
DH* dh;
|
||||
DHAESSession(Mechanism *m, const Anope::string &u, DH* dh_params) : SASL::Session(m, u)
|
||||
{
|
||||
if (!(dh = DH_new()))
|
||||
return;
|
||||
|
||||
dh->g = BN_dup(dh_params->g);
|
||||
dh->p = BN_dup(dh_params->p);
|
||||
|
||||
if (!DH_generate_key(dh))
|
||||
{
|
||||
DH_free(dh);
|
||||
dh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~DHAESSession()
|
||||
{
|
||||
if (dh)
|
||||
DH_free(dh);
|
||||
}
|
||||
};
|
||||
|
||||
DH* dh_params;
|
||||
const size_t keysize;
|
||||
SASL::Session* CreateSession(const Anope::string &uid) anope_override
|
||||
{
|
||||
return new DHAESSession(this, uid, dh_params);
|
||||
}
|
||||
|
||||
DHAES(Module *o) : Mechanism(o, "DH-AES"), keysize(256 / 8)
|
||||
{
|
||||
if (!(dh_params = DH_new()))
|
||||
throw ModuleException("DH_new() failed!");
|
||||
|
||||
if (!DH_generate_parameters_ex(dh_params, keysize * 8, 5, NULL))
|
||||
{
|
||||
DH_free(dh_params);
|
||||
throw ModuleException("Could not generate DH-params");
|
||||
}
|
||||
}
|
||||
|
||||
~DHAES()
|
||||
{
|
||||
DH_free(dh_params);
|
||||
}
|
||||
|
||||
void ProcessMessage(SASL::Session *session, const SASL::Message &m) anope_override
|
||||
{
|
||||
DHAESSession *sess = anope_dynamic_static_cast<DHAESSession *>(session);
|
||||
|
||||
if (!sess->dh)
|
||||
{
|
||||
sasl->SendMessage(sess, "D", "A");
|
||||
delete sess;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.type == "S")
|
||||
{
|
||||
// Format: [ss]<p>[ss]<g>[ss]<pub_key>
|
||||
// Where ss is a unsigned short with the size of the key
|
||||
const BIGNUM* dhval[] = { sess->dh->p, sess->dh->g, sess->dh->pub_key };
|
||||
|
||||
// Find the size of our buffer - initialized at 6 because of string size data
|
||||
size_t size = 6;
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
size += BN_num_bytes(dhval[i]);
|
||||
|
||||
// Fill in the DH data
|
||||
std::vector<unsigned char> buffer(size);
|
||||
for (size_t i = 0, pos = 0; i < 3; i++)
|
||||
{
|
||||
*reinterpret_cast<uint16_t*>(&buffer[pos]) = htons(BN_num_bytes(dhval[i]));
|
||||
pos += 2;
|
||||
BN_bn2bin(dhval[i], &buffer[pos]);
|
||||
pos += BN_num_bytes(dhval[i]);
|
||||
}
|
||||
|
||||
Anope::string encoded;
|
||||
Anope::B64Encode(Anope::string(buffer.begin(), buffer.end()), encoded);
|
||||
sasl->SendMessage(sess, "C", encoded);
|
||||
}
|
||||
else if (m.type == "C")
|
||||
{
|
||||
// Make sure we have some data - actual size check is done later
|
||||
if (m.data.length() < 10)
|
||||
return Err(sess);
|
||||
|
||||
// Format: [ss]<key>[ss]<iv>[ss]<encrypted>
|
||||
// <encrypted> = <username>\0<password>\0
|
||||
|
||||
Anope::string decoded;
|
||||
Anope::B64Decode(m.data, decoded);
|
||||
|
||||
// Make sure we have an IV and at least one encrypted block
|
||||
if ((decoded.length() < keysize + 2 + (AES_BLOCK_SIZE * 2)) || ((decoded.length() - keysize - 2) % AES_BLOCK_SIZE))
|
||||
return Err(sess);
|
||||
|
||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(decoded.data());
|
||||
|
||||
// Control the size of the key
|
||||
if (ntohs(*reinterpret_cast<const uint16_t*>(&data[0])) != keysize)
|
||||
return Err(sess);
|
||||
|
||||
// Convert pubkey from binary
|
||||
size_t pos = 2;
|
||||
BIGNUM* pubkey = BN_bin2bn(&data[pos], keysize, NULL);
|
||||
if (!pubkey)
|
||||
return Err(sess);
|
||||
|
||||
// Find shared key
|
||||
std::vector<unsigned char> secretkey(keysize);
|
||||
if (DH_compute_key(&secretkey[0], pubkey, sess->dh) != static_cast<int>(keysize))
|
||||
return Err(sess, pubkey);
|
||||
|
||||
// Set decryption key
|
||||
AES_KEY AESKey;
|
||||
AES_set_decrypt_key(&secretkey[0], keysize * 8, &AESKey);
|
||||
|
||||
// Fetch IV
|
||||
pos += keysize;
|
||||
std::vector<unsigned char> IV(data + pos, data + pos + AES_BLOCK_SIZE);
|
||||
|
||||
// Find encrypted blocks, and decrypt
|
||||
pos += AES_BLOCK_SIZE;
|
||||
size_t size = decoded.length() - pos;
|
||||
std::vector<char> decrypted(size + 2, 0);
|
||||
AES_cbc_encrypt(&data[pos], reinterpret_cast<unsigned char*>(&decrypted[0]), size, &AESKey, &IV[0], AES_DECRYPT);
|
||||
|
||||
std::string username = &decrypted[0];
|
||||
std::string password = &decrypted[username.length() + 1];
|
||||
|
||||
if (username.empty() || password.empty())
|
||||
return Err(sess, pubkey);
|
||||
|
||||
SASL::IdentifyRequest* req = new SASL::IdentifyRequest(this->owner, m.source, username, password);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
req->Dispatch();
|
||||
|
||||
BN_free(pubkey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModuleSASLDHAES : public Module
|
||||
{
|
||||
DHAES dhaes;
|
||||
|
||||
public:
|
||||
ModuleSASLDHAES(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR | EXTRA),
|
||||
dhaes(this)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(ModuleSASLDHAES)
|
||||
@@ -0,0 +1,193 @@
|
||||
/* RequiredLibraries: ssl,crypto */
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sasl.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/blowfish.h>
|
||||
|
||||
using namespace SASL;
|
||||
|
||||
class DHBS : public Mechanism
|
||||
{
|
||||
void Err(Session* sess, BIGNUM* key = NULL)
|
||||
{
|
||||
if (key)
|
||||
BN_free(key);
|
||||
|
||||
sasl->Fail(sess);
|
||||
delete sess;
|
||||
}
|
||||
|
||||
public:
|
||||
struct DHBSSession : SASL::Session
|
||||
{
|
||||
DH* dh;
|
||||
DHBSSession(Mechanism *m, const Anope::string &u, DH* dh_params) : SASL::Session(m, u)
|
||||
{
|
||||
if (!(dh = DH_new()))
|
||||
return;
|
||||
|
||||
dh->g = BN_dup(dh_params->g);
|
||||
dh->p = BN_dup(dh_params->p);
|
||||
|
||||
if (!DH_generate_key(dh))
|
||||
{
|
||||
DH_free(dh);
|
||||
dh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~DHBSSession()
|
||||
{
|
||||
if (dh)
|
||||
DH_free(dh);
|
||||
}
|
||||
};
|
||||
|
||||
DH* dh_params;
|
||||
const size_t keysize;
|
||||
SASL::Session* CreateSession(const Anope::string &uid) anope_override
|
||||
{
|
||||
return new DHBSSession(this, uid, dh_params);
|
||||
}
|
||||
|
||||
DHBS(Module *o) : Mechanism(o, "DH-BLOWFISH"), keysize(256 / 8)
|
||||
{
|
||||
if (!(dh_params = DH_new()))
|
||||
throw ModuleException("DH_new() failed!");
|
||||
|
||||
if (!DH_generate_parameters_ex(dh_params, keysize * 8, 5, NULL))
|
||||
{
|
||||
DH_free(dh_params);
|
||||
throw ModuleException("Could not generate DH-params");
|
||||
}
|
||||
}
|
||||
|
||||
~DHBS()
|
||||
{
|
||||
DH_free(dh_params);
|
||||
}
|
||||
|
||||
void ProcessMessage(SASL::Session *session, const SASL::Message &m) anope_override
|
||||
{
|
||||
DHBSSession *sess = anope_dynamic_static_cast<DHBSSession *>(session);
|
||||
|
||||
if (!sess->dh)
|
||||
{
|
||||
sasl->SendMessage(sess, "D", "A");
|
||||
delete sess;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.type == "S")
|
||||
{
|
||||
// Format: [ss]<p>[ss]<g>[ss]<pub_key>
|
||||
// Where ss is a unsigned short with the size of the key
|
||||
const BIGNUM* dhval[] = { sess->dh->p, sess->dh->g, sess->dh->pub_key };
|
||||
|
||||
// Find the size of our buffer - initialized at 6 because of string size data
|
||||
size_t size = 6;
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
size += BN_num_bytes(dhval[i]);
|
||||
|
||||
// Fill in the DH data
|
||||
std::vector<unsigned char> buffer(size);
|
||||
for (size_t i = 0, pos = 0; i < 3; i++)
|
||||
{
|
||||
*reinterpret_cast<uint16_t*>(&buffer[pos]) = htons(BN_num_bytes(dhval[i]));
|
||||
pos += 2;
|
||||
BN_bn2bin(dhval[i], &buffer[pos]);
|
||||
pos += BN_num_bytes(dhval[i]);
|
||||
}
|
||||
|
||||
Anope::string encoded;
|
||||
Anope::B64Encode(Anope::string(buffer.begin(), buffer.end()), encoded);
|
||||
sasl->SendMessage(sess, "C", encoded);
|
||||
}
|
||||
else if (m.type == "C")
|
||||
{
|
||||
// Make sure we have some data - actual size check is done later
|
||||
if (m.data.length() < 10)
|
||||
return Err(sess);
|
||||
|
||||
// Format: [ss]<key><username><\0><encrypted>
|
||||
|
||||
Anope::string decoded;
|
||||
Anope::B64Decode(m.data, decoded);
|
||||
|
||||
// As we rely on the client giving us a null terminator at the right place,
|
||||
// let's add one extra in case the client tries to crash us
|
||||
const size_t decodedlen = decoded.length();
|
||||
decoded.push_back('\0');
|
||||
|
||||
// Make sure we have enough data for at least the key, a one letter username, and a block of data
|
||||
if (decodedlen < keysize + 2 + 2 + 8)
|
||||
return Err(sess);
|
||||
|
||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(decoded.data());
|
||||
|
||||
// Control the size of the key
|
||||
if (ntohs(*reinterpret_cast<const uint16_t*>(&data[0])) != keysize)
|
||||
return Err(sess);
|
||||
|
||||
// Convert pubkey from binary
|
||||
size_t pos = 2;
|
||||
BIGNUM* pubkey = BN_bin2bn(&data[pos], keysize, NULL);
|
||||
if (!pubkey)
|
||||
return Err(sess);
|
||||
|
||||
// Find shared key
|
||||
std::vector<unsigned char> secretkey(DH_size(sess->dh) + 1, 0);
|
||||
if (DH_compute_key(&secretkey[0], pubkey, sess->dh) != static_cast<int>(keysize))
|
||||
return Err(sess, pubkey);
|
||||
|
||||
// Set decryption key
|
||||
BF_KEY BFKey;
|
||||
BF_set_key(&BFKey, keysize, &secretkey[0]);
|
||||
|
||||
pos += keysize;
|
||||
const Anope::string username = reinterpret_cast<const char*>(&data[pos]);
|
||||
// Check that the username is valid, and that we have at least one block of data
|
||||
// 2 + 1 + 8 = uint16_t size for keylen, \0 for username, 8 for one block of data
|
||||
if (username.empty() || username.length() + keysize + 2 + 1 + 8 > decodedlen)
|
||||
return Err(sess, pubkey);
|
||||
|
||||
pos += username.length() + 1;
|
||||
size_t size = decodedlen - pos;
|
||||
|
||||
// Blowfish data blocks are 64 bits wide - valid format?
|
||||
if (size % 8)
|
||||
return Err(sess, pubkey);
|
||||
|
||||
std::vector<char> decrypted(size + 1, 0);
|
||||
for (size_t i = 0; i < size; i += 8)
|
||||
BF_ecb_encrypt(&data[pos + i], reinterpret_cast<unsigned char*>(&decrypted[i]), &BFKey, BF_DECRYPT);
|
||||
|
||||
std::string password = &decrypted[0];
|
||||
if (password.empty())
|
||||
return Err(sess, pubkey);
|
||||
|
||||
SASL::IdentifyRequest* req = new SASL::IdentifyRequest(this->owner, m.source, username, password);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
req->Dispatch();
|
||||
|
||||
BN_free(pubkey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ModuleSASLDHBS : public Module
|
||||
{
|
||||
DHBS dhbs;
|
||||
|
||||
public:
|
||||
ModuleSASLDHBS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR | EXTRA),
|
||||
dhbs(this)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(ModuleSASLDHBS)
|
||||
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* (C) 2014 Attila Molnar <attilamolnar@hush.com>
|
||||
* (C) 2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
/* RequiredLibraries: gnutls */
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/ssl.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
|
||||
class GnuTLSModule;
|
||||
static GnuTLSModule *me;
|
||||
|
||||
namespace GnuTLS { class X509CertCredentials; }
|
||||
|
||||
class MySSLService : public SSLService
|
||||
{
|
||||
public:
|
||||
MySSLService(Module *o, const Anope::string &n);
|
||||
|
||||
/** Initialize a socket to use SSL
|
||||
* @param s The socket
|
||||
*/
|
||||
void Init(Socket *s) anope_override;
|
||||
};
|
||||
|
||||
class SSLSocketIO : public SocketIO
|
||||
{
|
||||
public:
|
||||
gnutls_session_t sess;
|
||||
GnuTLS::X509CertCredentials* mycreds;
|
||||
|
||||
/** Constructor
|
||||
*/
|
||||
SSLSocketIO();
|
||||
|
||||
/** Really receive something from the buffer
|
||||
* @param s The socket
|
||||
* @param buf The buf to read to
|
||||
* @param sz How much to read
|
||||
* @return Number of bytes received
|
||||
*/
|
||||
int Recv(Socket *s, char *buf, size_t sz) anope_override;
|
||||
|
||||
/** Write something to the socket
|
||||
* @param s The socket
|
||||
* @param buf The data to write
|
||||
* @param size The length of the data
|
||||
*/
|
||||
int Send(Socket *s, const char *buf, size_t sz) anope_override;
|
||||
|
||||
/** Accept a connection from a socket
|
||||
* @param s The socket
|
||||
* @return The new socket
|
||||
*/
|
||||
ClientSocket *Accept(ListenSocket *s) anope_override;
|
||||
|
||||
/** Finished accepting a connection from a socket
|
||||
* @param s The socket
|
||||
* @return SF_ACCEPTED if accepted, SF_ACCEPTING if still in process, SF_DEAD on error
|
||||
*/
|
||||
SocketFlag FinishAccept(ClientSocket *cs) anope_override;
|
||||
|
||||
/** Connect the socket
|
||||
* @param s THe socket
|
||||
* @param target IP to connect to
|
||||
* @param port to connect to
|
||||
*/
|
||||
void Connect(ConnectionSocket *s, const Anope::string &target, int port) anope_override;
|
||||
|
||||
/** Called to potentially finish a pending connection
|
||||
* @param s The socket
|
||||
* @return SF_CONNECTED on success, SF_CONNECTING if still pending, and SF_DEAD on error.
|
||||
*/
|
||||
SocketFlag FinishConnect(ConnectionSocket *s) anope_override;
|
||||
|
||||
/** Called when the socket is destructing
|
||||
*/
|
||||
void Destroy() anope_override;
|
||||
};
|
||||
|
||||
namespace GnuTLS
|
||||
{
|
||||
class Init
|
||||
{
|
||||
public:
|
||||
Init() { gnutls_global_init(); }
|
||||
~Init() { gnutls_global_deinit(); }
|
||||
};
|
||||
|
||||
/** Used to create a gnutls_datum_t* from an Anope::string
|
||||
*/
|
||||
class Datum
|
||||
{
|
||||
gnutls_datum_t datum;
|
||||
|
||||
public:
|
||||
Datum(const Anope::string &dat)
|
||||
{
|
||||
datum.data = reinterpret_cast<unsigned char *>(const_cast<char *>(dat.data()));
|
||||
datum.size = static_cast<unsigned int>(dat.length());
|
||||
}
|
||||
|
||||
const gnutls_datum_t *get() const { return &datum; }
|
||||
};
|
||||
|
||||
class DHParams
|
||||
{
|
||||
gnutls_dh_params_t dh_params;
|
||||
|
||||
public:
|
||||
DHParams() : dh_params(NULL) { }
|
||||
|
||||
void Import(const Anope::string &dhstr)
|
||||
{
|
||||
if (dh_params != NULL)
|
||||
{
|
||||
gnutls_dh_params_deinit(dh_params);
|
||||
dh_params = NULL;
|
||||
}
|
||||
|
||||
int ret = gnutls_dh_params_init(&dh_params);
|
||||
if (ret < 0)
|
||||
throw ConfigException("Unable to initialize DH parameters");
|
||||
|
||||
ret = gnutls_dh_params_import_pkcs3(dh_params, Datum(dhstr).get(), GNUTLS_X509_FMT_PEM);
|
||||
if (ret < 0)
|
||||
{
|
||||
gnutls_dh_params_deinit(dh_params);
|
||||
dh_params = NULL;
|
||||
throw ConfigException("Unable to import DH parameters");
|
||||
}
|
||||
}
|
||||
|
||||
~DHParams()
|
||||
{
|
||||
if (dh_params)
|
||||
gnutls_dh_params_deinit(dh_params);
|
||||
}
|
||||
|
||||
gnutls_dh_params_t get() const { return dh_params; }
|
||||
};
|
||||
|
||||
class X509Key
|
||||
{
|
||||
/** Ensure that the key is deinited in case the constructor of X509Key throws
|
||||
*/
|
||||
class RAIIKey
|
||||
{
|
||||
public:
|
||||
gnutls_x509_privkey_t key;
|
||||
|
||||
RAIIKey()
|
||||
{
|
||||
int ret = gnutls_x509_privkey_init(&key);
|
||||
if (ret < 0)
|
||||
throw ConfigException("gnutls_x509_privkey_init() failed");
|
||||
}
|
||||
|
||||
~RAIIKey()
|
||||
{
|
||||
gnutls_x509_privkey_deinit(key);
|
||||
}
|
||||
} key;
|
||||
|
||||
public:
|
||||
/** Import */
|
||||
X509Key(const Anope::string &keystr)
|
||||
{
|
||||
int ret = gnutls_x509_privkey_import(key.key, Datum(keystr).get(), GNUTLS_X509_FMT_PEM);
|
||||
if (ret < 0)
|
||||
throw ConfigException("Error loading private key: " + Anope::string(gnutls_strerror(ret)));
|
||||
}
|
||||
|
||||
gnutls_x509_privkey_t& get() { return key.key; }
|
||||
};
|
||||
|
||||
class X509CertList
|
||||
{
|
||||
std::vector<gnutls_x509_crt_t> certs;
|
||||
|
||||
public:
|
||||
/** Import */
|
||||
X509CertList(const Anope::string &certstr)
|
||||
{
|
||||
unsigned int certcount = 3;
|
||||
certs.resize(certcount);
|
||||
Datum datum(certstr);
|
||||
|
||||
int ret = gnutls_x509_crt_list_import(raw(), &certcount, datum.get(), GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
|
||||
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
|
||||
{
|
||||
// the buffer wasn't big enough to hold all certs but gnutls changed certcount to the number of available certs,
|
||||
// try again with a bigger buffer
|
||||
certs.resize(certcount);
|
||||
ret = gnutls_x509_crt_list_import(raw(), &certcount, datum.get(), GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
throw ConfigException("Unable to load certificates" + Anope::string(gnutls_strerror(ret)));
|
||||
|
||||
// Resize the vector to the actual number of certs because we rely on its size being correct
|
||||
// when deallocating the certs
|
||||
certs.resize(certcount);
|
||||
}
|
||||
|
||||
~X509CertList()
|
||||
{
|
||||
for (std::vector<gnutls_x509_crt_t>::iterator i = certs.begin(); i != certs.end(); ++i)
|
||||
gnutls_x509_crt_deinit(*i);
|
||||
}
|
||||
|
||||
gnutls_x509_crt_t* raw() { return &certs[0]; }
|
||||
unsigned int size() const { return certs.size(); }
|
||||
};
|
||||
|
||||
class X509CertCredentials
|
||||
{
|
||||
unsigned int refcount;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
DHParams dh;
|
||||
|
||||
static Anope::string LoadFile(const Anope::string &filename)
|
||||
{
|
||||
std::ifstream ifs(filename.c_str());
|
||||
const Anope::string ret((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if (GNUTLS_VERSION_MAJOR < 2 || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 12))
|
||||
static int cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, gnutls_retr_st* st);
|
||||
#else
|
||||
static int cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, gnutls_retr2_st* st);
|
||||
#endif
|
||||
|
||||
public:
|
||||
X509CertList certs;
|
||||
X509Key key;
|
||||
|
||||
X509CertCredentials(const Anope::string &certfile, const Anope::string &keyfile)
|
||||
: refcount(0), certs(LoadFile(certfile)), key(LoadFile(keyfile))
|
||||
{
|
||||
if (gnutls_certificate_allocate_credentials(&cred) < 0)
|
||||
throw ConfigException("Cannot allocate certificate credentials");
|
||||
|
||||
int ret = gnutls_certificate_set_x509_key(cred, certs.raw(), certs.size(), key.get());
|
||||
if (ret < 0)
|
||||
{
|
||||
gnutls_certificate_free_credentials(cred);
|
||||
throw ConfigException("Unable to set cert/key pair");
|
||||
}
|
||||
|
||||
#if (GNUTLS_VERSION_MAJOR < 2 || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 12))
|
||||
gnutls_certificate_client_set_retrieve_function(cred, cert_callback);
|
||||
#else
|
||||
gnutls_certificate_set_retrieve_function(cred, cert_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
~X509CertCredentials()
|
||||
{
|
||||
gnutls_certificate_free_credentials(cred);
|
||||
}
|
||||
|
||||
void SetupSession(gnutls_session_t sess)
|
||||
{
|
||||
gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, cred);
|
||||
gnutls_set_default_priority(sess);
|
||||
}
|
||||
|
||||
void SetDH(const Anope::string &dhfile)
|
||||
{
|
||||
const Anope::string dhdata = LoadFile(dhfile);
|
||||
dh.Import(dhdata);
|
||||
gnutls_certificate_set_dh_params(cred, dh.get());
|
||||
}
|
||||
|
||||
bool HasDH() const
|
||||
{
|
||||
return (dh.get() != NULL);
|
||||
}
|
||||
|
||||
void incrref() { refcount++; }
|
||||
void decrref() { if (!--refcount) delete this; }
|
||||
};
|
||||
}
|
||||
|
||||
class GnuTLSModule : public Module
|
||||
{
|
||||
GnuTLS::Init libinit;
|
||||
|
||||
public:
|
||||
GnuTLS::X509CertCredentials *cred;
|
||||
MySSLService service;
|
||||
|
||||
GnuTLSModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), cred(NULL), service(this, "ssl")
|
||||
{
|
||||
me = this;
|
||||
this->SetPermanent(true);
|
||||
}
|
||||
|
||||
~GnuTLSModule()
|
||||
{
|
||||
for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
|
||||
{
|
||||
Socket *s = it->second;
|
||||
++it;
|
||||
|
||||
if (dynamic_cast<SSLSocketIO *>(s->io))
|
||||
delete s;
|
||||
}
|
||||
|
||||
if (cred)
|
||||
cred->decrref();
|
||||
}
|
||||
|
||||
static void CheckFile(const Anope::string &filename)
|
||||
{
|
||||
if (!Anope::IsFile(filename.c_str()))
|
||||
{
|
||||
Log() << "File does not exist: " << filename;
|
||||
throw ConfigException("Error loading certificate/private key");
|
||||
}
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
Configuration::Block *config = conf->GetModule(this);
|
||||
|
||||
const Anope::string certfile = config->Get<const Anope::string>("cert", "data/anope.crt");
|
||||
const Anope::string keyfile = config->Get<const Anope::string>("key", "data/anope.key");
|
||||
const Anope::string dhfile = config->Get<const Anope::string>("dh", "data/dhparams.pem");
|
||||
|
||||
CheckFile(certfile);
|
||||
CheckFile(keyfile);
|
||||
|
||||
GnuTLS::X509CertCredentials *newcred = new GnuTLS::X509CertCredentials(certfile, keyfile);
|
||||
|
||||
// DH params is not mandatory
|
||||
if (Anope::IsFile(dhfile.c_str()))
|
||||
{
|
||||
try
|
||||
{
|
||||
newcred->SetDH(dhfile);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete newcred;
|
||||
throw;
|
||||
}
|
||||
Log(LOG_DEBUG) << "m_ssl_gnutls: Successfully loaded DH parameters from " << dhfile;
|
||||
}
|
||||
|
||||
if (cred)
|
||||
cred->decrref();
|
||||
cred = newcred;
|
||||
cred->incrref();
|
||||
|
||||
Log(LOG_DEBUG) << "m_ssl_gnutls: Successfully loaded certificate " << certfile << " and private key " << keyfile;
|
||||
}
|
||||
|
||||
void OnPreServerConnect() anope_override
|
||||
{
|
||||
Configuration::Block *config = Config->GetBlock("uplink", Anope::CurrentUplink);
|
||||
|
||||
if (config->Get<bool>("ssl"))
|
||||
{
|
||||
this->service.Init(UplinkSock);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MySSLService::MySSLService(Module *o, const Anope::string &n) : SSLService(o, n)
|
||||
{
|
||||
}
|
||||
|
||||
void MySSLService::Init(Socket *s)
|
||||
{
|
||||
if (s->io != &NormalSocketIO)
|
||||
throw CoreException("Socket initializing SSL twice");
|
||||
|
||||
s->io = new SSLSocketIO();
|
||||
}
|
||||
|
||||
int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
|
||||
{
|
||||
int ret = gnutls_record_recv(this->sess, buf, sz);
|
||||
|
||||
if (ret > 0)
|
||||
TotalRead += ret;
|
||||
else if (ret < 0)
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case GNUTLS_E_AGAIN:
|
||||
case GNUTLS_E_INTERRUPTED:
|
||||
SocketEngine::SetLastError(EAGAIN);
|
||||
break;
|
||||
default:
|
||||
if (s == UplinkSock)
|
||||
{
|
||||
// Log and fake an errno because this is a fatal error on the uplink socket
|
||||
Log() << "SSL error: " << gnutls_strerror(ret);
|
||||
}
|
||||
SocketEngine::SetLastError(ECONNRESET);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
|
||||
{
|
||||
int ret = gnutls_record_send(this->sess, buf, sz);
|
||||
|
||||
if (ret > 0)
|
||||
TotalWritten += ret;
|
||||
else
|
||||
{
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
case GNUTLS_E_AGAIN:
|
||||
case GNUTLS_E_INTERRUPTED:
|
||||
SocketEngine::SetLastError(EAGAIN);
|
||||
break;
|
||||
default:
|
||||
if (s == UplinkSock)
|
||||
{
|
||||
// Log and fake an errno because this is a fatal error on the uplink socket
|
||||
Log() << "SSL error: " << gnutls_strerror(ret);
|
||||
}
|
||||
SocketEngine::SetLastError(ECONNRESET);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ClientSocket *SSLSocketIO::Accept(ListenSocket *s)
|
||||
{
|
||||
if (s->io == &NormalSocketIO)
|
||||
throw SocketException("Attempting to accept on uninitialized socket with SSL");
|
||||
|
||||
sockaddrs conaddr;
|
||||
|
||||
socklen_t size = sizeof(conaddr);
|
||||
int newsock = accept(s->GetFD(), &conaddr.sa, &size);
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
const int INVALID_SOCKET = -1;
|
||||
#endif
|
||||
|
||||
if (newsock < 0 || newsock == INVALID_SOCKET)
|
||||
throw SocketException("Unable to accept connection: " + Anope::LastError());
|
||||
|
||||
ClientSocket *newsocket = s->OnAccept(newsock, conaddr);
|
||||
me->service.Init(newsocket);
|
||||
SSLSocketIO *io = anope_dynamic_static_cast<SSLSocketIO *>(newsocket->io);
|
||||
|
||||
if (gnutls_init(&io->sess, GNUTLS_SERVER) != GNUTLS_E_SUCCESS)
|
||||
throw SocketException("Unable to initialize SSL socket");
|
||||
|
||||
me->cred->SetupSession(io->sess);
|
||||
gnutls_transport_set_ptr(io->sess, reinterpret_cast<gnutls_transport_ptr_t>(newsock));
|
||||
|
||||
newsocket->flags[SF_ACCEPTING] = true;
|
||||
this->FinishAccept(newsocket);
|
||||
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
SocketFlag SSLSocketIO::FinishAccept(ClientSocket *cs)
|
||||
{
|
||||
if (cs->io == &NormalSocketIO)
|
||||
throw SocketException("Attempting to finish connect uninitialized socket with SSL");
|
||||
else if (cs->flags[SF_ACCEPTED])
|
||||
return SF_ACCEPTED;
|
||||
else if (!cs->flags[SF_ACCEPTING])
|
||||
throw SocketException("SSLSocketIO::FinishAccept called for a socket not accepted nor accepting?");
|
||||
|
||||
SSLSocketIO *io = anope_dynamic_static_cast<SSLSocketIO *>(cs->io);
|
||||
|
||||
int ret = gnutls_handshake(io->sess);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
|
||||
{
|
||||
// gnutls_handshake() wants to read or write again;
|
||||
// if gnutls_record_get_direction() returns 0 it wants to read, otherwise it wants to write.
|
||||
if (gnutls_record_get_direction(io->sess) == 0)
|
||||
{
|
||||
SocketEngine::Change(cs, false, SF_WRITABLE);
|
||||
SocketEngine::Change(cs, true, SF_READABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SocketEngine::Change(cs, true, SF_WRITABLE);
|
||||
SocketEngine::Change(cs, false, SF_READABLE);
|
||||
}
|
||||
return SF_ACCEPTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
cs->OnError(Anope::string(gnutls_strerror(ret)));
|
||||
cs->flags[SF_DEAD] = true;
|
||||
cs->flags[SF_ACCEPTING] = false;
|
||||
return SF_DEAD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cs->flags[SF_ACCEPTED] = true;
|
||||
cs->flags[SF_ACCEPTING] = false;
|
||||
SocketEngine::Change(cs, false, SF_WRITABLE);
|
||||
SocketEngine::Change(cs, true, SF_READABLE);
|
||||
cs->OnAccept();
|
||||
return SF_ACCEPTED;
|
||||
}
|
||||
}
|
||||
|
||||
void SSLSocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int port)
|
||||
{
|
||||
if (s->io == &NormalSocketIO)
|
||||
throw SocketException("Attempting to connect uninitialized socket with SSL");
|
||||
|
||||
s->flags[SF_CONNECTING] = s->flags[SF_CONNECTED] = false;
|
||||
|
||||
s->conaddr.pton(s->IsIPv6() ? AF_INET6 : AF_INET, target, port);
|
||||
int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
|
||||
if (c == -1)
|
||||
{
|
||||
if (Anope::LastErrorCode() != EINPROGRESS)
|
||||
{
|
||||
s->OnError(Anope::LastError());
|
||||
s->flags[SF_DEAD] = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
SocketEngine::Change(s, true, SF_WRITABLE);
|
||||
s->flags[SF_CONNECTING] = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->flags[SF_CONNECTING] = true;
|
||||
this->FinishConnect(s);
|
||||
}
|
||||
}
|
||||
|
||||
SocketFlag SSLSocketIO::FinishConnect(ConnectionSocket *s)
|
||||
{
|
||||
if (s->io == &NormalSocketIO)
|
||||
throw SocketException("Attempting to finish connect uninitialized socket with SSL");
|
||||
else if (s->flags[SF_CONNECTED])
|
||||
return SF_CONNECTED;
|
||||
else if (!s->flags[SF_CONNECTING])
|
||||
throw SocketException("SSLSocketIO::FinishConnect called for a socket not connected nor connecting?");
|
||||
|
||||
SSLSocketIO *io = anope_dynamic_static_cast<SSLSocketIO *>(s->io);
|
||||
|
||||
if (io->sess == NULL)
|
||||
{
|
||||
if (gnutls_init(&io->sess, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS)
|
||||
throw SocketException("Unable to initialize SSL socket");
|
||||
me->cred->SetupSession(io->sess);
|
||||
gnutls_transport_set_ptr(io->sess, reinterpret_cast<gnutls_transport_ptr_t>(s->GetFD()));
|
||||
}
|
||||
|
||||
int ret = gnutls_handshake(io->sess);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
|
||||
{
|
||||
// gnutls_handshake() wants to read or write again;
|
||||
// if gnutls_record_get_direction() returns 0 it wants to read, otherwise it wants to write.
|
||||
if (gnutls_record_get_direction(io->sess) == 0)
|
||||
{
|
||||
SocketEngine::Change(s, false, SF_WRITABLE);
|
||||
SocketEngine::Change(s, true, SF_READABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SocketEngine::Change(s, true, SF_WRITABLE);
|
||||
SocketEngine::Change(s, false, SF_READABLE);
|
||||
}
|
||||
|
||||
return SF_CONNECTING;
|
||||
}
|
||||
else
|
||||
{
|
||||
s->OnError(Anope::string(gnutls_strerror(ret)));
|
||||
s->flags[SF_CONNECTING] = false;
|
||||
s->flags[SF_DEAD] = true;
|
||||
return SF_DEAD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s->flags[SF_CONNECTING] = false;
|
||||
s->flags[SF_CONNECTED] = true;
|
||||
SocketEngine::Change(s, false, SF_WRITABLE);
|
||||
SocketEngine::Change(s, true, SF_READABLE);
|
||||
s->OnConnect();
|
||||
return SF_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
void SSLSocketIO::Destroy()
|
||||
{
|
||||
if (this->sess)
|
||||
{
|
||||
gnutls_bye(this->sess, GNUTLS_SHUT_WR);
|
||||
gnutls_deinit(this->sess);
|
||||
}
|
||||
|
||||
mycreds->decrref();
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
SSLSocketIO::SSLSocketIO() : sess(NULL), mycreds(me->cred)
|
||||
{
|
||||
mycreds->incrref();
|
||||
}
|
||||
|
||||
#if (GNUTLS_VERSION_MAJOR < 2 || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 12))
|
||||
int GnuTLS::X509CertCredentials::cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, gnutls_retr_st* st)
|
||||
{
|
||||
st->type = GNUTLS_CRT_X509;
|
||||
#else
|
||||
int GnuTLS::X509CertCredentials::cert_callback(gnutls_session_t sess, const gnutls_datum_t* req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t* sign_algos, int sign_algos_length, gnutls_retr2_st* st)
|
||||
{
|
||||
st->cert_type = GNUTLS_CRT_X509;
|
||||
st->key_type = GNUTLS_PRIVKEY_X509;
|
||||
#endif
|
||||
st->ncerts = me->cred->certs.size();
|
||||
st->cert.x509 = me->cred->certs.raw();
|
||||
st->key.x509 = me->cred->key.get();
|
||||
st->deinit_all = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_INIT(GnuTLSModule)
|
||||
@@ -137,7 +137,7 @@ class SSLModule : public Module
|
||||
if (!SSL_CTX_use_certificate_file(client_ctx, this->certfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_certificate_file(server_ctx, this->certfile.c_str(), SSL_FILETYPE_PEM))
|
||||
throw ConfigException("Error loading certificate");
|
||||
else
|
||||
Log(LOG_DEBUG) << "m_ssl: Successfully loaded certificate " << this->certfile;
|
||||
Log(LOG_DEBUG) << "m_ssl_openssl: Successfully loaded certificate " << this->certfile;
|
||||
}
|
||||
else
|
||||
Log() << "Unable to open certificate " << this->certfile;
|
||||
@@ -147,7 +147,7 @@ class SSLModule : public Module
|
||||
if (!SSL_CTX_use_PrivateKey_file(client_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(server_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM))
|
||||
throw ConfigException("Error loading private key");
|
||||
else
|
||||
Log(LOG_DEBUG) << "m_ssl: Successfully loaded private key " << this->keyfile;
|
||||
Log(LOG_DEBUG) << "m_ssl_openssl: Successfully loaded private key " << this->keyfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -190,14 +190,37 @@ SSLSocketIO::SSLSocketIO()
|
||||
int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
|
||||
{
|
||||
int i = SSL_read(this->sslsock, buf, sz);
|
||||
TotalRead += i;
|
||||
if (i > 0)
|
||||
TotalRead += i;
|
||||
else if (i < 0)
|
||||
{
|
||||
int err = SSL_get_error(this->sslsock, i);
|
||||
switch (err)
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
SocketEngine::SetLastError(EAGAIN);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
|
||||
{
|
||||
int i = SSL_write(this->sslsock, buf, sz);
|
||||
TotalWritten += i;
|
||||
if (i > 0)
|
||||
TotalWritten += i;
|
||||
else if (i < 0)
|
||||
{
|
||||
int err = SSL_get_error(this->sslsock, i);
|
||||
switch (err)
|
||||
{
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
SocketEngine::SetLastError(EAGAIN);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,6 @@ void IRC2SQL::CheckTables()
|
||||
query = "CREATE TABLE `" + prefix + "chan` ("
|
||||
"`chanid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,"
|
||||
"`channel` varchar(255) NOT NULL,"
|
||||
"`currentusers` int(15) NOT NULL DEFAULT 0,"
|
||||
"`topic` varchar(255) DEFAULT NULL,"
|
||||
"`topicauthor` varchar(255) DEFAULT NULL,"
|
||||
"`topictime` datetime DEFAULT NULL,"
|
||||
@@ -230,47 +229,6 @@ void IRC2SQL::CheckTables()
|
||||
query = "CREATE PROCEDURE " + prefix + "ServerQuit(sname_ varchar(255)) "
|
||||
"BEGIN "
|
||||
/* 1.
|
||||
* loop through all channels and decrease the user count
|
||||
* by the number of users that are on this channel AND
|
||||
* on the splitting server
|
||||
*
|
||||
* we dont have to care about channels that get empty, there will be
|
||||
* an extra OnChannelDelete event triggered from anope.
|
||||
*/
|
||||
"DECLARE no_more_rows BOOLEAN DEFAULT FALSE;"
|
||||
"DECLARE channel_ varchar(255);"
|
||||
"DECLARE ucount_ int;"
|
||||
"DECLARE channel_cursor CURSOR FOR "
|
||||
"SELECT c.channel "
|
||||
"FROM `" + prefix + "chan` as c, `" + prefix + "ison` as i, "
|
||||
"`" + prefix + "user` as u, `" + prefix + "server` as s "
|
||||
"WHERE c.chanid = i.chanid "
|
||||
"AND i.nickid = u.nickid "
|
||||
"AND u.servid = s.id "
|
||||
"AND s.name = sname_;"
|
||||
"DECLARE CONTINUE HANDLER FOR NOT FOUND "
|
||||
"SET no_more_rows = TRUE;"
|
||||
"OPEN channel_cursor;"
|
||||
"the_loop: LOOP "
|
||||
"FETCH channel_cursor INTO channel_;"
|
||||
"IF no_more_rows THEN "
|
||||
"CLOSE channel_cursor;"
|
||||
"LEAVE the_loop;"
|
||||
"END IF;"
|
||||
"SELECT COUNT(*) INTO ucount_ "
|
||||
"FROM `" + prefix + "ison` AS i, `" + prefix + "chan` AS c,"
|
||||
"`" + prefix + "user` AS u, `" + prefix + "server` AS s "
|
||||
"WHERE i.nickid = u.nickid "
|
||||
"AND u.servid = s.id "
|
||||
"AND i.chanid = c.chanid "
|
||||
"AND c.channel = channel_ "
|
||||
"AND s.name = sname_; "
|
||||
"UPDATE `" + prefix + "chan` "
|
||||
"SET currentusers = currentusers - ucount_ "
|
||||
"WHERE channel = channel_;"
|
||||
"END LOOP;"
|
||||
|
||||
/* 2.
|
||||
* remove all users on the splitting server from the ison table
|
||||
*/
|
||||
"DELETE i FROM `" + prefix + "ison` AS i "
|
||||
@@ -280,7 +238,7 @@ void IRC2SQL::CheckTables()
|
||||
"AND u.servid = s.id "
|
||||
"AND s.name = sname_;"
|
||||
|
||||
/* 3.
|
||||
/* 2.
|
||||
* remove all users on the splitting server from the user table
|
||||
*/
|
||||
"DELETE u FROM `" + prefix + "user` AS u "
|
||||
@@ -288,7 +246,7 @@ void IRC2SQL::CheckTables()
|
||||
"WHERE s.id = u.servid "
|
||||
"AND s.name = sname_;"
|
||||
|
||||
/* 4.
|
||||
/* 3.
|
||||
* on the splitting server, set usercount = 0, split_time = now(), online = 'N'
|
||||
*/
|
||||
"UPDATE `" + prefix + "server` SET currentusers = 0, split_time = now(), online = 'N' "
|
||||
@@ -306,12 +264,6 @@ void IRC2SQL::CheckTables()
|
||||
"UPDATE `" + prefix + "user` AS `u`, `" + prefix + "server` AS `s` "
|
||||
"SET s.currentusers = s.currentusers - 1 "
|
||||
"WHERE u.nick=nick_ AND u.servid = s.id; "
|
||||
/* decrease the usercount on all channels where the user was on */
|
||||
"UPDATE `" + prefix + "user` AS u, `" + prefix + "ison` AS i, "
|
||||
"`" + prefix + "chan` AS c "
|
||||
"SET c.currentusers = c.currentusers - 1 "
|
||||
"WHERE u.nick=nick_ AND u.nickid = i.nickid "
|
||||
"AND i.chanid = c.chanid; "
|
||||
/* remove from all channels where the user was on */
|
||||
"DELETE i FROM `" + prefix + "ison` AS i "
|
||||
"INNER JOIN `" + prefix + "user` as u "
|
||||
@@ -345,9 +297,9 @@ void IRC2SQL::CheckTables()
|
||||
"SELECT u.nickid, c.chanid, modes_ "
|
||||
"FROM " + prefix + "user AS u, " + prefix + "chan AS c "
|
||||
"WHERE u.nick=nick_ AND c.channel=channel_;"
|
||||
"UPDATE `" + prefix + "chan` SET currentusers=currentusers+1 "
|
||||
"WHERE channel=channel_;"
|
||||
"SELECT `currentusers` INTO cur FROM `" + prefix + "chan` WHERE channel=channel_;"
|
||||
"SELECT count(i.chanid) INTO cur "
|
||||
"FROM `" + prefix + "chan` AS c, " + prefix + "ison AS i "
|
||||
"WHERE i.chanid = c.chanid AND c.channel=channel_;"
|
||||
"SELECT `maxusers` INTO max FROM `" + prefix + "maxusers` WHERE name=channel_;"
|
||||
"IF found_rows() AND cur <= max THEN "
|
||||
"UPDATE `" + prefix + "maxusers` SET lastused=now() WHERE name=channel_;"
|
||||
@@ -373,8 +325,6 @@ void IRC2SQL::CheckTables()
|
||||
"AND u.nick = nick_ "
|
||||
"AND i.chanid = c.chanid "
|
||||
"AND c.channel = channel_;"
|
||||
"UPDATE `" + prefix + "chan` SET currentusers=currentusers-1 "
|
||||
"WHERE channel=channel_;"
|
||||
"END";
|
||||
this->RunQuery(query);
|
||||
}
|
||||
|
||||
+6
-3
@@ -97,7 +97,7 @@ class Fantasy : public Module
|
||||
if (!u || !c || !c->ci || !c->ci->bi || msg.empty() || msg[0] == '\1')
|
||||
return;
|
||||
|
||||
if (!fantasy.HasExt(c->ci))
|
||||
if (Config->GetClient("BotServ") && !fantasy.HasExt(c->ci))
|
||||
return;
|
||||
|
||||
std::vector<Anope::string> params;
|
||||
@@ -162,8 +162,11 @@ class Fantasy : public Module
|
||||
source.command = it->first;
|
||||
source.permission = info.permission;
|
||||
|
||||
AccessGroup ag = c->ci->AccessFor(u);
|
||||
bool has_fantasia = ag.HasPriv("FANTASIA") || source.HasPriv("chanserv/administration");
|
||||
|
||||
EventReturn MOD_RESULT;
|
||||
if (c->ci->AccessFor(u).HasPriv("FANTASIA"))
|
||||
if (has_fantasia)
|
||||
{
|
||||
FOREACH_RESULT(OnBotFantasy, MOD_RESULT, (source, cmd, c->ci, params));
|
||||
}
|
||||
@@ -172,7 +175,7 @@ class Fantasy : public Module
|
||||
FOREACH_RESULT(OnBotNoFantasyAccess, MOD_RESULT, (source, cmd, c->ci, params));
|
||||
}
|
||||
|
||||
if (MOD_RESULT == EVENT_STOP || !c->ci->AccessFor(u).HasPriv("FANTASIA"))
|
||||
if (MOD_RESULT == EVENT_STOP || !has_fantasia)
|
||||
return;
|
||||
|
||||
if (MOD_RESULT != EVENT_ALLOW && !info.permission.empty() && !source.HasCommand(info.permission))
|
||||
|
||||
@@ -454,9 +454,6 @@ class HTTPD : public Module
|
||||
|
||||
void OnModuleLoad(User *u, Module *m) anope_override
|
||||
{
|
||||
if (m->name != "m_ssl")
|
||||
return;
|
||||
|
||||
for (std::map<Anope::string, MyHTTPProvider *>::iterator it = this->providers.begin(), it_end = this->providers.end(); it != it_end; ++it)
|
||||
{
|
||||
MyHTTPProvider *p = it->second;
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
*
|
||||
* (C) 2014 Anope Team
|
||||
* Contact us at team@anope.org
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sasl.h"
|
||||
#include "modules/ns_cert.h"
|
||||
|
||||
using namespace SASL;
|
||||
|
||||
class Plain : public Mechanism
|
||||
{
|
||||
public:
|
||||
Plain(Module *o) : Mechanism(o, "PLAIN") { }
|
||||
|
||||
void ProcessMessage(Session *sess, const SASL::Message &m) anope_override
|
||||
{
|
||||
if (m.type == "S")
|
||||
{
|
||||
sasl->SendMessage(sess, "C", "+");
|
||||
}
|
||||
else if (m.type == "C")
|
||||
{
|
||||
Anope::string decoded;
|
||||
Anope::B64Decode(m.data, decoded);
|
||||
|
||||
size_t p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
decoded = decoded.substr(p + 1);
|
||||
|
||||
p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
Anope::string acc = decoded.substr(0, p),
|
||||
pass = decoded.substr(p + 1);
|
||||
|
||||
if (acc.empty() || pass.empty())
|
||||
return;
|
||||
|
||||
SASL::IdentifyRequest *req = new SASL::IdentifyRequest(this->owner, m.source, acc, pass);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
req->Dispatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class External : public Mechanism
|
||||
{
|
||||
ServiceReference<CertService> certs;
|
||||
|
||||
struct Session : SASL::Session
|
||||
{
|
||||
Anope::string cert;
|
||||
|
||||
Session(Mechanism *m, const Anope::string &u) : SASL::Session(m, u) { }
|
||||
};
|
||||
|
||||
public:
|
||||
External(Module *o) : Mechanism(o, "EXTERNAL"), certs("CertService", "certs")
|
||||
{
|
||||
if (!IRCD || !IRCD->CanCertFP)
|
||||
throw ModuleException("No CertFP");
|
||||
}
|
||||
|
||||
Session* CreateSession(const Anope::string &uid) anope_override
|
||||
{
|
||||
return new Session(this, uid);
|
||||
}
|
||||
|
||||
void ProcessMessage(SASL::Session *sess, const SASL::Message &m) anope_override
|
||||
{
|
||||
Session *mysess = anope_dynamic_static_cast<Session *>(sess);
|
||||
|
||||
if (m.type == "S")
|
||||
{
|
||||
mysess->cert = m.ext;
|
||||
|
||||
sasl->SendMessage(sess, "C", "+");
|
||||
}
|
||||
else if (m.type == "C")
|
||||
{
|
||||
if (!certs)
|
||||
{
|
||||
sasl->Fail(sess);
|
||||
delete sess;
|
||||
return;
|
||||
}
|
||||
|
||||
NickCore *nc = certs->FindAccountFromCert(mysess->cert);
|
||||
if (!nc || nc->HasExt("NS_SUSPENDED"))
|
||||
{
|
||||
sasl->Fail(sess);
|
||||
delete sess;
|
||||
return;
|
||||
}
|
||||
|
||||
Log(Config->GetClient("NickServ")) << "A user identified to account " << nc->display << " using SASL EXTERNAL";
|
||||
sasl->Succeed(sess, nc);
|
||||
delete sess;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SASLService : public SASL::Service, public Timer
|
||||
{
|
||||
std::map<Anope::string, SASL::Session *> sessions;
|
||||
|
||||
public:
|
||||
SASLService(Module *o) : SASL::Service(o), Timer(o, 60, Anope::CurTime, true) { }
|
||||
|
||||
~SASLService()
|
||||
{
|
||||
for (std::map<Anope::string, Session *>::iterator it = sessions.begin(); it != sessions.end(); it++)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
void ProcessMessage(const SASL::Message &m) anope_override
|
||||
{
|
||||
if (m.target != "*")
|
||||
{
|
||||
Server *s = Server::Find(m.target);
|
||||
if (s != Me)
|
||||
{
|
||||
User *u = User::Find(m.target);
|
||||
if (!u || u->server != Me)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Session* &session = sessions[m.source];
|
||||
|
||||
if (m.type == "S")
|
||||
{
|
||||
ServiceReference<Mechanism> mech("SASL::Mechanism", m.data);
|
||||
if (!mech)
|
||||
{
|
||||
Session tmp(NULL, m.source);
|
||||
|
||||
sasl->SendMechs(&tmp);
|
||||
sasl->Fail(&tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session)
|
||||
session = mech->CreateSession(m.source);
|
||||
}
|
||||
else if (m.type == "D")
|
||||
{
|
||||
delete session;
|
||||
sessions.erase(m.source);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session && session->mech)
|
||||
session->mech->ProcessMessage(session, m);
|
||||
}
|
||||
|
||||
Anope::string GetAgent() anope_override
|
||||
{
|
||||
Anope::string agent = Config->GetModule(Service::owner)->Get<Anope::string>("agent", "NickServ");
|
||||
BotInfo *bi = Config->GetClient(agent);
|
||||
if (bi)
|
||||
agent = bi->GetUID();
|
||||
return agent;
|
||||
}
|
||||
|
||||
Session* GetSession(const Anope::string &uid) anope_override
|
||||
{
|
||||
std::map<Anope::string, Session *>::iterator it = sessions.find(uid);
|
||||
if (it != sessions.end())
|
||||
return it->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RemoveSession(Session *sess) anope_override
|
||||
{
|
||||
sessions.erase(sess->uid);
|
||||
}
|
||||
|
||||
void DeleteSessions(Mechanism *mech, bool da) anope_override
|
||||
{
|
||||
for (std::map<Anope::string, Session *>::iterator it = sessions.begin(); it != sessions.end();)
|
||||
{
|
||||
std::map<Anope::string, Session *>::iterator del = it++;
|
||||
if (*del->second->mech == mech)
|
||||
{
|
||||
if (da)
|
||||
this->SendMessage(del->second, "D", "A");
|
||||
delete del->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendMessage(Session *session, const Anope::string &mtype, const Anope::string &data) anope_override
|
||||
{
|
||||
SASL::Message msg;
|
||||
msg.source = this->GetAgent();
|
||||
msg.target = session->uid;
|
||||
msg.type = mtype;
|
||||
msg.data = data;
|
||||
|
||||
IRCD->SendSASLMessage(msg);
|
||||
}
|
||||
|
||||
void Succeed(Session *session, NickCore *nc) anope_override
|
||||
{
|
||||
IRCD->SendSVSLogin(session->uid, nc->display);
|
||||
this->SendMessage(session, "D", "S");
|
||||
}
|
||||
|
||||
void Fail(Session *session) anope_override
|
||||
{
|
||||
this->SendMessage(session, "D", "F");
|
||||
}
|
||||
|
||||
void SendMechs(Session *session) anope_override
|
||||
{
|
||||
std::vector<Anope::string> mechs = Service::GetServiceKeys("SASL::Mechanism");
|
||||
Anope::string buf;
|
||||
for (unsigned j = 0; j < mechs.size(); ++j)
|
||||
buf += "," + mechs[j];
|
||||
|
||||
this->SendMessage(session, "M", buf.empty() ? "" : buf.substr(1));
|
||||
}
|
||||
|
||||
void Tick(time_t) anope_override
|
||||
{
|
||||
for (std::map<Anope::string, Session *>::iterator it = sessions.begin(); it != sessions.end();)
|
||||
{
|
||||
Anope::string key = it->first;
|
||||
Session *s = it->second;
|
||||
++it;
|
||||
|
||||
if (!s || !s->mech || s->created + 60 < Anope::CurTime)
|
||||
{
|
||||
delete s;
|
||||
sessions.erase(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleSASL : public Module
|
||||
{
|
||||
SASLService sasl;
|
||||
|
||||
Plain plain;
|
||||
External *external;
|
||||
|
||||
public:
|
||||
ModuleSASL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
|
||||
sasl(this), plain(this), external(NULL)
|
||||
{
|
||||
try
|
||||
{
|
||||
external = new External(this);
|
||||
}
|
||||
catch (ModuleException &) { }
|
||||
}
|
||||
|
||||
~ModuleSASL()
|
||||
{
|
||||
delete external;
|
||||
}
|
||||
};
|
||||
|
||||
MODULE_INIT(ModuleSASL)
|
||||
+10
-2
@@ -25,9 +25,9 @@ class NSMaxEmail : public Module
|
||||
return false;
|
||||
|
||||
if (NSEmailMax == 1)
|
||||
source.Reply(_("The given email address has reached its usage limit of 1 user."));
|
||||
source.Reply(_("The email address \002%s\002 has reached its usage limit of 1 user."), email.c_str());
|
||||
else
|
||||
source.Reply(_("The given email address has reached its usage limit of %d users."), NSEmailMax);
|
||||
source.Reply(_("The email address \002%s\002 has reached its usage limit of %d users."), email.c_str(), NSEmailMax);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -57,6 +57,9 @@ class NSMaxEmail : public Module
|
||||
|
||||
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override
|
||||
{
|
||||
if (source.IsOper())
|
||||
return EVENT_CONTINUE;
|
||||
|
||||
if (command->name == "nickserv/register")
|
||||
{
|
||||
if (this->CheckLimitReached(source, params.size() > 1 ? params[1] : ""))
|
||||
@@ -67,6 +70,11 @@ class NSMaxEmail : public Module
|
||||
if (this->CheckLimitReached(source, params.size() > 0 ? params[0] : ""))
|
||||
return EVENT_STOP;
|
||||
}
|
||||
else if (command->name == "nickserv/ungroup" && source.GetAccount())
|
||||
{
|
||||
if (this->CheckLimitReached(source, source.GetAccount()->email))
|
||||
return EVENT_STOP;
|
||||
}
|
||||
|
||||
return EVENT_CONTINUE;
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ struct IRCDMessageNick : IRCDMessage
|
||||
if (signon && signon == stamp)
|
||||
na = NickAlias::Find(params[0]);
|
||||
|
||||
new User(params[0], params[4], params[5], "", params[8], s, params[9], signon, params[3], "", na ? *na->nc : NULL);
|
||||
User::OnIntroduce(params[0], params[4], params[5], "", params[8], s, params[9], signon, params[3], "", na ? *na->nc : NULL);
|
||||
}
|
||||
else
|
||||
source.GetUser()->ChangeNick(params[0]);
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/cs_mode.h"
|
||||
#include "modules/sasl.h"
|
||||
|
||||
static bool sasl = true;
|
||||
static Anope::string UplinkSID;
|
||||
|
||||
static ServiceReference<IRCDProto> ratbox("IRCDProto", "ratbox");
|
||||
@@ -140,6 +140,18 @@ class CharybdisProto : public IRCDProto
|
||||
{
|
||||
this->SendVhost(u, "", u->host);
|
||||
}
|
||||
|
||||
void SendSASLMessage(const SASL::Message &message) anope_override
|
||||
{
|
||||
Server *s = Server::Find(message.target.substr(0, 3));
|
||||
UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : message.target.substr(0, 3)) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext));
|
||||
}
|
||||
|
||||
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override
|
||||
{
|
||||
Server *s = Server::Find(uid.substr(0, 3));
|
||||
UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * * * " << acc;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -176,82 +188,16 @@ struct IRCDMessageEncap : IRCDMessage
|
||||
*
|
||||
* Charybdis only accepts messages from SASL agents; these must have umode +S
|
||||
*/
|
||||
if (params[1] == "SASL" && sasl && params.size() == 6)
|
||||
if (params[1] == "SASL" && SASL::sasl && params.size() >= 6)
|
||||
{
|
||||
class CharybdisSASLIdentifyRequest : public IdentifyRequest
|
||||
{
|
||||
Anope::string uid;
|
||||
MessageSource msource;
|
||||
SASL::Message m;
|
||||
m.source = params[2];
|
||||
m.target = params[3];
|
||||
m.type = params[4];
|
||||
m.data = params[5];
|
||||
m.ext = params.size() > 6 ? params[6] : "";
|
||||
|
||||
public:
|
||||
CharybdisSASLIdentifyRequest(Module *m, MessageSource &source_, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id), msource(source_) { }
|
||||
|
||||
void OnSuccess() anope_override
|
||||
{
|
||||
BotInfo *NickServ = Config->GetClient("NickServ");
|
||||
if (!NickServ)
|
||||
return;
|
||||
|
||||
/* SVSLOGIN
|
||||
* parameters: target, new nick, new username, new visible hostname, new login name
|
||||
* Sent after successful SASL authentication.
|
||||
* The target is a UID, typically an unregistered one.
|
||||
* Any of the "new" parameters can be '*' to leave the corresponding field
|
||||
* unchanged. The new login name can be '0' to log the user out.
|
||||
* If the UID is registered on the network, a SIGNON with the changes will be
|
||||
* broadcast, otherwise the changes will be stored, to be used when registration
|
||||
* completes.
|
||||
*/
|
||||
UplinkSocket::Message(Me) << "ENCAP " << msource.GetName() << " SVSLOGIN " << this->uid << " * * * " << this->GetAccount();
|
||||
UplinkSocket::Message(Me) << "ENCAP " << msource.GetName() << " SASL " << NickServ->GetUID() << " " << this->uid << " D S";
|
||||
}
|
||||
|
||||
void OnFail() anope_override
|
||||
{
|
||||
BotInfo *NickServ = Config->GetClient("NickServ");
|
||||
if (!NickServ)
|
||||
return;
|
||||
|
||||
UplinkSocket::Message(Me) << "ENCAP " << msource.GetName() << " SASL " << NickServ->GetUID() << " " << this->uid << " " << " D F";
|
||||
|
||||
Log(NickServ) << "A user failed to identify for account " << this->GetAccount() << " using SASL";
|
||||
}
|
||||
};
|
||||
if (params[4] == "S")
|
||||
{
|
||||
BotInfo *NickServ = Config->GetClient("NickServ");
|
||||
if (!NickServ)
|
||||
return;
|
||||
|
||||
if (params[5] == "PLAIN")
|
||||
UplinkSocket::Message(Me) << "ENCAP " << source.GetName() << " SASL " << NickServ->GetUID() << " " << params[2] << " C +";
|
||||
else
|
||||
UplinkSocket::Message(Me) << "ENCAP " << source.GetName() << " SASL " << NickServ->GetUID() << " " << params[2] << " D F";
|
||||
}
|
||||
else if (params[4] == "C")
|
||||
{
|
||||
Anope::string decoded;
|
||||
Anope::B64Decode(params[5], decoded);
|
||||
|
||||
size_t p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
decoded = decoded.substr(p + 1);
|
||||
|
||||
p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
Anope::string acc = decoded.substr(0, p),
|
||||
pass = decoded.substr(p + 1);
|
||||
|
||||
if (acc.empty() || pass.empty())
|
||||
return;
|
||||
|
||||
IdentifyRequest *req = new CharybdisSASLIdentifyRequest(this->owner, source, params[2], acc, pass);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
req->Dispatch();
|
||||
}
|
||||
SASL::sasl->ProcessMessage(m);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -279,7 +225,7 @@ struct IRCDMessageEUID : IRCDMessage
|
||||
if (params[9] != "*")
|
||||
na = NickAlias::Find(params[9]);
|
||||
|
||||
new User(params[0], params[4], params[8], params[5], params[6], source.GetServer(), params[10], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime, params[3], params[7], na ? *na->nc : NULL);
|
||||
User::OnIntroduce(params[0], params[4], params[8], params[5], params[6], source.GetServer(), params[10], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime, params[3], params[7], na ? *na->nc : NULL);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -417,7 +363,6 @@ class ProtoCharybdis : public Module
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock");
|
||||
sasl = conf->GetModule(this)->Get<bool>("sasl");
|
||||
}
|
||||
|
||||
void OnChannelSync(Channel *c) anope_override
|
||||
|
||||
+16
-17
@@ -16,6 +16,19 @@ static Anope::string UplinkSID;
|
||||
|
||||
class HybridProto : public IRCDProto
|
||||
{
|
||||
BotInfo *FindIntroduced()
|
||||
{
|
||||
BotInfo *bi = Config->GetClient("OperServ");
|
||||
if (bi && bi->introduced)
|
||||
return bi;
|
||||
|
||||
for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
|
||||
if (it->second->introduced)
|
||||
return it->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override
|
||||
{
|
||||
IRCDProto::SendSVSKillInternal(source, user, buf);
|
||||
@@ -54,7 +67,7 @@ class HybridProto : public IRCDProto
|
||||
|
||||
void SendSQLine(User *, const XLine *x) anope_override
|
||||
{
|
||||
UplinkSocket::Message(Config->GetClient("OperServ")) << "ENCAP * RESV " << (x->expires ? x->expires - Anope::CurTime : 0) << " " << x->mask << " 0 :" << x->reason;
|
||||
UplinkSocket::Message(FindIntroduced()) << "ENCAP * RESV " << (x->expires ? x->expires - Anope::CurTime : 0) << " " << x->mask << " 0 :" << x->reason;
|
||||
}
|
||||
|
||||
void SendSGLineDel(const XLine *x) anope_override
|
||||
@@ -233,21 +246,7 @@ class HybridProto : public IRCDProto
|
||||
|
||||
void SendTopic(const MessageSource &source, Channel *c) anope_override
|
||||
{
|
||||
BotInfo *bi = source.GetBot();
|
||||
bool needjoin = c->FindUser(bi) == NULL;
|
||||
|
||||
if (needjoin)
|
||||
{
|
||||
ChannelStatus status;
|
||||
|
||||
status.AddMode('o');
|
||||
bi->Join(c, &status);
|
||||
}
|
||||
|
||||
IRCDProto::SendTopic(source, c);
|
||||
|
||||
if (needjoin)
|
||||
bi->Part(c);
|
||||
UplinkSocket::Message(source) << "TBURST " << c->creation_time << " " << c->name << " " << c->topic_ts << " " << c->topic_setter << " :" << c->topic;
|
||||
}
|
||||
|
||||
void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) anope_override
|
||||
@@ -541,7 +540,7 @@ struct IRCDMessageUID : IRCDMessage
|
||||
na = NickAlias::Find(params[8]);
|
||||
|
||||
/* Source is always the server */
|
||||
new User(params[0], params[4], params[5], "",
|
||||
User::OnIntroduce(params[0], params[4], params[5], "",
|
||||
ip, source.GetServer(),
|
||||
params[9], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0,
|
||||
params[3], params[7], na ? *na->nc : NULL);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/sasl.h"
|
||||
|
||||
struct SASLUser
|
||||
{
|
||||
@@ -18,7 +19,6 @@ struct SASLUser
|
||||
time_t created;
|
||||
};
|
||||
|
||||
static bool sasl = true;
|
||||
static std::list<SASLUser> saslusers;
|
||||
|
||||
static Anope::string rsquit_server, rsquit_id;
|
||||
@@ -398,6 +398,33 @@ class InspIRCd12Proto : public IRCDProto
|
||||
{
|
||||
}
|
||||
|
||||
void SendSASLMessage(const SASL::Message &message) anope_override
|
||||
{
|
||||
UplinkSocket::Message(Me) << "ENCAP " << message.target.substr(0, 3) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext));
|
||||
}
|
||||
|
||||
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override
|
||||
{
|
||||
UplinkSocket::Message(Me) << "METADATA " << uid << " accountname :" << acc;
|
||||
|
||||
SASLUser su;
|
||||
su.uid = uid;
|
||||
su.acc = acc;
|
||||
su.created = Anope::CurTime;
|
||||
|
||||
for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
|
||||
{
|
||||
SASLUser &u = *it;
|
||||
|
||||
if (u.created + 30 < Anope::CurTime || u.uid == uid)
|
||||
it = saslusers.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
saslusers.push_back(su);
|
||||
}
|
||||
|
||||
bool IsExtbanValid(const Anope::string &mask) anope_override
|
||||
{
|
||||
return mask.length() >= 3 && mask[1] == ':';
|
||||
@@ -846,83 +873,16 @@ struct IRCDMessageEncap : IRCDMessage
|
||||
if (Anope::Match(Me->GetSID(), params[0]) == false)
|
||||
return;
|
||||
|
||||
if (sasl && params[1] == "SASL" && params.size() == 6)
|
||||
if (SASL::sasl && params[1] == "SASL" && params.size() >= 6)
|
||||
{
|
||||
class InspIRCDSASLIdentifyRequest : public IdentifyRequest
|
||||
{
|
||||
Anope::string uid;
|
||||
SASL::Message m;
|
||||
m.source = params[2];
|
||||
m.target = params[3];
|
||||
m.type = params[4];
|
||||
m.data = params[5];
|
||||
m.ext = params.size() > 6 ? params[6] : "";
|
||||
|
||||
public:
|
||||
InspIRCDSASLIdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id) { }
|
||||
|
||||
void OnSuccess() anope_override
|
||||
{
|
||||
UplinkSocket::Message(Me) << "METADATA " << this->uid << " accountname :" << this->GetAccount();
|
||||
UplinkSocket::Message(Me) << "ENCAP " << this->uid.substr(0, 3) << " SASL " << Me->GetSID() << " " << this->uid << " D S";
|
||||
|
||||
SASLUser su;
|
||||
su.uid = this->uid;
|
||||
su.acc = this->GetAccount();
|
||||
su.created = Anope::CurTime;
|
||||
|
||||
for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
|
||||
{
|
||||
SASLUser &u = *it;
|
||||
|
||||
if (u.created + 30 < Anope::CurTime || u.uid == this->uid)
|
||||
it = saslusers.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
saslusers.push_back(su);
|
||||
}
|
||||
|
||||
void OnFail() anope_override
|
||||
{
|
||||
UplinkSocket::Message(Me) << "ENCAP " << this->uid.substr(0, 3) << " SASL " << Me->GetSID() << " " << this->uid << " " << " D F";
|
||||
|
||||
Log(Config->GetClient("NickServ")) << "A user failed to identify for account " << this->GetAccount() << " using SASL";
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Received: :869 ENCAP * SASL 869AAAAAH * S PLAIN
|
||||
Sent: :00B ENCAP 869 SASL 00B 869AAAAAH C +
|
||||
Received: :869 ENCAP * SASL 869AAAAAH 00B C QWRhbQBBZGFtAG1vbw==
|
||||
base64(account\0account\0pass)
|
||||
*/
|
||||
if (params[4] == "S")
|
||||
{
|
||||
if (params[5] == "PLAIN")
|
||||
UplinkSocket::Message(Me) << "ENCAP " << params[2].substr(0, 3) << " SASL " << Me->GetSID() << " " << params[2] << " C +";
|
||||
else
|
||||
UplinkSocket::Message(Me) << "ENCAP " << params[2].substr(0, 3) << " SASL " << Me->GetSID() << " " << params[2] << " D F";
|
||||
}
|
||||
else if (params[4] == "C")
|
||||
{
|
||||
Anope::string decoded;
|
||||
Anope::B64Decode(params[5], decoded);
|
||||
|
||||
size_t p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
decoded = decoded.substr(p + 1);
|
||||
|
||||
p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
Anope::string acc = decoded.substr(0, p),
|
||||
pass = decoded.substr(p + 1);
|
||||
|
||||
if (acc.empty() || pass.empty())
|
||||
return;
|
||||
|
||||
IdentifyRequest *req = new InspIRCDSASLIdentifyRequest(this->owner, params[2], acc, pass);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
req->Dispatch();
|
||||
}
|
||||
SASL::sasl->ProcessMessage(m);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1323,7 +1283,7 @@ struct IRCDMessageUID : IRCDMessage
|
||||
modes += " " + params[i];
|
||||
|
||||
NickAlias *na = NULL;
|
||||
if (sasl)
|
||||
if (SASL::sasl)
|
||||
for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
|
||||
{
|
||||
SASLUser &u = *it;
|
||||
@@ -1339,7 +1299,9 @@ struct IRCDMessageUID : IRCDMessage
|
||||
++it;
|
||||
}
|
||||
|
||||
new User(params[2], params[5], params[3], params[4], params[6], source.GetServer(), params[params.size() - 1], ts, modes, params[0], na ? *na->nc : NULL);
|
||||
User *u = User::OnIntroduce(params[2], params[5], params[3], params[4], params[6], source.GetServer(), params[params.size() - 1], ts, modes, params[0], na ? *na->nc : NULL);
|
||||
if (u)
|
||||
u->signon = convertTo<time_t>(params[7]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1402,11 +1364,6 @@ class ProtoInspIRCd12 : public Module
|
||||
Servers::Capab.insert("NOQUIT");
|
||||
}
|
||||
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
sasl = conf->GetModule(this)->Get<bool>("sasl") || conf->GetModule("inspircd20")->Get<bool>("sasl");
|
||||
}
|
||||
|
||||
void OnUserNickChange(User *u, const Anope::string &) anope_override
|
||||
{
|
||||
/* InspIRCd 1.2 doesn't set -r on nick change, remove -r here. Note that if we have to set +r later
|
||||
|
||||
@@ -71,6 +71,8 @@ class InspIRCd20Proto : public IRCDProto
|
||||
void SendLogin(User *u, NickAlias *na) anope_override { insp12->SendLogin(u, na); }
|
||||
void SendLogout(User *u) anope_override { insp12->SendLogout(u); }
|
||||
void SendChannel(Channel *c) anope_override { insp12->SendChannel(c); }
|
||||
void SendSASLMessage(const SASL::Message &message) anope_override { insp12->SendSASLMessage(message); }
|
||||
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override { insp12->SendSVSLogin(uid, acc); }
|
||||
bool IsExtbanValid(const Anope::string &mask) anope_override { return insp12->IsExtbanValid(mask); }
|
||||
bool IsIdentValid(const Anope::string &ident) anope_override { return insp12->IsIdentValid(ident); }
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* ngIRCd Protocol module for Anope IRC Services
|
||||
*
|
||||
* (C) 2012 Anope Team <team@anope.org>
|
||||
* (C) 2011-2012 Alexander Barton <alex@barton.de>
|
||||
* (C) 2011-2012, 2014 Alexander Barton <alex@barton.de>
|
||||
* (C) 2011 Anope Team <team@anope.org>
|
||||
*
|
||||
* Please read COPYING and README for further details.
|
||||
@@ -15,6 +15,12 @@
|
||||
|
||||
class ngIRCdProto : public IRCDProto
|
||||
{
|
||||
void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override
|
||||
{
|
||||
IRCDProto::SendSVSKillInternal(source, user, buf);
|
||||
user->KillInternal(source, buf);
|
||||
}
|
||||
|
||||
public:
|
||||
ngIRCdProto(Module *creator) : IRCDProto(creator, "ngIRCd")
|
||||
{
|
||||
@@ -437,7 +443,7 @@ struct IRCDMessageNick : IRCDMessage
|
||||
else if (params.size() == 7)
|
||||
{
|
||||
// a new user is connecting to the network
|
||||
new User(params[0], params[2], params[3], "", "", source.GetServer(), params[6], Anope::CurTime, params[5], "", NULL);
|
||||
User::OnIntroduce(params[0], params[2], params[3], "", "", source.GetServer(), params[6], Anope::CurTime, params[5], "", NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -86,14 +86,12 @@ class PlexusProto : public IRCDProto
|
||||
if (!ident.empty())
|
||||
UplinkSocket::Message(Me) << "ENCAP * CHGIDENT " << u->GetUID() << " " << ident;
|
||||
UplinkSocket::Message(Me) << "ENCAP * CHGHOST " << u->GetUID() << " " << host;
|
||||
u->SetMode(Config->GetClient("HostServ"), "CLOAK");
|
||||
}
|
||||
|
||||
void SendVhostDel(User *u) anope_override
|
||||
{
|
||||
if (u->HasMode("CLOAK"))
|
||||
u->RemoveMode(Config->GetClient("HostServ"), "CLOAK");
|
||||
else
|
||||
this->SendVhost(u, u->GetIdent(), u->chost);
|
||||
u->RemoveMode(Config->GetClient("HostServ"), "CLOAK");
|
||||
}
|
||||
|
||||
void SendConnect() anope_override
|
||||
@@ -284,7 +282,7 @@ struct IRCDMessageUID : IRCDMessage
|
||||
if (params[8] != "0" && !na)
|
||||
na = NickAlias::Find(params[8]);
|
||||
|
||||
new User(params[0], params[4], params[9], params[5], ip, source.GetServer(), params[10], ts, params[3], params[7], na ? *na->nc : NULL);
|
||||
User::OnIntroduce(params[0], params[4], params[9], params[5], ip, source.GetServer(), params[10], ts, params[3], params[7], na ? *na->nc : NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ class RatboxProto : public IRCDProto
|
||||
void SendServer(const Server *server) anope_override { hybrid->SendServer(server); }
|
||||
void SendModeInternal(const MessageSource &source, User *u, const Anope::string &buf) anope_override { hybrid->SendModeInternal(source, u, buf); }
|
||||
void SendChannel(Channel *c) anope_override { hybrid->SendChannel(c); }
|
||||
void SendTopic(const MessageSource &source, Channel *c) anope_override { hybrid->SendTopic(source, c); }
|
||||
bool IsIdentValid(const Anope::string &ident) anope_override { return hybrid->IsIdentValid(ident); }
|
||||
|
||||
void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) anope_override
|
||||
@@ -94,6 +93,25 @@ class RatboxProto : public IRCDProto
|
||||
{
|
||||
UplinkSocket::Message(Me) << "ENCAP * SU " << u->GetUID();
|
||||
}
|
||||
|
||||
void SendTopic(const MessageSource &source, Channel *c) anope_override
|
||||
{
|
||||
BotInfo *bi = source.GetBot();
|
||||
bool needjoin = c->FindUser(bi) == NULL;
|
||||
|
||||
if (needjoin)
|
||||
{
|
||||
ChannelStatus status;
|
||||
|
||||
status.AddMode('o');
|
||||
bi->Join(c, &status);
|
||||
}
|
||||
|
||||
IRCDProto::SendTopic(source, c);
|
||||
|
||||
if (needjoin)
|
||||
bi->Part(c);
|
||||
}
|
||||
};
|
||||
|
||||
struct IRCDMessageEncap : IRCDMessage
|
||||
@@ -179,7 +197,7 @@ struct IRCDMessageUID : IRCDMessage
|
||||
void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
||||
{
|
||||
/* Source is always the server */
|
||||
new User(params[0], params[4], params[5], "", params[6], source.GetServer(), params[8], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0, params[3], params[7], NULL);
|
||||
User::OnIntroduce(params[0], params[4], params[5], "", params[6], source.GetServer(), params[8], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0, params[3], params[7], NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+31
-75
@@ -11,8 +11,7 @@
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/cs_mode.h"
|
||||
|
||||
static bool sasl = true;
|
||||
#include "modules/sasl.h"
|
||||
|
||||
class UnrealIRCdProto : public IRCDProto
|
||||
{
|
||||
@@ -377,6 +376,23 @@ class UnrealIRCdProto : public IRCDProto
|
||||
}
|
||||
}
|
||||
|
||||
void SendSASLMessage(const SASL::Message &message) anope_override
|
||||
{
|
||||
size_t p = message.target.find('!');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext);
|
||||
}
|
||||
|
||||
void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override
|
||||
{
|
||||
size_t p = uid.find('!');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
UplinkSocket::Message(Me) << "SVSLOGIN " << uid.substr(0, p) << " " << uid << " " << acc;
|
||||
}
|
||||
|
||||
bool IsIdentValid(const Anope::string &ident) anope_override
|
||||
{
|
||||
if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
|
||||
@@ -839,7 +855,7 @@ struct IRCDMessageNick : IRCDMessage
|
||||
na = NickAlias::Find(params[6]);
|
||||
}
|
||||
|
||||
new User(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL);
|
||||
User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL);
|
||||
}
|
||||
else
|
||||
source.GetUser()->ChangeNick(params[0]);
|
||||
@@ -868,80 +884,22 @@ struct IRCDMessagePong : IRCDMessage
|
||||
|
||||
struct IRCDMessageSASL : IRCDMessage
|
||||
{
|
||||
class UnrealSASLIdentifyRequest : public IdentifyRequest
|
||||
{
|
||||
Anope::string uid;
|
||||
IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
|
||||
|
||||
public:
|
||||
UnrealSASLIdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id) { }
|
||||
|
||||
void OnSuccess() anope_override
|
||||
{
|
||||
size_t p = this->uid.find('!');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
UplinkSocket::Message(Me) << "SVSLOGIN " << this->uid.substr(0, p) << " " << this->uid << " " << this->GetAccount();
|
||||
UplinkSocket::Message() << "SASL " << this->uid.substr(0, p) << " " << this->uid << " D S";
|
||||
}
|
||||
|
||||
void OnFail() anope_override
|
||||
{
|
||||
size_t p = this->uid.find('!');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
UplinkSocket::Message() << "SASL " << this->uid.substr(0, p) << " " << this->uid << " D F";
|
||||
|
||||
Log(Config->GetClient("NickServ")) << "A user failed to identify for account " << this->GetAccount() << " using SASL";
|
||||
}
|
||||
};
|
||||
|
||||
IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
|
||||
|
||||
/* Received: :irc.foonet.com SASL services.localhost.net irc.foonet.com!1.57290 S PLAIN
|
||||
* uid
|
||||
*
|
||||
* Received: :irc.foonet.com SASL services.localhost.net irc.foonet.com!3.56270 C QWRhbQBBZGFtAHF3ZXJ0eQ==
|
||||
* uid base64(account\0account\0pass)
|
||||
*/
|
||||
void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
||||
{
|
||||
size_t p = params[1].find('!');
|
||||
if (!sasl || p == Anope::string::npos)
|
||||
if (!SASL::sasl || p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
if (params[2] == "S")
|
||||
{
|
||||
if (params[3] == "PLAIN")
|
||||
UplinkSocket::Message() << "SASL " << params[1].substr(0, p) << " " << params[1] << " C +";
|
||||
else
|
||||
UplinkSocket::Message() << "SASL " << params[1].substr(0, p) << " " << params[1] << " D F";
|
||||
}
|
||||
else if (params[2] == "C")
|
||||
{
|
||||
Anope::string decoded;
|
||||
Anope::B64Decode(params[3], decoded);
|
||||
SASL::Message m;
|
||||
m.source = params[1];
|
||||
m.target = params[0];
|
||||
m.type = params[2];
|
||||
m.data = params[3];
|
||||
m.ext = params.size() > 4 ? params[4] : "";
|
||||
|
||||
p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
decoded = decoded.substr(p + 1);
|
||||
|
||||
p = decoded.find('\0');
|
||||
if (p == Anope::string::npos)
|
||||
return;
|
||||
|
||||
Anope::string acc = decoded.substr(0, p),
|
||||
pass = decoded.substr(p + 1);
|
||||
|
||||
if (acc.empty() || pass.empty())
|
||||
return;
|
||||
|
||||
IdentifyRequest *req = new UnrealSASLIdentifyRequest(this->owner, params[1], acc, pass);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
req->Dispatch();
|
||||
}
|
||||
SASL::sasl->ProcessMessage(m);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -984,13 +942,12 @@ struct IRCDMessageSetIdent : IRCDMessage
|
||||
|
||||
struct IRCDMessageSetName : IRCDMessage
|
||||
{
|
||||
IRCDMessageSetName(Module *creator) : IRCDMessage(creator, "SETNAME", 1) { }
|
||||
IRCDMessageSetName(Module *creator) : IRCDMessage(creator, "SETNAME", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
|
||||
|
||||
void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
||||
{
|
||||
User *u = User::Find(params[0]);
|
||||
if (u)
|
||||
u->SetRealname(params[1]);
|
||||
User *u = source.GetUser();
|
||||
u->SetRealname(params[0]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1237,7 +1194,6 @@ class ProtoUnreal : public Module
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock");
|
||||
sasl = conf->GetModule(this)->Get<bool>("sasl");
|
||||
}
|
||||
|
||||
void OnUserNickChange(User *u, const Anope::string &) anope_override
|
||||
|
||||
@@ -25,15 +25,7 @@ class BotServCore : public Module
|
||||
void OnReload(Configuration::Conf *conf) anope_override
|
||||
{
|
||||
const Anope::string &bsnick = conf->GetModule(this)->Get<const Anope::string>("client");
|
||||
|
||||
if (bsnick.empty())
|
||||
throw ConfigException(Module::name + ": <client> must be defined");
|
||||
|
||||
BotInfo *bi = BotInfo::Find(bsnick, true);
|
||||
if (!bi)
|
||||
throw ConfigException(Module::name + ": no bot named " + bsnick);
|
||||
|
||||
BotServ = bi;
|
||||
BotServ = BotInfo::Find(bsnick, true);
|
||||
}
|
||||
|
||||
void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) anope_override
|
||||
@@ -144,7 +136,7 @@ class BotServCore : public Module
|
||||
"channel, and provide a more convenient way to execute commands. Commands that\n"
|
||||
"require a channel as a parameter will automatically have that parameter\n"
|
||||
"given.\n"), source.service->nick.c_str());
|
||||
const Anope::string &fantasycharacters = Config->GetModule(this)->Get<const Anope::string>("fantasycharacter", "!");
|
||||
const Anope::string &fantasycharacters = Config->GetModule("fantasy")->Get<const Anope::string>("fantasycharacter", "!");
|
||||
if (!fantasycharacters.empty())
|
||||
source.Reply(_(" \n"
|
||||
"Fantasy commands may be prefixed with one of the following characters: %s\n"), fantasycharacters.c_str());
|
||||
@@ -175,7 +167,7 @@ class BotServCore : public Module
|
||||
source.Reply(_(" \n"
|
||||
"Bot will join a channel whenever there is at least\n"
|
||||
"\002%d\002 user(s) on it."), Config->GetModule(this)->Get<unsigned>("minusers"));
|
||||
const Anope::string &fantasycharacters = Config->GetModule(this)->Get<const Anope::string>("fantasycharacter", "!");
|
||||
const Anope::string &fantasycharacters = Config->GetModule("fantasy")->Get<const Anope::string>("fantasycharacter", "!");
|
||||
if (!fantasycharacters.empty())
|
||||
source.Reply(_("Additionally, if fantasy is enabled fantasy commands\n"
|
||||
"can be executed by prefixing the command name with\n"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user