Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- 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 5a0a71d
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 10 deletions.
8 changes: 8 additions & 0 deletions Changes
Expand Up @@ -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()
2 changes: 2 additions & 0 deletions doc/unreal32docs.html
Expand Up @@ -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>
Expand Down
7 changes: 6 additions & 1 deletion include/struct.h
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 */
Expand Down
7 changes: 6 additions & 1 deletion makefile.win32
Expand Up @@ -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 \
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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:


Expand Down
11 changes: 9 additions & 2 deletions src/modules/Makefile.in
Expand Up @@ -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 \
Expand All @@ -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)
Expand Down Expand Up @@ -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
#############################################################################
Expand Down Expand Up @@ -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...
#############################################################################
Expand Down
128 changes: 128 additions & 0 deletions src/modules/m_starttls.c
@@ -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
}
15 changes: 11 additions & 4 deletions src/s_bsd.c
Expand Up @@ -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))
{
Expand All @@ -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... */
}

}
Expand Down
1 change: 1 addition & 0 deletions src/s_conf.c
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions src/s_err.c
Expand Up @@ -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 */
Expand All @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions src/ssl.c
Expand Up @@ -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;
Expand Down

0 comments on commit 5a0a71d

Please sign in to comment.