mirror of
https://github.com/anope/anope.git
synced 2026-06-25 15:26:39 +02:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -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"; }
|
||||
|
||||
+3
-8
@@ -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
|
||||
@@ -1223,6 +1217,7 @@ module
|
||||
*
|
||||
*/
|
||||
|
||||
#module { name = "enc_bcrypt" }
|
||||
module { name = "enc_sha256" }
|
||||
#module { name = "enc_md5" }
|
||||
#module { name = "enc_sha1" }
|
||||
|
||||
@@ -139,7 +139,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-aes [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";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+101
-2
@@ -1,5 +1,104 @@
|
||||
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 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,7 @@ 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
|
||||
|
||||
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
|
||||
|
||||
+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
|
||||
|
||||
@@ -52,4 +52,5 @@ struct Exception;
|
||||
struct MemoInfo;
|
||||
struct ModeLock;
|
||||
struct Oper;
|
||||
namespace SASL { struct Message; }
|
||||
|
||||
|
||||
@@ -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,115 @@
|
||||
/*
|
||||
*
|
||||
* (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)
|
||||
return OnFail();
|
||||
|
||||
Session *s = sasl->GetSession(uid);
|
||||
if (s)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
Log(Config->GetClient("NickServ")) << "A user failed to identify for 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() { }
|
||||
};
|
||||
@@ -217,6 +217,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, ...);
|
||||
|
||||
+1
-1
@@ -323,7 +323,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
|
||||
|
||||
+356
-360
File diff suppressed because it is too large
Load Diff
+357
-361
File diff suppressed because it is too large
Load Diff
+355
-359
File diff suppressed because it is too large
Load Diff
+362
-364
File diff suppressed because it is too large
Load Diff
+367
-370
File diff suppressed because it is too large
Load Diff
+354
-358
File diff suppressed because it is too large
Load Diff
+2965
-3625
File diff suppressed because it is too large
Load Diff
+371
-374
File diff suppressed because it is too large
Load Diff
+354
-358
File diff suppressed because it is too large
Load Diff
+354
-358
File diff suppressed because it is too large
Load Diff
+360
-364
File diff suppressed because it is too large
Load Diff
+354
-358
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"))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(' ');
|
||||
@@ -165,16 +162,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 +204,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:
|
||||
|
||||
@@ -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,12 @@ struct NSCertListImpl : NSCertList
|
||||
Anope::string buf;
|
||||
data["cert"] >> buf;
|
||||
spacesepstream sep(buf);
|
||||
c->certs.clear();
|
||||
c->ClearCert();
|
||||
while (sep.GetToken(buf))
|
||||
{
|
||||
c->certs.push_back(buf);
|
||||
certmap[buf] = n;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -308,10 +335,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 +347,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -223,15 +223,7 @@ class CommandNSRegister : public Command
|
||||
else if (nsregister.equals_ci("mail"))
|
||||
{
|
||||
nc->Extend<bool>("UNCONFIRMED");
|
||||
if (SendRegmail(u, na, source.service))
|
||||
{
|
||||
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());
|
||||
}
|
||||
SendRegmail(NULL, na, source.service);
|
||||
}
|
||||
|
||||
if (u)
|
||||
@@ -368,12 +360,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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+114
-10
@@ -14,6 +14,8 @@
|
||||
#include "modules/cs_mode.h"
|
||||
#include "modules/bs_badwords.h"
|
||||
#include "modules/os_news.h"
|
||||
#include "modules/suspend.h"
|
||||
#include "modules/os_forbid.h"
|
||||
|
||||
#define READ(x) \
|
||||
if (true) \
|
||||
@@ -48,6 +50,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 +59,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
|
||||
@@ -423,6 +426,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;
|
||||
@@ -495,7 +499,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 +616,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 +727,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 +792,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 +801,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 +837,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 +847,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));
|
||||
@@ -957,6 +1035,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 Session : SASL::Session
|
||||
{
|
||||
DH* dh;
|
||||
Session(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;
|
||||
}
|
||||
}
|
||||
|
||||
~Session()
|
||||
{
|
||||
if (dh)
|
||||
DH_free(dh);
|
||||
}
|
||||
};
|
||||
|
||||
DH* dh_params;
|
||||
const size_t keysize;
|
||||
SASL::Session* CreateSession(const Anope::string &uid) anope_override
|
||||
{
|
||||
return new Session(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
|
||||
{
|
||||
Session *sess = anope_dynamic_static_cast<Session *>(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 Session : SASL::Session
|
||||
{
|
||||
DH* dh;
|
||||
Session(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;
|
||||
}
|
||||
}
|
||||
|
||||
~Session()
|
||||
{
|
||||
if (dh)
|
||||
DH_free(dh);
|
||||
}
|
||||
};
|
||||
|
||||
DH* dh_params;
|
||||
const size_t keysize;
|
||||
SASL::Session* CreateSession(const Anope::string &uid) anope_override
|
||||
{
|
||||
return new Session(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
|
||||
{
|
||||
Session *sess = anope_dynamic_static_cast<Session *>(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,639 @@
|
||||
/*
|
||||
* (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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
gnutls_certificate_client_set_retrieve_function(cred, cert_callback);
|
||||
}
|
||||
|
||||
~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();
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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,272 @@
|
||||
/*
|
||||
*
|
||||
* (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)
|
||||
{
|
||||
sasl->Fail(sess);
|
||||
delete sess;
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -233,21 +233,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
|
||||
|
||||
@@ -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;
|
||||
@@ -1402,11 +1362,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); }
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
+27
-70
@@ -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"))
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1236,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
|
||||
|
||||
@@ -16,7 +16,7 @@ bool WebCPanel::OperServ::Akill::OnRequest(HTTPProvider *server, const Anope::st
|
||||
|
||||
static ServiceReference<XLineManager> akills("XLineManager","xlinemanager/sgline");
|
||||
|
||||
if (!na->nc->IsServicesOper() && !(na->nc->o && na->nc->o->ot && na->nc->o->ot->HasPriv("operserv/akill")))
|
||||
if (!na->nc->o || !na->nc->o->ot->HasCommand("operserv/akill"))
|
||||
{
|
||||
replacements["NOACCESS"];
|
||||
}
|
||||
|
||||
@@ -220,8 +220,11 @@ void TemplateFileServer::Serve(HTTPProvider *server, const Anope::string &page_n
|
||||
Log() << "Invalid INCLUDE in web template " << this->file_name;
|
||||
else
|
||||
{
|
||||
reply.Write(finished); // Write out what we have currently so we insert this files contents here
|
||||
finished.clear();
|
||||
if (!finished.empty())
|
||||
{
|
||||
reply.Write(finished); // Write out what we have currently so we insert this files contents here
|
||||
finished.clear();
|
||||
}
|
||||
|
||||
TemplateFileServer tfs(tokens[1]);
|
||||
tfs.Serve(server, page_name, client, message, reply, r);
|
||||
@@ -255,7 +258,7 @@ void TemplateFileServer::Serve(HTTPProvider *server, const Anope::string &page_n
|
||||
}
|
||||
}
|
||||
|
||||
reply.Write(finished);
|
||||
return;
|
||||
if (!finished.empty())
|
||||
reply.Write(finished);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-offset-3 col-lg-6">
|
||||
<div class="footer text-center">
|
||||
Anope IRC Services - © 2013 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
Anope IRC Services - © 2013-2014 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="footer text-center">
|
||||
Anope IRC Services - © 2013 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
Anope IRC Services - © 2013-2014 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-offset-3 col-lg-6">
|
||||
<div class="footer text-center">
|
||||
Anope IRC Services - © 2013 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
Anope IRC Services - © 2013-2014 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-offset-3 col-lg-6">
|
||||
<div class="footer text-center">
|
||||
Anope IRC Services - © 2013 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
Anope IRC Services - © 2013-2014 Anope Team - <a href="http://anope.org">http://anope.org</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,4 +62,4 @@
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -240,6 +240,9 @@ namespace WebPanel
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < cmd->min_params)
|
||||
return;
|
||||
|
||||
BotInfo *bi = Config->GetClient(service);
|
||||
if (!bi)
|
||||
{
|
||||
@@ -263,6 +266,13 @@ namespace WebPanel
|
||||
my_reply(r, key);
|
||||
|
||||
CommandSource source(user, NULL, nc, &my_reply, bi);
|
||||
|
||||
if (!cmd->AllowUnregistered() && !source.nc)
|
||||
{
|
||||
r[key] = "Access denied.";
|
||||
return;
|
||||
}
|
||||
|
||||
cmd->Execute(source, params);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ void Anope::B64Decode(const Anope::string &src, Anope::string &target)
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
if (!target[target.length() - 1])
|
||||
if (!target.empty() && !target[target.length() - 1])
|
||||
target.erase(target.length() - 1);
|
||||
}
|
||||
|
||||
|
||||
+6
-9
@@ -85,13 +85,17 @@ void Channel::Reset()
|
||||
for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
|
||||
this->SetCorrectModes(it->second->user, true);
|
||||
|
||||
this->Sync();
|
||||
// If the channel is syncing now, do not force a sync due to Reset(), as we are probably iterating over users in Message::SJoin
|
||||
// A sync will come soon
|
||||
if (!syncing)
|
||||
this->Sync();
|
||||
}
|
||||
|
||||
void Channel::Sync()
|
||||
{
|
||||
syncing = false;
|
||||
FOREACH_MOD(OnChannelSync, (this));
|
||||
CheckModes();
|
||||
}
|
||||
|
||||
void Channel::CheckModes()
|
||||
@@ -727,11 +731,7 @@ bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...)
|
||||
vsnprintf(buf, BUFSIZE - 1, reason, args);
|
||||
va_end(args);
|
||||
|
||||
/* May not kick ulines */
|
||||
if (u->server->IsULined())
|
||||
return false;
|
||||
|
||||
/* Do not kick protected clients */
|
||||
/* Do not kick protected clients or Ulines */
|
||||
if (u->IsProtected())
|
||||
return false;
|
||||
|
||||
@@ -863,9 +863,6 @@ bool Channel::CheckKick(User *user)
|
||||
|
||||
/* We don't enforce services restrictions on clients on ulined services
|
||||
* as this will likely lead to kick/rejoin floods. ~ Viper */
|
||||
if (user->server->IsULined())
|
||||
return false;
|
||||
|
||||
if (user->IsProtected())
|
||||
return false;
|
||||
|
||||
|
||||
@@ -322,6 +322,9 @@ bool IRCDProto::IsChannelValid(const Anope::string &chan)
|
||||
if (chan.empty() || chan[0] != '#' || chan.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen"))
|
||||
return false;
|
||||
|
||||
if (chan.find_first_of(" ,") != Anope::string::npos)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,10 @@ bool BufferedSocket::ProcessRead()
|
||||
this->recv_len = 0;
|
||||
|
||||
int len = this->io->Recv(this, tbuffer, sizeof(tbuffer) - 1);
|
||||
if (len <= 0)
|
||||
if (len == 0)
|
||||
return false;
|
||||
if (len < 0)
|
||||
return SocketEngine::IgnoreErrno();
|
||||
|
||||
tbuffer[len] = 0;
|
||||
this->read_buffer.append(tbuffer);
|
||||
@@ -42,8 +44,11 @@ bool BufferedSocket::ProcessRead()
|
||||
bool BufferedSocket::ProcessWrite()
|
||||
{
|
||||
int count = this->io->Send(this, this->write_buffer);
|
||||
if (count <= -1)
|
||||
if (count == 0)
|
||||
return false;
|
||||
if (count < 0)
|
||||
return SocketEngine::IgnoreErrno();
|
||||
|
||||
this->write_buffer = this->write_buffer.substr(count);
|
||||
if (this->write_buffer.empty())
|
||||
SocketEngine::Change(this, false, SF_WRITABLE);
|
||||
@@ -58,8 +63,8 @@ const Anope::string BufferedSocket::GetLine()
|
||||
return "";
|
||||
Anope::string str = this->read_buffer.substr(0, s + 1);
|
||||
this->read_buffer.erase(0, s + 1);
|
||||
this->read_buffer.ltrim();
|
||||
return str.trim();
|
||||
this->read_buffer.ltrim("\r\n");
|
||||
return str.trim("\r\n");
|
||||
}
|
||||
|
||||
void BufferedSocket::Write(const char *buffer, size_t l)
|
||||
@@ -162,6 +167,8 @@ bool BinarySocket::ProcessWrite()
|
||||
|
||||
void BinarySocket::Write(const char *buffer, size_t l)
|
||||
{
|
||||
if (l == 0)
|
||||
return;
|
||||
this->write_buffer.push_back(new DataBlock(buffer, l));
|
||||
SocketEngine::Change(this, true, SF_WRITABLE);
|
||||
}
|
||||
|
||||
+35
-7
@@ -348,15 +348,17 @@ size_t cidr::hash::operator()(const cidr &s) const
|
||||
|
||||
int SocketIO::Recv(Socket *s, char *buf, size_t sz)
|
||||
{
|
||||
size_t i = recv(s->GetFD(), buf, sz, 0);
|
||||
TotalRead += i;
|
||||
int i = recv(s->GetFD(), buf, sz, 0);
|
||||
if (i > 0)
|
||||
TotalRead += i;
|
||||
return i;
|
||||
}
|
||||
|
||||
int SocketIO::Send(Socket *s, const char *buf, size_t sz)
|
||||
{
|
||||
size_t i = send(s->GetFD(), buf, sz, 0);
|
||||
TotalWritten += i;
|
||||
int i = send(s->GetFD(), buf, sz, 0);
|
||||
if (i > 0)
|
||||
TotalWritten += i;
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -402,7 +404,7 @@ void SocketIO::Connect(ConnectionSocket *s, const Anope::string &target, int por
|
||||
int c = connect(s->GetFD(), &s->conaddr.sa, s->conaddr.size());
|
||||
if (c == -1)
|
||||
{
|
||||
if (Anope::LastErrorCode() != EINPROGRESS)
|
||||
if (!SocketEngine::IgnoreErrno())
|
||||
s->OnError(Anope::LastError());
|
||||
else
|
||||
{
|
||||
@@ -515,8 +517,8 @@ ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool i)
|
||||
{
|
||||
this->SetBlocking(false);
|
||||
|
||||
const char op = 1;
|
||||
setsockopt(this->GetFD(), SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op));
|
||||
const int op = 1;
|
||||
setsockopt(this->GetFD(), SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&op), sizeof(op));
|
||||
|
||||
this->bindaddr.pton(i ? AF_INET6 : AF_INET, bindip, port);
|
||||
this->io->Bind(this, bindip, port);
|
||||
@@ -542,3 +544,29 @@ bool ListenSocket::ProcessRead()
|
||||
return true;
|
||||
}
|
||||
|
||||
int SocketEngine::GetLastError()
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return errno;
|
||||
#else
|
||||
return WSAGetLastError();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SocketEngine::SetLastError(int err)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
errno = err;
|
||||
#else
|
||||
WSASetLastError(err);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketEngine::IgnoreErrno()
|
||||
{
|
||||
return GetLastError() == EAGAIN
|
||||
|| GetLastError() == EWOULDBLOCK
|
||||
|| GetLastError() == EINTR
|
||||
|| GetLastError() == EINPROGRESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
ANOPEPID="@INSTDIR@/data/services.pid"
|
||||
ANOPROG="@INSTDIR@/bin/services"
|
||||
LOG="@INSTDIR@/data/logs/"
|
||||
ARCVERSION="1.4"
|
||||
ARCVERSION="2"
|
||||
|
||||
isAnopeRunning () {
|
||||
if [ ! -f $ANOPEPID ] ; then
|
||||
@@ -26,8 +26,8 @@ isAnopeRunning () {
|
||||
fi
|
||||
|
||||
PID=`cat $ANOPEPID`
|
||||
|
||||
if [ ! `ps auxw | grep $ANOPROG | grep $PID | grep -v -c grep` ] ; then
|
||||
kill -0 $PID 2>/dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Warning: Anope is not currently running"
|
||||
exit 1
|
||||
fi
|
||||
@@ -48,7 +48,8 @@ fi
|
||||
if [ "$1" = "start" ] ; then
|
||||
if [ -f $ANOPEPID ] ; then
|
||||
PID=`cat $ANOPEPID`
|
||||
if [ `ps auxw | grep $ANOPROG | grep $PID | grep -v -c grep` = 1 ] ; then
|
||||
kill -0 $PID 2>/dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo "Warning! Anope is already running"
|
||||
exit 1
|
||||
fi
|
||||
@@ -76,7 +77,8 @@ elif [ "$1" = "stop" ] ; then
|
||||
elif [ "$1" = "status" ] ; then
|
||||
if [ -f $ANOPEPID ] ; then
|
||||
PID=`cat $ANOPEPID`
|
||||
if [ `ps auxw | grep $PID | grep -v -c grep` = 1 ] ; then
|
||||
kill -0 $PID 2>/dev/null
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo "Anope is currently running"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
+2
-5
@@ -642,12 +642,9 @@ ChanUserContainer *User::FindChannel(Channel *c) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool User::IsProtected() const
|
||||
bool User::IsProtected()
|
||||
{
|
||||
if (this->HasMode("PROTECTED") || this->HasMode("GOD"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return this->HasMode("PROTECTED") || this->HasMode("GOD") || this->HasPriv("protected") || (this->server && this->server->IsULined());
|
||||
}
|
||||
|
||||
void User::Kill(const MessageSource &source, const Anope::string &reason)
|
||||
|
||||
+1
-1
@@ -3,5 +3,5 @@
|
||||
VERSION_MAJOR="2"
|
||||
VERSION_MINOR="0"
|
||||
VERSION_PATCH="0"
|
||||
VERSION_EXTRA="-rc3"
|
||||
VERSION_EXTRA="-rc4"
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
#include "pthread/pthread.h"
|
||||
#include "sigaction/sigaction.h"
|
||||
|
||||
typedef int ssize_t;
|
||||
|
||||
namespace Anope
|
||||
{
|
||||
class string;
|
||||
|
||||
Reference in New Issue
Block a user