Permalink
Browse files

- Added support for STARTTLS. This allows users to switch to SSL without

  having to use a special SSL-only port, they can simply switch to SSL on
  any port. This is currently only supported by few clients (such as KVIrc 4).
  This functionality can be disabled by setting set::ssl::options::no-starttls,
  for example if you don't want to offer SSL to your users and only want it
  to be used for server to server links.
  Naturally, the IRCd must be compiled with SSL support for STARTTLS to work.
- Fixed SSL_ERROR_WANT_READ in IRCd_ssl_write()
  • Loading branch information...
syzop committed Dec 6, 2009
1 parent a5bd782 commit 5a0a71de03f447803ec94c8e208984e1af0260c8
Showing with 176 additions and 10 deletions.
  1. +8 −0 Changes
  2. +2 −0 doc/unreal32docs.html
  3. +6 −1 include/struct.h
  4. +6 −1 makefile.win32
  5. +9 −2 src/modules/Makefile.in
  6. +128 −0 src/modules/m_starttls.c
  7. +11 −4 src/s_bsd.c
  8. +1 −0 src/s_conf.c
  9. +2 −2 src/s_err.c
  10. +3 −0 src/ssl.c
@@ -1850,3 +1850,11 @@
stuff instead of hacking configure directly :P .
- Made the timesynch log output more clear and understandable.
- Added an 'UnrealIRCd started' log message on startup.
- Added support for STARTTLS. This allows users to switch to SSL without
having to use a special SSL-only port, they can simply switch to SSL on
any port. This is currently only supported by few clients (such as KVIrc 4).
This functionality can be disabled by setting set::ssl::options::no-starttls,
for example if you don't want to offer SSL to your users and only want it
to be used for server to server links.
Naturally, the IRCd must be compiled with SSL support for STARTTLS to work.
- Fixed SSL_ERROR_WANT_READ in IRCd_ssl_write()
@@ -2468,6 +2468,8 @@
Disallows connections from people with self-signed certificates.</p>
<p><font class="set">set::ssl::options::verify-certificate;</font><br>
Makes Unreal determine if the SSL certificate is valid before allowing connection.</p>
<p><font class="set">set::ssl::options::no-starttls;</font><br>
Disable STARTTLS. STARTTLS allows clients to use SSL on regular (non-SSL) ports.</p>
<p><font class="set">set::throttle::period &lt;timevalue&gt;</font><br>
How long a user must wait before reconnecting more than set::throttle::connections
times.</p>
@@ -232,6 +232,7 @@ typedef unsigned int u_int32_t; /* XXX Hope this works! */
#define STAT_LOG -7 /* logfile for -x */
#define STAT_CONNECTING -6
#define STAT_SSL_STARTTLS_HANDSHAKE -8
#define STAT_SSL_CONNECT_HANDSHAKE -5
#define STAT_SSL_ACCEPT_HANDSHAKE -4
#define STAT_HANDSHAKE -3
@@ -254,9 +255,11 @@ typedef unsigned int u_int32_t; /* XXX Hope this works! */
#define IsLog(x) ((x)->status == STAT_LOG)
#ifdef USE_SSL
#define IsSSLStartTLSHandshake(x) ((x)->status == STAT_SSL_STARTTLS_HANDSHAKE)
#define IsSSLAcceptHandshake(x) ((x)->status == STAT_SSL_ACCEPT_HANDSHAKE)
#define IsSSLConnectHandshake(x) ((x)->status == STAT_SSL_CONNECT_HANDSHAKE)
#define IsSSLHandshake(x) (IsSSLAcceptHandshake(x) || IsSSLConnectHandshake(x))
#define IsSSLHandshake(x) (IsSSLAcceptHandshake(x) || IsSSLConnectHandshake(x) | IsSSLStartTLSHandshake(x))
#define SetSSLStartTLSHandshake(x) ((x)->status = STAT_SSL_STARTTLS_HANDSHAKE)
#define SetSSLAcceptHandshake(x) ((x)->status = STAT_SSL_ACCEPT_HANDSHAKE)
#define SetSSLConnectHandshake(x) ((x)->status = STAT_SSL_CONNECT_HANDSHAKE)
#endif
@@ -935,6 +938,8 @@ typedef struct {
#define SSLFLAG_FAILIFNOCERT 0x1
#define SSLFLAG_VERIFYCERT 0x2
#define SSLFLAG_DONOTACCEPTSELFSIGNED 0x4
#define SSLFLAG_NOSTARTTLS 0x8
struct Client {
struct Client *next, *prev, *hnext;
anUser *user; /* ...defined, if this is a User */
@@ -188,7 +188,8 @@ MOD_FILES=SRC/MODULES/L_COMMANDS.C SRC/MODULES/M_CHGHOST.C SRC/MODULES/M_SDESC.C
SRC/MODULES/M_NICK.C SRC/MODULES/M_USER.C SRC/MODULES/M_MODE.C \
SRC/MODULES/M_WATCH.C SRC/MODULES/M_PART.C SRC/MODULES/M_JOIN.C \
SRC/MODULES/M_MOTD.C SRC/MODULES/M_OPERMOTD.C SRC/MODULES/M_BOTMOTD.C \
SRC/MODULES/M_LUSERS.C SRC/MODULES/M_NAMES.C SRC/MODULES/M_SVSNOLAG.C
SRC/MODULES/M_LUSERS.C SRC/MODULES/M_NAMES.C SRC/MODULES/M_SVSNOLAG.C \
SRC/MODULES/M_STARTTLS.C
DLL_FILES=SRC/MODULES/M_CHGHOST.DLL SRC/MODULES/M_SDESC.DLL SRC/MODULES/M_SETIDENT.DLL \
SRC/MODULES/M_SETNAME.DLL SRC/MODULES/M_SETHOST.DLL SRC/MODULES/M_CHGIDENT.DLL \
@@ -224,6 +225,7 @@ DLL_FILES=SRC/MODULES/M_CHGHOST.DLL SRC/MODULES/M_SDESC.DLL SRC/MODULES/M_SETIDE
SRC/MODULES/M_WATCH.DLL SRC/MODULES/M_PART.DLL SRC/MODULES/M_JOIN.DLL \
SRC/MODULES/M_MOTD.DLL SRC/MODULES/M_OPERMOTD.DLL SRC/MODULES/M_BOTMOTD.DLL \
SRC/MODULES/M_LUSERS.DLL SRC/MODULES/M_NAMES.DLL SRC/MODULES/M_SVSNOLAG.DLL \
SRC/MODULES/M_STARTTLS.DLL \
SRC/MODULES/CLOAK.DLL
@@ -783,6 +785,9 @@ src/modules/cloak.dll: src/modules/cloak.c $(INCLUDES)
src/modules/m_svsnolag.dll: src/modules/m_svsnolag.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/m_svsnolag.c $(MODLFLAGS)
src/modules/m_starttls.dll: src/modules/m_starttls.c $(INCLUDES)
$(CC) $(MODCFLAGS) src/modules/m_starttls.c $(MODLFLAGS)
dummy:
@@ -54,7 +54,7 @@ R_MODULES= \
m_connect.so m_dccallow.so m_userip.so m_nick.so m_user.so \
m_mode.so m_watch.so m_part.so m_join.so m_motd.so m_opermotd.so \
m_botmotd.so m_lusers.so m_names.so m_svsnolag.so m_addmotd.so \
m_svslusers.so
m_svslusers.so m_starttls.so
#note change of .c to .o
COMMANDS=m_sethost.o m_chghost.o m_chgident.o m_setname.o m_setident.o \
@@ -76,7 +76,7 @@ COMMANDS=m_sethost.o m_chghost.o m_chgident.o m_setname.o m_setident.o \
m_svsfline.o m_dccdeny.o m_undccdeny.o m_whowas.o \
m_connect.o m_dccallow.o m_userip.o m_nick.o m_user.o \
m_mode.o m_watch.o m_part.o m_join.o m_motd.o m_opermotd.o \
m_botmotd.o m_lusers.o m_names.o m_svsnolag.o
m_botmotd.o m_lusers.o m_names.o m_svsnolag.o m_starttls.o
MODULES=commands.so cloak.so $(R_MODULES)
@@ -407,6 +407,9 @@ m_names.o: m_names.c $(INCLUDES)
m_svsnolag.o: m_svsnolag.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -c m_svsnolag.c
m_starttls.o: m_starttls.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -c m_starttls.c
#############################################################################
# .so's section
#############################################################################
@@ -819,6 +822,10 @@ m_svsnolag.so: m_svsnolag.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o m_svsnolag.so m_svsnolag.c
m_starttls.so: m_starttls.c $(INCLUDES)
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
-o m_starttls.so m_starttls.c
#############################################################################
# and now the remaining modules...
#############################################################################
@@ -0,0 +1,128 @@
/*
* IRC - Internet Relay Chat, src/modules/m_starttls.c
* (C) 2009 Syzop & The UnrealIRCd Team
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "proto.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif
DLLFUNC CMD_FUNC(m_starttls);
#define MSG_STARTTLS "STARTTLS"
ModuleHeader MOD_HEADER(m_starttls)
= {
"m_starttls",
"$Id$",
"command /starttls",
"3.2-b8-1",
NULL
};
DLLFUNC int MOD_INIT(m_starttls)(ModuleInfo *modinfo)
{
CommandAdd(modinfo->handle, MSG_STARTTLS, NULL, m_starttls, MAXPARA, M_UNREGISTERED);
MARK_AS_OFFICIAL_MODULE(modinfo);
return MOD_SUCCESS;
}
DLLFUNC int MOD_LOAD(m_starttls)(int module_load)
{
return MOD_SUCCESS;
}
DLLFUNC int MOD_UNLOAD(m_starttls)(int module_unload)
{
return MOD_SUCCESS;
}
DLLFUNC CMD_FUNC(m_starttls)
{
if (!MyConnect(sptr) || !IsUnknown(sptr))
return 0;
#ifndef USE_SSL
/* sendnotice(sptr, "This server does not support SSL"); */
/* or numeric 691? */
/* actually... it's probably best to just act like we don't know this command...? */
sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "STARTTLS");
return 0;
#else
if (iConf.ssl_options & SSLFLAG_NOSTARTTLS)
{
sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "STARTTLS");
return 0;
}
if (IsSecure(sptr))
{
sendto_one(sptr, ":%s 691 %s :STARTTLS failed. Already using TLS.", me.name, sptr->name);
return 0;
}
dbuf_delete(&sptr->recvQ, 1000000); /* Clear up any remaining plaintext commands */
sendto_one(sptr, ":%s 670 %s :STARTTLS successful, go ahead with TLS handshake", me.name, sptr->name);
// ^^ FIXME, use: RPL_STARTTLS
send_queued(sptr);
SetSSLStartTLSHandshake(sptr);
Debug((DEBUG_DEBUG, "Starting SSL handshake (due to STARTTLS) for %s", sptr->sockhost));
if ((sptr->ssl = SSL_new(ctx_server)) == NULL)
goto fail;
sptr->flags |= FLAGS_SSL;
SSL_set_fd(sptr->ssl, sptr->fd);
SSL_set_nonblocking(sptr->ssl);
if (!ircd_SSL_accept(sptr, sptr->fd)) {
Debug((DEBUG_DEBUG, "Failed SSL accept handshake in instance 1: %s", sptr->sockhost));
SSL_set_shutdown(sptr->ssl, SSL_RECEIVED_SHUTDOWN);
SSL_smart_shutdown(sptr->ssl);
SSL_free(sptr->ssl);
goto fail;
}
/* HANDSHAKE IN PROGRESS */
return 0;
fail:
/* Failure */
sendto_one(sptr, ":%s 691 %s :STARTTLS failed", me.name, sptr->name); // FIXME, use: ERR_STARTTLS
sptr->ssl = NULL;
sptr->flags &= ~FLAGS_SSL;
SetUnknown(sptr);
return 0;
#endif
}
@@ -1972,21 +1972,24 @@ int read_message(time_t delay, fdlist *listp)
!(DoingDNS(cptr) || DoingAuth(cptr))
#ifdef USE_SSL
&&
!(IsSSLAcceptHandshake(cptr) || IsSSLConnectHandshake(cptr))
!(IsSSLHandshake(cptr))
#endif
)
length = read_packet(cptr, &read_set);
#ifdef USE_SSL
if ((length != FLUSH_BUFFER) && (cptr->ssl != NULL) &&
(IsSSLAcceptHandshake(cptr) || IsSSLConnectHandshake(cptr)) &&
IsSSLHandshake(cptr) &&
FD_ISSET(cptr->fd, &read_set))
{
if (!SSL_is_init_finished(cptr->ssl))
{
if (IsDead(cptr) || IsSSLAcceptHandshake(cptr) ? !ircd_SSL_accept(cptr, cptr->fd) : ircd_SSL_connect(cptr) < 0)
if (IsDead(cptr) ||
(IsSSLAcceptHandshake(cptr) || IsSSLStartTLSHandshake(cptr)) ? !ircd_SSL_accept(cptr, cptr->fd) : ircd_SSL_connect(cptr) < 0)
{
length = -1;
}
/* if (IsSSLStartTLSHandshake(cptr))
length = read_packet(cptr, &read_set); */
}
if (SSL_is_init_finished(cptr->ssl))
{
@@ -1995,10 +1998,14 @@ int read_message(time_t delay, fdlist *listp)
Debug((DEBUG_ERROR, "ssl: start_of_normal_client_handshake(%s)", cptr->sockhost));
start_of_normal_client_handshake(cptr);
}
else
else if (IsSSLConnectHandshake(cptr))
{
Debug((DEBUG_ERROR, "ssl: completed_connection", cptr->name));
completed_connection(cptr);
} else if (IsSSLStartTLSHandshake(cptr))
{
SetUnknown(cptr);
/* STARTTLS is now complete. We could send something, but I don't know why... */
}
}
@@ -295,6 +295,7 @@ static OperFlag _SSLFlags[] = {
{ SSLFLAG_FAILIFNOCERT, "fail-if-no-clientcert" },
{ SSLFLAG_DONOTACCEPTSELFSIGNED, "no-self-signed" },
{ SSLFLAG_VERIFYCERT, "verify-certificate" },
{ SSLFLAG_NOSTARTTLS, "no-starttls" }
};
#endif
@@ -726,7 +726,7 @@ static char *replies[] = {
/* 667 */ NULL,
/* 668 */ NULL,
/* 669 */ NULL,
/* 670 */ NULL, /* kineircd */
/* 670 RPL_STARTTLS */ ":%s 670 %s :STARTTLS successful, go ahead with TLS handshake", /* kineircd */
/* 671 RPL_WHOISSECURE */ ":%s 671 %s %s :%s", /* our variation on the kineircd numeric */
/* 672 */ NULL, /* ithildin */
/* 673 */ NULL, /* ithildin */
@@ -747,7 +747,7 @@ static char *replies[] = {
/* 688 */ NULL, /* kineircd */
/* 689 */ NULL, /* kineircd */
/* 690 */ NULL, /* kineircd */
/* 691 */ NULL,
/* 691 ERR_STARTTLS */ ":%s 691 %s :%s",
/* 692 */ NULL,
/* 693 */ NULL,
/* 694 */ NULL,
@@ -490,6 +490,9 @@ int ircd_SSL_write(aClient *acptr, const void *buf, int sz)
case SSL_ERROR_WANT_WRITE:
SET_ERRNO(P_EWOULDBLOCK);
return -1;
case SSL_ERROR_WANT_READ:
SET_ERRNO(P_EWOULDBLOCK); /* is this correct? next write will block if not read, so sounds right... */
return -1;
case SSL_ERROR_SSL:
if(ERRNO == EAGAIN)
return -1;

0 comments on commit 5a0a71d

Please sign in to comment.