Skip to content

Commit 5a0a71d

Browse files
committed
- 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()
1 parent a5bd782 commit 5a0a71d

File tree

10 files changed

+176
-10
lines changed

10 files changed

+176
-10
lines changed

Changes

+8
Original file line numberDiff line numberDiff line change
@@ -1850,3 +1850,11 @@
18501850
stuff instead of hacking configure directly :P .
18511851
- Made the timesynch log output more clear and understandable.
18521852
- Added an 'UnrealIRCd started' log message on startup.
1853+
- Added support for STARTTLS. This allows users to switch to SSL without
1854+
having to use a special SSL-only port, they can simply switch to SSL on
1855+
any port. This is currently only supported by few clients (such as KVIrc 4).
1856+
This functionality can be disabled by setting set::ssl::options::no-starttls,
1857+
for example if you don't want to offer SSL to your users and only want it
1858+
to be used for server to server links.
1859+
Naturally, the IRCd must be compiled with SSL support for STARTTLS to work.
1860+
- Fixed SSL_ERROR_WANT_READ in IRCd_ssl_write()

doc/unreal32docs.html

+2
Original file line numberDiff line numberDiff line change
@@ -2468,6 +2468,8 @@
24682468
Disallows connections from people with self-signed certificates.</p>
24692469
<p><font class="set">set::ssl::options::verify-certificate;</font><br>
24702470
Makes Unreal determine if the SSL certificate is valid before allowing connection.</p>
2471+
<p><font class="set">set::ssl::options::no-starttls;</font><br>
2472+
Disable STARTTLS. STARTTLS allows clients to use SSL on regular (non-SSL) ports.</p>
24712473
<p><font class="set">set::throttle::period &lt;timevalue&gt;</font><br>
24722474
How long a user must wait before reconnecting more than set::throttle::connections
24732475
times.</p>

include/struct.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ typedef unsigned int u_int32_t; /* XXX Hope this works! */
232232

233233
#define STAT_LOG -7 /* logfile for -x */
234234
#define STAT_CONNECTING -6
235+
#define STAT_SSL_STARTTLS_HANDSHAKE -8
235236
#define STAT_SSL_CONNECT_HANDSHAKE -5
236237
#define STAT_SSL_ACCEPT_HANDSHAKE -4
237238
#define STAT_HANDSHAKE -3
@@ -254,9 +255,11 @@ typedef unsigned int u_int32_t; /* XXX Hope this works! */
254255
#define IsLog(x) ((x)->status == STAT_LOG)
255256

