From 9c0134ee2c76fe7ff1509501b3904f9db9b29454 Mon Sep 17 00:00:00 2001 From: Attila Molnar Date: Mon, 17 Feb 2014 00:41:36 +0100 Subject: Rename m_ssl to m_ssl_openssl and update docs --- data/example.conf | 2 +- data/modules.example.conf | 45 ++--- data/stats.standalone.example.conf | 2 +- docs/Changes.conf | 1 + docs/WIN32.txt | 7 +- include/service.h | 2 +- modules/extra/m_ssl.cpp | 395 ------------------------------------- modules/extra/m_ssl_openssl.cpp | 395 +++++++++++++++++++++++++++++++++++++ modules/m_httpd.cpp | 3 - 9 files changed, 426 insertions(+), 426 deletions(-) delete mode 100644 modules/extra/m_ssl.cpp create mode 100644 modules/extra/m_ssl_openssl.cpp 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..e4eeda802 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 @@ -468,6 +468,28 @@ module { name = "help" } */ #module { name = "m_sasl_dh-blowfish" } +/* + * m_ssl_openssl [EXTRA] + * + * This module provides SSL services to Anope using OpenSSL, for example to + * connect to the uplink server(s) via SSL. + */ +#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] * @@ -662,27 +684,6 @@ module { name = "help" } 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" -} - /* * m_xmlrpc * 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/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/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/modules/extra/m_ssl.cpp b/modules/extra/m_ssl.cpp deleted file mode 100644 index 44971908c..000000000 --- a/modules/extra/m_ssl.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* RequiredLibraries: ssl,crypto */ - -#include "module.h" -#include "modules/ssl.h" - -#define OPENSSL_NO_SHA512 -#include -#include -#include -#include -#include - -static SSL_CTX *server_ctx, *client_ctx; - -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: - /* The SSL socket for this socket */ - SSL *sslsock; - - /** 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; -}; - -class SSLModule; -static SSLModule *me; -class SSLModule : public Module -{ - Anope::string certfile, keyfile; - - public: - MySSLService service; - - SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), service(this, "ssl") - { - me = this; - - this->SetPermanent(true); - - SSL_library_init(); - SSL_load_error_strings(); - - client_ctx = SSL_CTX_new(SSLv23_client_method()); - server_ctx = SSL_CTX_new(SSLv23_server_method()); - - if (!client_ctx || !server_ctx) - throw ModuleException("Error initializing SSL CTX"); - - SSL_CTX_set_mode(client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_mode(server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - Anope::string context_name = "Anope"; - SSL_CTX_set_session_id_context(client_ctx, reinterpret_cast(context_name.c_str()), context_name.length()); - SSL_CTX_set_session_id_context(server_ctx, reinterpret_cast(context_name.c_str()), context_name.length()); - } - - ~SSLModule() - { - for (std::map::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;) - { - Socket *s = it->second; - ++it; - - if (dynamic_cast(s->io)) - delete s; - } - - SSL_CTX_free(client_ctx); - SSL_CTX_free(server_ctx); - } - - void OnReload(Configuration::Conf *conf) anope_override - { - Configuration::Block *config = conf->GetModule(this); - - this->certfile = config->Get("cert", "data/anope.crt"); - this->keyfile = config->Get("key", "data/anope.key"); - - if (Anope::IsFile(this->certfile.c_str())) - { - 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; - } - else - Log() << "Unable to open certificate " << this->certfile; - - if (Anope::IsFile(this->keyfile.c_str())) - { - 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; - } - else - { - if (Anope::IsFile(this->certfile.c_str())) - throw ConfigException("Error loading private key " + this->keyfile + " - file not found"); - else - Log() << "Unable to open private key " << this->keyfile; - } - - } - - void OnPreServerConnect() anope_override - { - Configuration::Block *config = Config->GetBlock("uplink", Anope::CurrentUplink); - - if (config->Get("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(); -} - -SSLSocketIO::SSLSocketIO() -{ - this->sslsock = NULL; -} - -int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz) -{ - int i = SSL_read(this->sslsock, buf, sz); - 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); - 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; -} - -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(newsocket->io); - - io->sslsock = SSL_new(server_ctx); - if (!io->sslsock) - throw SocketException("Unable to initialize SSL socket"); - - SSL_set_accept_state(io->sslsock); - - if (!SSL_set_fd(io->sslsock, newsocket->GetFD())) - throw SocketException("Unable to set SSL fd"); - - 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(cs->io); - - int ret = SSL_accept(io->sslsock); - if (ret <= 0) - { - int error = SSL_get_error(io->sslsock, ret); - if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)) - { - SocketEngine::Change(cs, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE); - SocketEngine::Change(cs, error == SSL_ERROR_WANT_READ, SF_READABLE); - return SF_ACCEPTING; - } - else - { - cs->OnError(ERR_error_string(ERR_get_error(), NULL)); - 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(s->io); - - if (io->sslsock == NULL) - { - io->sslsock = SSL_new(client_ctx); - if (!io->sslsock) - throw SocketException("Unable to initialize SSL socket"); - - if (!SSL_set_fd(io->sslsock, s->GetFD())) - throw SocketException("Unable to set SSL fd"); - } - - int ret = SSL_connect(io->sslsock); - if (ret <= 0) - { - int error = SSL_get_error(io->sslsock, ret); - if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)) - { - SocketEngine::Change(s, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE); - SocketEngine::Change(s, error == SSL_ERROR_WANT_READ, SF_READABLE); - return SF_CONNECTING; - } - else - { - s->OnError(ERR_error_string(ERR_get_error(), NULL)); - 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->sslsock) - { - SSL_shutdown(this->sslsock); - SSL_free(this->sslsock); - } - - delete this; -} - -MODULE_INIT(SSLModule) diff --git a/modules/extra/m_ssl_openssl.cpp b/modules/extra/m_ssl_openssl.cpp new file mode 100644 index 000000000..a274dc78d --- /dev/null +++ b/modules/extra/m_ssl_openssl.cpp @@ -0,0 +1,395 @@ +/* RequiredLibraries: ssl,crypto */ + +#include "module.h" +#include "modules/ssl.h" + +#define OPENSSL_NO_SHA512 +#include +#include +#include +#include +#include + +static SSL_CTX *server_ctx, *client_ctx; + +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: + /* The SSL socket for this socket */ + SSL *sslsock; + + /** 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; +}; + +class SSLModule; +static SSLModule *me; +class SSLModule : public Module +{ + Anope::string certfile, keyfile; + + public: + MySSLService service; + + SSLModule(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), service(this, "ssl") + { + me = this; + + this->SetPermanent(true); + + SSL_library_init(); + SSL_load_error_strings(); + + client_ctx = SSL_CTX_new(SSLv23_client_method()); + server_ctx = SSL_CTX_new(SSLv23_server_method()); + + if (!client_ctx || !server_ctx) + throw ModuleException("Error initializing SSL CTX"); + + SSL_CTX_set_mode(client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_mode(server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + Anope::string context_name = "Anope"; + SSL_CTX_set_session_id_context(client_ctx, reinterpret_cast(context_name.c_str()), context_name.length()); + SSL_CTX_set_session_id_context(server_ctx, reinterpret_cast(context_name.c_str()), context_name.length()); + } + + ~SSLModule() + { + for (std::map::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;) + { + Socket *s = it->second; + ++it; + + if (dynamic_cast(s->io)) + delete s; + } + + SSL_CTX_free(client_ctx); + SSL_CTX_free(server_ctx); + } + + void OnReload(Configuration::Conf *conf) anope_override + { + Configuration::Block *config = conf->GetModule(this); + + this->certfile = config->Get("cert", "data/anope.crt"); + this->keyfile = config->Get("key", "data/anope.key"); + + if (Anope::IsFile(this->certfile.c_str())) + { + 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_openssl: Successfully loaded certificate " << this->certfile; + } + else + Log() << "Unable to open certificate " << this->certfile; + + if (Anope::IsFile(this->keyfile.c_str())) + { + 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_openssl: Successfully loaded private key " << this->keyfile; + } + else + { + if (Anope::IsFile(this->certfile.c_str())) + throw ConfigException("Error loading private key " + this->keyfile + " - file not found"); + else + Log() << "Unable to open private key " << this->keyfile; + } + + } + + void OnPreServerConnect() anope_override + { + Configuration::Block *config = Config->GetBlock("uplink", Anope::CurrentUplink); + + if (config->Get("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(); +} + +SSLSocketIO::SSLSocketIO() +{ + this->sslsock = NULL; +} + +int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz) +{ + int i = SSL_read(this->sslsock, buf, sz); + 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); + 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; +} + +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(newsocket->io); + + io->sslsock = SSL_new(server_ctx); + if (!io->sslsock) + throw SocketException("Unable to initialize SSL socket"); + + SSL_set_accept_state(io->sslsock); + + if (!SSL_set_fd(io->sslsock, newsocket->GetFD())) + throw SocketException("Unable to set SSL fd"); + + 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(cs->io); + + int ret = SSL_accept(io->sslsock); + if (ret <= 0) + { + int error = SSL_get_error(io->sslsock, ret); + if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)) + { + SocketEngine::Change(cs, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE); + SocketEngine::Change(cs, error == SSL_ERROR_WANT_READ, SF_READABLE); + return SF_ACCEPTING; + } + else + { + cs->OnError(ERR_error_string(ERR_get_error(), NULL)); + 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(s->io); + + if (io->sslsock == NULL) + { + io->sslsock = SSL_new(client_ctx); + if (!io->sslsock) + throw SocketException("Unable to initialize SSL socket"); + + if (!SSL_set_fd(io->sslsock, s->GetFD())) + throw SocketException("Unable to set SSL fd"); + } + + int ret = SSL_connect(io->sslsock); + if (ret <= 0) + { + int error = SSL_get_error(io->sslsock, ret); + if (ret == -1 && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)) + { + SocketEngine::Change(s, error == SSL_ERROR_WANT_WRITE, SF_WRITABLE); + SocketEngine::Change(s, error == SSL_ERROR_WANT_READ, SF_READABLE); + return SF_CONNECTING; + } + else + { + s->OnError(ERR_error_string(ERR_get_error(), NULL)); + 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->sslsock) + { + SSL_shutdown(this->sslsock); + SSL_free(this->sslsock); + } + + delete this; +} + +MODULE_INIT(SSLModule) 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::iterator it = this->providers.begin(), it_end = this->providers.end(); it != it_end; ++it) { MyHTTPProvider *p = it->second; -- cgit From 1c39d25ccaabeab2a8b1f317bf5394f007db14f8 Mon Sep 17 00:00:00 2001 From: Attila Molnar Date: Mon, 17 Feb 2014 01:12:01 +0100 Subject: Add m_ssl_gnutls --- data/modules.example.conf | 41 ++++ modules/extra/m_ssl_gnutls.cpp | 509 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 550 insertions(+) create mode 100644 modules/extra/m_ssl_gnutls.cpp diff --git a/data/modules.example.conf b/data/modules.example.conf index e4eeda802..8fe9ca4db 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -468,11 +468,52 @@ 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 { 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 +#include + +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(const_cast(dat.data())); + datum.size = static_cast(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(ifs)), std::istreambuf_iterator()); + + 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::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;) + { + Socket *s = it->second; + ++it; + + if (dynamic_cast(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("cert", "data/anope.crt"); + const Anope::string keyfile = config->Get("key", "data/anope.key"); + const Anope::string dhfile = config->Get("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("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(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(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(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) -- cgit From 707494481046d330ee5b2eb641b67cb4fc96f6ca Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 Feb 2014 13:39:49 -0500 Subject: Fix not applying ipv[46]_cidr to connecting clients in os_session, #1573 --- modules/commands/os_session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; -- cgit From baff417652ac7058babbbc478a9bcbcb47867378 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 Feb 2014 13:53:04 -0500 Subject: Move encryption.h to include/modules --- include/modules/encryption.h | 37 +++++++++++++++++++++++++++++++++++++ modules/encryption/enc_md5.cpp | 2 +- modules/encryption/enc_old.cpp | 2 +- modules/encryption/enc_sha1.cpp | 2 +- modules/encryption/enc_sha256.cpp | 2 +- modules/encryption/encryption.h | 37 ------------------------------------- modules/extra/enc_bcrypt.cpp | 2 +- 7 files changed, 42 insertions(+), 42 deletions(-) create mode 100644 include/modules/encryption.h delete mode 100644 modules/encryption/encryption.h diff --git a/include/modules/encryption.h b/include/modules/encryption.h new file mode 100644 index 000000000..95c5703aa --- /dev/null +++ b/include/modules/encryption.h @@ -0,0 +1,37 @@ +/* + * + * (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. + * + */ + +namespace Encryption +{ + typedef std::pair Hash; + typedef std::pair IV; + + class Context + { + public: + virtual ~Context() { } + virtual void Update(const unsigned char *data, size_t len) = 0; + virtual void Finalize() = 0; + virtual Hash GetFinalizedHash() = 0; + }; + + class Provider : public Service + { + public: + Provider(Module *creator, const Anope::string &sname) : Service(creator, "Encryption::Provider", sname) { } + virtual ~Provider() { } + + virtual Context *CreateContext(IV * = NULL) = 0; + virtual IV GetDefaultIV() = 0; + }; +} + 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 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/encryption/encryption.h b/modules/encryption/encryption.h deleted file mode 100644 index 95c5703aa..000000000 --- a/modules/encryption/encryption.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * (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. - * - */ - -namespace Encryption -{ - typedef std::pair Hash; - typedef std::pair IV; - - class Context - { - public: - virtual ~Context() { } - virtual void Update(const unsigned char *data, size_t len) = 0; - virtual void Finalize() = 0; - virtual Hash GetFinalizedHash() = 0; - }; - - class Provider : public Service - { - public: - Provider(Module *creator, const Anope::string &sname) : Service(creator, "Encryption::Provider", sname) { } - virtual ~Provider() { } - - virtual Context *CreateContext(IV * = NULL) = 0; - virtual IV GetDefaultIV() = 0; - }; -} - 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 class EBCRYPT : public Module -- cgit From 7b4eec97480bace2621b8caa4b17f0ea50aa1f98 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 Feb 2014 13:53:45 -0500 Subject: Remove docs/IRCD, it is very outdated and no longer correct at all --- docs/IRCD | 202 -------------------------------------------------------------- 1 file changed, 202 deletions(-) delete mode 100644 docs/IRCD 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 ¶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. -- cgit From ef7dc94f8891e1dba8ac3dcad5966d1025b6226a Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 Feb 2014 19:39:25 -0500 Subject: 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 --- include/modules/os_forbid.h | 48 +++++-------------------------------- modules/commands/os_forbid.cpp | 54 ++++++++++++++++++++++++++++++++++++++++-- modules/database/db_old.cpp | 4 ++-- 3 files changed, 60 insertions(+), 46 deletions(-) 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 GetForbids() = 0; @@ -40,43 +42,5 @@ class ForbidService : public Service static ServiceReference 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(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(t); - - if (t > FT_SIZE - 1) - return NULL; - - if (!obj) - forbid_service->AddForbid(fb); - return fb; -} - #endif 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 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(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(t); + + if (t > FT_SIZE - 1) + return NULL; + + if (!obj) + forbid_service->AddForbid(fb); + return fb; +} + class MyForbidService : public ForbidService { Serialize::Checker[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/database/db_old.cpp b/modules/database/db_old.cpp index 8c322d02e..ddc488084 100644 --- a/modules/database/db_old.cpp +++ b/modules/database/db_old.cpp @@ -622,7 +622,7 @@ static void LoadNicks() if (!forbid) continue; - ForbidData *d = new ForbidData(); + ForbidData *d = forbid->CreateForbid(); d->mask = nc->display; d->creator = last_usermask; d->reason = last_realname; @@ -1031,7 +1031,7 @@ static void LoadChannels() if (!forbid) continue; - ForbidData *d = new ForbidData(); + ForbidData *d = forbid->CreateForbid(); d->mask = ci->name; d->creator = forbidby; d->reason = forbidreason; -- cgit From 80588fba818b746d43adf978d09933fda79b5e1f Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 17 Feb 2014 19:43:19 -0500 Subject: Fix os_ignore to work correctly with SQL --- include/modules/os_ignore.h | 54 +++----------- modules/commands/os_ignore.cpp | 160 ++++++++++++++++++++++++++--------------- 2 files changed, 112 insertions(+), 102 deletions(-) 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 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 &GetIgnores() { return this->ignores; } + virtual std::vector &GetIgnores() = 0; }; static ServiceReference 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)