+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
#include <string>
#include <vector>
#include "hashcomp.h"
#include "inspircd.h"
-#include "ssl_cert.h"
+#include "transport.h"
/* $ModDesc: Provides SSL support for clients */
/* $CompileFlags: `libgnutls-config --cflags` */
-/* $LinkerFlags: `libgnutls-config --libs` `perl ../gnutls_rpath.pl` */
-
+/* $LinkerFlags: `perl extra/gnutls_rpath.pl` */
+/* $ModDep: transport.h */
enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED };
return false;
}
+/** Represents an SSL user's extra data
+ */
class issl_session : public classbase
{
public:
culllist = new CullList(ServerInstance);
+
+ ServerInstance->PublishInterface("InspSocketHook", this);
// Not rehashable...because I cba to reduce all the sizes of existing buffers.
inbufsize = ServerInstance->Config->NetBufferSize;
if(((Conf->ReadValue("bind", "type", i) == "") || (Conf->ReadValue("bind", "type", i) == "clients")) && (Conf->ReadValue("bind", "ssl", i) == "gnutls"))
{
// Get the port we're meant to be listening on with SSL
- unsigned int port = Conf->ReadInteger("bind", "port", i, true);
- if (ServerInstance->Config->AddIOHook(port, this))
- {
- // We keep a record of which ports we're listening on with SSL
- listenports.push_back(port);
-
- ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", port);
- }
- else
+ std::string port = Conf->ReadValue("bind", "port", i);
+ irc::portparser portrange(port, false);
+ long portno = -1;
+ while ((portno = portrange.GetToken()))
{
- ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", port);
+ if (ServerInstance->Config->AddIOHook(portno, this))
+ {
+ listenports.push_back(portno);
+ ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: Enabling SSL for port %d", portno);
+ }
+ else
+ {
+ ServerInstance->Log(DEFAULT, "m_ssl_gnutls.so: FAILED to enable SSL on port %d, maybe you have another ssl or similar module loaded?", portno);
+ }
}
}
}
virtual Version GetVersion()
{
- return Version(1, 0, 0, 0, VF_VENDOR);
+ return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
}
void Implements(char* List)
{
- List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
- List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
+ List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = List[I_OnCleanup] = 1;
+ List[I_OnRequest] = List[I_OnSyncUserMetaData] = List[I_OnDecodeMetaData] = List[I_OnUnloadModule] = List[I_OnRehash] = List[I_OnWhois] = List[I_OnPostConnect] = 1;
}
+ virtual char* OnRequest(Request* request)
+ {
+ ISHRequest* ISR = (ISHRequest*)request;
+ if (strcmp("IS_NAME", request->GetId()) == 0)
+ {
+ return "gnutls";
+ }
+ else if (strcmp("IS_HOOK", request->GetId()) == 0)
+ {
+ char* ret = "OK";
+ try
+ {
+ ret = ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+ }
+ catch (ModuleException &e)
+ {
+ return NULL;
+ }
+ return ret;
+ }
+ else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
+ {
+ return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
+ }
+ else if (strcmp("IS_HSDONE", request->GetId()) == 0)
+ {
+ issl_session* session = &sessions[ISR->Sock->GetFd()];
+ return (session->status == ISSL_HANDSHAKING_READ || session->status == ISSL_HANDSHAKING_WRITE) ? NULL : (char*)"OK";
+ }
+ else if (strcmp("IS_ATTACH", request->GetId()) == 0)
+ {
+ issl_session* session = &sessions[ISR->Sock->GetFd()];
+ if (session)
+ {
+ VerifyCertificate(session, (InspSocket*)ISR->Sock);
+ return "OK";
+ }
+ }
+ return NULL;
+ }
+
+
virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
{
issl_session* session = &sessions[fd];
Handshake(session);
}
+ virtual void OnRawSocketConnect(int fd)
+ {
+ issl_session* session = &sessions[fd];
+
+ session->fd = fd;
+ session->inbuf = new char[inbufsize];
+ session->inbufoffset = 0;
+
+ gnutls_init(&session->sess, GNUTLS_SERVER);
+
+ gnutls_set_default_priority(session->sess); // Avoid calling all the priority functions, defaults are adequate.
+ gnutls_credentials_set(session->sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
+ gnutls_dh_set_prime_bits(session->sess, dh_bits);
+
+ gnutls_transport_set_ptr(session->sess, (gnutls_transport_ptr_t) fd); // Give gnutls the fd for the socket.
+
+ Handshake(session);
+ }
+
virtual void OnRawSocketClose(int fd)
{
ServerInstance->Log(DEBUG, "OnRawSocketClose: %d", fd);
CloseSession(session);
return 1;
}
-
- ServerInstance->Log(DEBUG, "m_ssl_gnutls.so: OnRawSocketRead(%d, buffer, %u, %d)", fd, count, readresult);
-
+
if (session->status == ISSL_HANDSHAKING_READ)
{
// The handshake isn't finished, try to finish it.
}
virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
- {
+ {
+ if (!count)
+ return 0;
+
issl_session* session = &sessions[fd];
const char* sendbuffer = buffer;
// Bugfix, only send this numeric for *our* SSL users
if(dest->GetExt("ssl", dummy) || (IS_LOCAL(dest) && isin(dest->GetPort(), listenports)))
{
- source->WriteServ("320 %s %s :is using a secure connection", source->nick, dest->nick);
+ ServerInstance->SendWhoisLine(source, dest, 320, "%s %s :is using a secure connection", source->nick, dest->nick);
}
}
session->status = ISSL_NONE;
}
- void VerifyCertificate(issl_session* session, userrec* user)
+ void VerifyCertificate(issl_session* session, Extensible* user)
{
unsigned int status;
const gnutls_datum_t* cert_list;
int ret;
- unsigned int cert_list_size, name_size;
+ unsigned int cert_list_size;
gnutls_x509_crt_t cert;
char name[MAXBUF];
+ unsigned char digest[MAXBUF];
+ size_t digest_size = sizeof(digest);
+ size_t name_size = sizeof(name);
ssl_cert* certinfo = new ssl_cert;
user->Extend("ssl_cert",certinfo);
return;
}
- name_size = sizeof(name);
gnutls_x509_crt_get_dn(cert, name, &name_size);
certinfo->data.insert(std::make_pair("dn",name));
- name_size = sizeof(name);
gnutls_x509_crt_get_issuer_dn(cert, name, &name_size);
certinfo->data.insert(std::make_pair("issuer",name));
+ if ((ret = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &digest_size)) < 0)
+ {
+ certinfo->data.insert(std::make_pair("error",gnutls_strerror(ret)));
+ }
+ else
+ {
+ certinfo->data.insert(std::make_pair("fingerprint",irc::hex(digest, digest_size)));
+ }
+
/* Beware here we do not check for errors.
*/
if ((gnutls_x509_crt_get_expiration_time(cert) < time(0)) || (gnutls_x509_crt_get_activation_time(cert) > time(0)))