diff options
author | lethality <lee@lethality.me.uk> | 2014-02-18 22:24:24 +0000 |
---|---|---|
committer | lethality <lee@lethality.me.uk> | 2014-02-18 22:24:24 +0000 |
commit | 5933a5e9b1ade9f926145b67e557b87ae6dd6e8f (patch) | |
tree | 41c9c8b4c1818531251c292ce184601a8721aed4 | |
parent | f1c5c27f3fda90265d5da8205db1bdd4d12c9851 (diff) | |
parent | 109d8f431f3d25d56570a6aaa1af957867bbb80e (diff) |
Merge remote branch 'upstream/2.0' into 2.0
26 files changed, 880 insertions, 486 deletions
diff --git a/data/example.conf b/data/example.conf index fbb7e310e..4d4ba6b17 100644 --- a/data/example.conf +++ b/data/example.conf @@ -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 diff --git a/data/modules.example.conf b/data/modules.example.conf index e58ebea88..30927433f 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -201,7 +201,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 @@ -357,6 +357,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 @@ -469,6 +545,69 @@ module { name = "help" } #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] * * This module allows authenticating users against an external SQL database using a custom @@ -586,101 +725,26 @@ module { name = "help" } } /* - * 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] + * webcpanel * - * Provides the regex engine regex/tre, which uses the TRE regex library. - */ -#module { name = "m_regex_tre" } - -/* - * m_rewrite + * 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. * - * Allows rewriting commands sent to/from clients. + * This module requires m_httpd. */ -#module { name = "m_rewrite" } -#command +#module { - 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 *" + name = "webcpanel" - /* - * 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" -} + /* Web server to use. */ + server = "httpd/main"; -/* - * m_ssl [EXTRA] - * - * This module uses SSL to connect to the uplink server(s). - */ -#module -{ - name = "m_ssl" + /* Template to use. */ + template = "default"; - /* - * 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"; } /* @@ -704,26 +768,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"; -} diff --git a/data/stats.standalone.example.conf b/data/stats.standalone.example.conf index 7ba985e19..8db7c9999 100644 --- a/data/stats.standalone.example.conf +++ b/data/stats.standalone.example.conf @@ -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 diff --git a/docs/Changes.conf b/docs/Changes.conf index aae151fd9..8b41ad2be 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -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 ------------------- diff --git a/docs/IRCD b/docs/IRCD deleted file mode 100644 index 7a3effbb3..000000000 --- a/docs/IRCD +++ /dev/null @@ -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.
diff --git a/docs/WIN32.txt b/docs/WIN32.txt index 7922523f4..018b898d2 100644 --- a/docs/WIN32.txt +++ b/docs/WIN32.txt @@ -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
diff --git a/modules/encryption/encryption.h b/include/modules/encryption.h index 95c5703aa..95c5703aa 100644 --- a/modules/encryption/encryption.h +++ b/include/modules/encryption.h diff --git a/include/modules/os_forbid.h b/include/modules/os_forbid.h index 3f1fe9a7f..fe96ba5c6 100644 --- a/include/modules/os_forbid.h +++ b/include/modules/os_forbid.h @@ -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 diff --git a/include/modules/os_ignore.h b/include/modules/os_ignore.h index 0f2c2f0d8..2511d47b2 100644 --- a/include/modules/os_ignore.h +++ b/include/modules/os_ignore.h @@ -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 void DelIgnore(IgnoreData *) = 0; - virtual bool DelIgnore(const Anope::string &mask) = 0; + virtual void ClearIgnores() = 0; - inline void ClearIgnores() { this->ignores.clear(); } + 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); -} - diff --git a/include/service.h b/include/service.h index db0b2af4b..8142363d6 100644 --- a/include/service.h +++ b/include/service.h @@ -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 { diff --git a/include/sockets.h b/include/sockets.h index 744f1a23e..0dfa5d9d0 100644 --- a/include/sockets.h +++ b/include/sockets.h @@ -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, ...); diff --git a/modules/commands/os_forbid.cpp b/modules/commands/os_forbid.cpp index c1fe1af8b..11215ab05 100644 --- a/modules/commands/os_forbid.cpp +++ b/modules/commands/os_forbid.cpp @@ -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) { } diff --git a/modules/commands/os_ignore.cpp b/modules/commands/os_ignore.cpp index b4d4b09a3..e00b4dd31 100644 --- a/modules/commands/os_ignore.cpp +++ b/modules/commands/os_ignore.cpp @@ -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 { + Serialize::Checker<std::vector<IgnoreData *> > ignores; + public: - OSIgnoreService(Module *o) : IgnoreService(o) { } + OSIgnoreService(Module *o) : IgnoreService(o), ignores("IgnoreData") { } - IgnoreData* AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) anope_override + void AddIgnore(IgnoreData *ign) anope_override { - /* Check if we already got an identical entry. */ - IgnoreData *ign = this->Find(mask); - if (ign != NULL) - { - 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(); - } + ignores->push_back(ign); } - bool DelIgnore(const Anope::string &mask) anope_override + void DelIgnore(IgnoreData *ign) anope_override { - for (std::list<IgnoreData>::iterator it = this->ignores.begin(), it_end = this->ignores.end(); it != it_end; ++it) + 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) { - IgnoreData &idn = *it; - if (idn.mask.equals_ci(mask)) - { - this->ignores.erase(it); - return true; - } + IgnoreData *ign = ignores->at(i - 1); + delete ign; } + } - return false; + IgnoreData *Create() anope_override + { + 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) { } diff --git a/modules/commands/os_session.cpp b/modules/commands/os_session.cpp index 8f5abdc1d..d3e82b04a 100644 --- a/modules/commands/os_session.cpp +++ b/modules/commands/os_session.cpp @@ -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; diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp index 8c322d02e..8fe57cfdd 100644 --- a/modules/database/db_old.cpp +++ b/modules/database/db_old.cpp @@ -620,9 +620,18 @@ static void LoadNicks() if (tmpu16 & OLD_NS_VERBOTEN) { if (!forbid) + { + delete nc; + continue; + } + + if (nc->display.find_first_of("?*") != Anope::string::npos) + { + delete nc; continue; + } - ForbidData *d = new ForbidData(); + ForbidData *d = forbid->CreateForbid(); d->mask = nc->display; d->creator = last_usermask; d->reason = last_realname; @@ -783,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) @@ -1029,9 +1038,18 @@ 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 = new ForbidData(); + ForbidData *d = forbid->CreateForbid(); d->mask = ci->name; d->creator = forbidby; d->reason = forbidreason; diff --git a/modules/encryption/enc_md5.cpp b/modules/encryption/enc_md5.cpp index ae51e0394..b56f03324 100644 --- a/modules/encryption/enc_md5.cpp +++ b/modules/encryption/enc_md5.cpp @@ -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. diff --git a/modules/encryption/enc_old.cpp b/modules/encryption/enc_old.cpp index e56224e22..c8c1093da 100644 --- a/modules/encryption/enc_old.cpp +++ b/modules/encryption/enc_old.cpp @@ -10,7 +10,7 @@ */ #include "module.h" -#include "encryption.h" +#include "modules/encryption.h" static ServiceReference<Encryption::Provider> md5("Encryption::Provider", "md5"); diff --git a/modules/encryption/enc_sha1.cpp b/modules/encryption/enc_sha1.cpp index 4ef3e51fe..38f32b2cb 100644 --- a/modules/encryption/enc_sha1.cpp +++ b/modules/encryption/enc_sha1.cpp @@ -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 { diff --git a/modules/encryption/enc_sha256.cpp b/modules/encryption/enc_sha256.cpp index 7533c2891..cccbceea1 100644 --- a/modules/encryption/enc_sha256.cpp +++ b/modules/encryption/enc_sha256.cpp @@ -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; diff --git a/modules/extra/enc_bcrypt.cpp b/modules/extra/enc_bcrypt.cpp index 67f2e8bef..cd5e05c35 100644 --- a/modules/extra/enc_bcrypt.cpp +++ b/modules/extra/enc_bcrypt.cpp @@ -1,7 +1,7 @@ /* RequiredLibraries: xcrypt */ #include "module.h" -#include "encryption.h" +#include "modules/encryption.h" #include <xcrypt.h> class EBCRYPT : public Module diff --git a/modules/extra/m_ssl_gnutls.cpp b/modules/extra/m_ssl_gnutls.cpp new file mode 100644 index 000000000..002015f5f --- /dev/null +++ b/modules/extra/m_ssl_gnutls.cpp @@ -0,0 +1,509 @@ +/* + * (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> + +class GnuTLSModule; +static GnuTLSModule *me; + +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; + + /** Constructor + */ + SSLSocketIO() : sess(NULL) { } + + /** 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 X509CertCredentials + { + gnutls_certificate_credentials_t cred; + DHParams dh; + + public: + X509CertCredentials() + { + if (gnutls_certificate_allocate_credentials(&cred) < 0) + throw ConfigException("Cannot allocate certificate credentials"); + } + + ~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 SetCertAndKey(const Anope::string &certfile, const Anope::string &keyfile) + { + int ret = gnutls_certificate_set_x509_key_file(cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM); + if (ret < 0) + throw ConfigException("Unable to load certificate/private key: " + Anope::string(gnutls_strerror(ret))); + } + + void SetDH(const Anope::string &dhfile) + { + std::ifstream ifs(dhfile.c_str()); + const Anope::string dhdata((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); + + dh.Import(dhdata); + gnutls_certificate_set_dh_params(cred, dh.get()); + } + + bool HasDH() const + { + return (dh.get() != NULL); + } + }; +} + +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), 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; + } + } + + 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); + + // DH params is not mandatory + if (Anope::IsFile(dhfile.c_str())) + { + cred.SetDH(dhfile); + Log(LOG_DEBUG) << "m_ssl_gnutls: Successfully loaded DH parameters from " << dhfile; + } + + cred.SetCertAndKey(certfile, keyfile); + 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_int(io->sess, 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_int(io->sess, 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); + } + + delete this; +} + +MODULE_INIT(GnuTLSModule) diff --git a/modules/extra/m_ssl.cpp b/modules/extra/m_ssl_openssl.cpp index 44971908c..a274dc78d 100644 --- a/modules/extra/m_ssl.cpp +++ b/modules/extra/m_ssl_openssl.cpp @@ -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 { diff --git a/modules/m_httpd.cpp b/modules/m_httpd.cpp index e08452d81..f3d0677a9 100644 --- a/modules/m_httpd.cpp +++ b/modules/m_httpd.cpp @@ -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; diff --git a/modules/webcpanel/template_fileserver.cpp b/modules/webcpanel/template_fileserver.cpp index d4e5ec7e4..dc950b330 100644 --- a/modules/webcpanel/template_fileserver.cpp +++ b/modules/webcpanel/template_fileserver.cpp @@ -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); } diff --git a/src/socket_transport.cpp b/src/socket_transport.cpp index 6293ea385..1476d0662 100644 --- a/src/socket_transport.cpp +++ b/src/socket_transport.cpp @@ -167,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); } diff --git a/src/sockets.cpp b/src/sockets.cpp index 948f3e238..f50092744 100644 --- a/src/sockets.cpp +++ b/src/sockets.cpp @@ -517,7 +517,7 @@ ListenSocket::ListenSocket(const Anope::string &bindip, int port, bool i) { this->SetBlocking(false); - const char op = 1; + int op = 1; setsockopt(this->GetFD(), SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)); this->bindaddr.pton(i ? AF_INET6 : AF_INET, bindip, port); |