256257
#ifdef USE_SSL
258+
#define IsSSLStartTLSHandshake(x) ((x)->status == STAT_SSL_STARTTLS_HANDSHAKE)
257259
#define IsSSLAcceptHandshake(x) ((x)->status == STAT_SSL_ACCEPT_HANDSHAKE)
258260
#define IsSSLConnectHandshake(x) ((x)->status == STAT_SSL_CONNECT_HANDSHAKE)
259-
#define IsSSLHandshake(x) (IsSSLAcceptHandshake(x) || IsSSLConnectHandshake(x))
261+
#define IsSSLHandshake(x) (IsSSLAcceptHandshake(x) || IsSSLConnectHandshake(x) | IsSSLStartTLSHandshake(x))
262+
#define SetSSLStartTLSHandshake(x) ((x)->status = STAT_SSL_STARTTLS_HANDSHAKE)
260263
#define SetSSLAcceptHandshake(x) ((x)->status = STAT_SSL_ACCEPT_HANDSHAKE)
261264
#define SetSSLConnectHandshake(x) ((x)->status = STAT_SSL_CONNECT_HANDSHAKE)
262265
#endif
@@ -935,6 +938,8 @@ typedef struct {
935938
#define SSLFLAG_FAILIFNOCERT 0x1
936939
#define SSLFLAG_VERIFYCERT 0x2
937940
#define SSLFLAG_DONOTACCEPTSELFSIGNED 0x4
941+
#define SSLFLAG_NOSTARTTLS 0x8
942+
938943
struct Client {
939944
struct Client *next, *prev, *hnext;
940945
anUser *user; /* ...defined, if this is a User */

makefile.win32

+6-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ MOD_FILES=SRC/MODULES/L_COMMANDS.C SRC/MODULES/M_CHGHOST.C SRC/MODULES/M_SDESC.C
188188
SRC/MODULES/M_NICK.C SRC/MODULES/M_USER.C SRC/MODULES/M_MODE.C \
189189
SRC/MODULES/M_WATCH.C SRC/MODULES/M_PART.C SRC/MODULES/M_JOIN.C \
190190
SRC/MODULES/M_MOTD.C SRC/MODULES/M_OPERMOTD.C SRC/MODULES/M_BOTMOTD.C \
191-
SRC/MODULES/M_LUSERS.C SRC/MODULES/M_NAMES.C SRC/MODULES/M_SVSNOLAG.C
191+
SRC/MODULES/M_LUSERS.C SRC/MODULES/M_NAMES.C SRC/MODULES/M_SVSNOLAG.C \
192+
SRC/MODULES/M_STARTTLS.C
192193

193194
DLL_FILES=SRC/MODULES/M_CHGHOST.DLL SRC/MODULES/M_SDESC.DLL SRC/MODULES/M_SETIDENT.DLL \
194195
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
224225
SRC/MODULES/M_WATCH.DLL SRC/MODULES/M_PART.DLL SRC/MODULES/M_JOIN.DLL \
225226
SRC/MODULES/M_MOTD.DLL SRC/MODULES/M_OPERMOTD.DLL SRC/MODULES/M_BOTMOTD.DLL \
226227
SRC/MODULES/M_LUSERS.DLL SRC/MODULES/M_NAMES.DLL SRC/MODULES/M_SVSNOLAG.DLL \
228+
SRC/MODULES/M_STARTTLS.DLL \
227229
SRC/MODULES/CLOAK.DLL
228230

229231

@@ -783,6 +785,9 @@ src/modules/cloak.dll: src/modules/cloak.c $(INCLUDES)
783785
src/modules/m_svsnolag.dll: src/modules/m_svsnolag.c $(INCLUDES)
784786
$(CC) $(MODCFLAGS) src/modules/m_svsnolag.c $(MODLFLAGS)
785787

788+
src/modules/m_starttls.dll: src/modules/m_starttls.c $(INCLUDES)
789+
$(CC) $(MODCFLAGS) src/modules/m_starttls.c $(MODLFLAGS)
790+
786791
dummy:
787792

788793

src/modules/Makefile.in

+9-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ R_MODULES= \
5454
m_connect.so m_dccallow.so m_userip.so m_nick.so m_user.so \
5555
m_mode.so m_watch.so m_part.so m_join.so m_motd.so m_opermotd.so \
5656
m_botmotd.so m_lusers.so m_names.so m_svsnolag.so m_addmotd.so \
57-
m_svslusers.so
57+
m_svslusers.so m_starttls.so
5858

5959
#note change of .c to .o
6060
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 \
7676
m_svsfline.o m_dccdeny.o m_undccdeny.o m_whowas.o \
7777
m_connect.o m_dccallow.o m_userip.o m_nick.o m_user.o \
7878
m_mode.o m_watch.o m_part.o m_join.o m_motd.o m_opermotd.o \
79-
m_botmotd.o m_lusers.o m_names.o m_svsnolag.o
79+
m_botmotd.o m_lusers.o m_names.o m_svsnolag.o m_starttls.o
8080

8181

8282
MODULES=commands.so cloak.so $(R_MODULES)
@@ -407,6 +407,9 @@ m_names.o: m_names.c $(INCLUDES)
407407
m_svsnolag.o: m_svsnolag.c $(INCLUDES)
408408
$(CC) $(CFLAGS) $(MODULEFLAGS) -c m_svsnolag.c
409409

410+
m_starttls.o: m_starttls.c $(INCLUDES)
411+
$(CC) $(CFLAGS) $(MODULEFLAGS) -c m_starttls.c
412+
410413
#############################################################################
411414
# .so's section
412415
#############################################################################
@@ -819,6 +822,10 @@ m_svsnolag.so: m_svsnolag.c $(INCLUDES)
819822
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
820823
-o m_svsnolag.so m_svsnolag.c
821824

825+
m_starttls.so: m_starttls.c $(INCLUDES)
826+
$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
827+
-o m_starttls.so m_starttls.c
828+
822829
#############################################################################
823830
# and now the remaining modules...
824831
#############################################################################

src/modules/m_starttls.c

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* IRC - Internet Relay Chat, src/modules/m_starttls.c
3+
* (C) 2009 Syzop & The UnrealIRCd Team
4+
*
5+
* See file AUTHORS in IRC package for additional names of
6+
* the programmers.
7+
*
8+
* This program is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License as published by
10+
* the Free Software Foundation; either version 1, or (at your option)
11+
* any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program; if not, write to the Free Software
20+
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21+
*/
22+
#include "config.h"
23+
#include "struct.h"
24+
#include "common.h"
25+
#include "sys.h"
26+
#include "numeric.h"
27+
#include "msg.h"
28+
#include "proto.h"
29+
#include "channel.h"
30+
#include <time.h>
31+
#include <sys/stat.h>
32+
#include <stdio.h>
33+
#include <stdlib.h>
34+
#include <string.h>
35+
#ifdef _WIN32
36+
#include <io.h>
37+
#endif
38+
#include <fcntl.h>
39+
#include "h.h"
40+
#ifdef STRIPBADWORDS
41+
#include "badwords.h"
42+
#endif
43+
#ifdef _WIN32
44+
#include "version.h"
45+
#endif
46+
47+
DLLFUNC CMD_FUNC(m_starttls);
48+
49+
#define MSG_STARTTLS "STARTTLS"
50+
51+
ModuleHeader MOD_HEADER(m_starttls)
52+
= {
53+
"m_starttls",
54+
"$Id$",
55+
"command /starttls",
56+
"3.2-b8-1",
57+
NULL
58+
};
59+
60+
DLLFUNC int MOD_INIT(m_starttls)(ModuleInfo *modinfo)
61+
{
62+
CommandAdd(modinfo->handle, MSG_STARTTLS, NULL, m_starttls, MAXPARA, M_UNREGISTERED);
63+
MARK_AS_OFFICIAL_MODULE(modinfo);
64+
return MOD_SUCCESS;
65+
}
66+
67+
DLLFUNC int MOD_LOAD(m_starttls)(int module_load)
68+
{
69+
return MOD_SUCCESS;
70+
}
71+
72+
DLLFUNC int MOD_UNLOAD(m_starttls)(int module_unload)
73+
{
74+
return MOD_SUCCESS;
75+
}
76+
77+
DLLFUNC CMD_FUNC(m_starttls)
78+
{
79+
if (!MyConnect(sptr) || !IsUnknown(sptr))
80+
return 0;
81+
#ifndef USE_SSL
82+
/* sendnotice(sptr, "This server does not support SSL"); */
83+
/* or numeric 691? */
84+
/* actually... it's probably best to just act like we don't know this command...? */
85+
sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "STARTTLS");
86+
return 0;
87+
#else
88+
if (iConf.ssl_options & SSLFLAG_NOSTARTTLS)
89+
{
90+
sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "STARTTLS");
91+
return 0;
92+
}
93+
if (IsSecure(sptr))
94+
{
95+
sendto_one(sptr, ":%s 691 %s :STARTTLS failed. Already using TLS.", me.name, sptr->name);
96+
return 0;
97+
}
98+
dbuf_delete(&sptr->recvQ, 1000000); /* Clear up any remaining plaintext commands */
99+
sendto_one(sptr, ":%s 670 %s :STARTTLS successful, go ahead with TLS handshake", me.name, sptr->name);
100+
// ^^ FIXME, use: RPL_STARTTLS
101+
send_queued(sptr);
102+
103+
SetSSLStartTLSHandshake(sptr);
104+
Debug((DEBUG_DEBUG, "Starting SSL handshake (due to STARTTLS) for %s", sptr->sockhost));
105+
if ((sptr->ssl = SSL_new(ctx_server)) == NULL)
106+
goto fail;
107+
sptr->flags |= FLAGS_SSL;
108+
SSL_set_fd(sptr->ssl, sptr->fd);
109+
SSL_set_nonblocking(sptr->ssl);
110+
if (!ircd_SSL_accept(sptr, sptr->fd)) {
111+
Debug((DEBUG_DEBUG, "Failed SSL accept handshake in instance 1: %s", sptr->sockhost));
112+
SSL_set_shutdown(sptr->ssl, SSL_RECEIVED_SHUTDOWN);
113+
SSL_smart_shutdown(sptr->ssl);
114+
SSL_free(sptr->ssl);
115+
goto fail;
116+
}
117+
118+
/* HANDSHAKE IN PROGRESS */
119+
return 0;
120+
fail:
121+
/* Failure */
122+
sendto_one(sptr, ":%s 691 %s :STARTTLS failed", me.name, sptr->name); // FIXME, use: ERR_STARTTLS
123+
sptr->ssl = NULL;
124+
sptr->flags &= ~FLAGS_SSL;
125+
SetUnknown(sptr);
126+
return 0;
127+
#endif
128+
}

src/s_bsd.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -1972,21 +1972,24 @@ int read_message(time_t delay, fdlist *listp)
19721972
!(DoingDNS(cptr) || DoingAuth(cptr))
19731973
#ifdef USE_SSL
19741974
&&
1975-
!(IsSSLAcceptHandshake(cptr) || IsSSLConnectHandshake(cptr))
1975+
!(IsSSLHandshake(cptr))
19761976
#endif
19771977
)
19781978
length = read_packet(cptr, &read_set);
19791979
#ifdef USE_SSL
19801980
if ((length != FLUSH_BUFFER) && (cptr->ssl != NULL) &&
1981-
(IsSSLAcceptHandshake(cptr) || IsSSLConnectHandshake(cptr)) &&
1981+
IsSSLHandshake(cptr) &&
19821982
FD_ISSET(cptr->fd, &read_set))
19831983
{
19841984
if (!SSL_is_init_finished(cptr->ssl))
19851985
{
1986-
if (IsDead(cptr) || IsSSLAcceptHandshake(cptr) ? !ircd_SSL_accept(cptr, cptr->fd) : ircd_SSL_connect(cptr) < 0)
1986+
if (IsDead(cptr) ||
1987+
(IsSSLAcceptHandshake(cptr) || IsSSLStartTLSHandshake(cptr)) ? !ircd_SSL_accept(cptr, cptr->fd) : ircd_SSL_connect(cptr) < 0)
19871988
{
19881989
length = -1;
19891990
}
1991+
/* if (IsSSLStartTLSHandshake(cptr))
1992+
length = read_packet(cptr, &read_set); */
19901993
}
19911994
if (SSL_is_init_finished(cptr->ssl))
19921995
{
@@ -1995,10 +1998,14 @@ int read_message(time_t delay, fdlist *listp)
19951998
Debug((DEBUG_ERROR, "ssl: start_of_normal_client_handshake(%s)", cptr->sockhost));
19961999
start_of_normal_client_handshake(cptr);
19972000
}
1998-
else
2001+
else if (IsSSLConnectHandshake(cptr))
19992002
{
20002003
Debug((DEBUG_ERROR, "ssl: completed_connection", cptr->name));
20012004
completed_connection(cptr);
2005+
} else if (IsSSLStartTLSHandshake(cptr))
2006+
{
2007+
SetUnknown(cptr);
2008+
/* STARTTLS is now complete. We could send something, but I don't know why... */
20022009
}
20032010

20042011
}

src/s_conf.c

+1
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ static OperFlag _SSLFlags[] = {
295295
{ SSLFLAG_FAILIFNOCERT, "fail-if-no-clientcert" },
296296
{ SSLFLAG_DONOTACCEPTSELFSIGNED, "no-self-signed" },
297297
{ SSLFLAG_VERIFYCERT, "verify-certificate" },
298+
{ SSLFLAG_NOSTARTTLS, "no-starttls" }
298299
};
299300
#endif
300301

src/s_err.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ static char *replies[] = {
726726
/* 667 */ NULL,
727727
/* 668 */ NULL,
728728
/* 669 */ NULL,
729-
/* 670 */ NULL, /* kineircd */
729+
/* 670 RPL_STARTTLS */ ":%s 670 %s :STARTTLS successful, go ahead with TLS handshake", /* kineircd */
730730
/* 671 RPL_WHOISSECURE */ ":%s 671 %s %s :%s", /* our variation on the kineircd numeric */
731731
/* 672 */ NULL, /* ithildin */
732732
/* 673 */ NULL, /* ithildin */
@@ -747,7 +747,7 @@ static char *replies[] = {
747747
/* 688 */ NULL, /* kineircd */
748748
/* 689 */ NULL, /* kineircd */
749749
/* 690 */ NULL, /* kineircd */
750-
/* 691 */ NULL,
750+
/* 691 ERR_STARTTLS */ ":%s 691 %s :%s",
751751
/* 692 */ NULL,
752752
/* 693 */ NULL,
753753
/* 694 */ NULL,

src/ssl.c

+3
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ int ircd_SSL_write(aClient *acptr, const void *buf, int sz)
490490
case SSL_ERROR_WANT_WRITE:
491491
SET_ERRNO(P_EWOULDBLOCK);
492492
return -1;
493+
case SSL_ERROR_WANT_READ:
494+
SET_ERRNO(P_EWOULDBLOCK); /* is this correct? next write will block if not read, so sounds right... */
495+
return -1;
493496
case SSL_ERROR_SSL:
494497
if(ERRNO == EAGAIN)
495498
return -1;

0 commit comments

Comments
 (0)