]> arthur.barton.de Git - ngircd-alex.git/commitdiff
TLS/SSL support: code changes.
authorFlorian Westphal <fw@strlen.de>
Sat, 13 Sep 2008 13:10:32 +0000 (15:10 +0200)
committerFlorian Westphal <fw@strlen.de>
Sat, 13 Sep 2008 13:10:32 +0000 (15:10 +0200)
This adds the required code to enable ssl/tls support
during compile and run time, respectively.

configure.in
src/ngircd/Makefile.am
src/ngircd/array.c
src/ngircd/conf.c
src/ngircd/conf.h
src/ngircd/conn.c
src/ngircd/conn.h
src/ngircd/irc-info.c
src/ngircd/ngircd.c

index 36f0bc28afb18e27f728af621bd2bb739774156f..61bf08e939333b6f5b1c1165d516ead18fb23882 100644 (file)
@@ -309,6 +309,52 @@ if test "$x_io_backend" = "none"; then
        AC_MSG_ERROR([No useabe IO API activated/found!?])
 fi
 
+# use SSL?
+
+AC_ARG_WITH(openssl,
+       [  --with-openssl          enable SSL support using OpenSSL],
+       [       if test "$withval" = "yes"; then
+                       if test "$withval" != "yes"; then
+                               CFLAGS="-I$withval/include $CFLAGS"
+                               CPPFLAGS="-I$withval/include $CPPFLAGS"
+                               LDFLAGS="-L$withval/lib $LDFLAGS"
+                       fi
+                       AC_CHECK_LIB(crypto, BIO_s_mem)
+                       AC_CHECK_LIB(ssl, SSL_library_init)
+                       AC_CHECK_FUNCS(SSL_library_init, x_ssl_openssl=yes,
+                               AC_MSG_ERROR([Can't enable openssl])
+                       )
+               fi
+       ]
+)
+
+AC_ARG_WITH(gnutls,
+       [  --with-gnutls           enable SSL support using gnutls],
+       [       if test "$withval" = "yes"; then
+                       if test "$withval" != "yes"; then
+                               CFLAGS="-I$withval/include $CFLAGS"
+                               CPPFLAGS="-I$withval/include $CPPFLAGS"
+                               LDFLAGS="-L$withval/lib $LDFLAGS"
+                       fi
+                       AC_CHECK_LIB(gnutls, gnutls_global_init)
+                       AC_CHECK_FUNCS(gnutls_global_init, x_ssl_gnutls=yes,
+                               AC_MSG_ERROR([Can't enable gnutls])
+                       )
+               fi
+       ]
+)
+
+x_ssl_lib="no"
+if test "$x_ssl_gnutls" = "yes"; then
+       if test "$x_ssl_openssl" = "yes";then
+               AC_MSG_ERROR([Cannot enable both gnutls and openssl])
+       fi
+       x_ssl_lib=gnutls
+fi
+if test "$x_ssl_openssl" = "yes"; then
+       x_ssl_lib=openssl
+fi
+
 # use TCP wrappers?
 
 x_tcpwrap_on=no
@@ -588,7 +634,11 @@ echo $ECHO_N "        I/O backend: $ECHO_C"
        echo "\"$x_io_backend\""
 
 echo $ECHO_N "      IPv6 protocol: $ECHO_C"
-echo "$x_ipv6_on"
+echo $ECHO_N "$x_ipv6_on    $ECHO_C"
+
+echo $ECHO_N "        SSL support: $ECHO_C"
+echo "$x_ssl_lib"
+
 echo
 
 # -eof-
index 1a5119f29853382625a06297043581ca0a9c4875..39ade59c21ba4a0ed135b50e39c466cea97fcdad 100644 (file)
@@ -21,7 +21,7 @@ LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
 sbin_PROGRAMS = ngircd
 
 ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
-       conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
+       conn-ssl.c conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \
        irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
        match.c numeric.c parse.c rendezvous.c resolve.c
 
@@ -30,7 +30,7 @@ ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
 ngircd_LDADD = -lngportab -lngtool -lngipaddr
 
 noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
-       conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \
+       conn-ssl.h conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \
        irc-mode.h irc-op.h irc-oper.h irc-server.h irc-write.h lists.h log.h \
        match.h numeric.h parse.h rendezvous.h resolve.h \
        defines.h messages.h
index ff7f02ce27afef98a3115e08b2759bcbaaa16e84..1e56b719cd4fabc74de4326959790d68805383ca 100644 (file)
@@ -281,6 +281,14 @@ array_free(array * a)
        a->used = 0;
 }
 
+void
+array_free_wipe(array *a)
+{
+       size_t bytes = a->allocated;
+       if (bytes)
+               memset(a->mem, 0, bytes);
+       array_free(a);
+}
 
 void *
 array_start(const array * const a)
index ca5611098388b5551ccf73fa99c9c15c32c0ed3a..a60a10e7a250586ce6b51e21f8b9ddb8004bba56 100644 (file)
@@ -76,6 +76,39 @@ static void Init_Server_Struct PARAMS(( CONF_SERVER *Server ));
 #define DEFAULT_LISTEN_ADDRSTR "0.0.0.0"
 #endif
 
+#ifdef SSL_SUPPORT
+struct SSLOptions Conf_SSLOptions;
+
+static void
+ConfSSL_Init(void)
+{
+       free(Conf_SSLOptions.KeyFile);
+       Conf_SSLOptions.KeyFile = NULL;
+
+       free(Conf_SSLOptions.CertFile);
+       Conf_SSLOptions.CertFile = NULL;
+
+       free(Conf_SSLOptions.DHFile);
+       Conf_SSLOptions.DHFile = NULL;
+       array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
+}
+
+
+static void
+ConfSSL_Puts(void)
+{
+       if (Conf_SSLOptions.KeyFile)
+               printf( "  SSLKeyFile = %s\n", Conf_SSLOptions.KeyFile);
+       if (Conf_SSLOptions.CertFile)
+               printf( "  SSLCertFile = %s\n", Conf_SSLOptions.CertFile);
+       if (Conf_SSLOptions.DHFile)
+               printf( "  SSLDHFile = %s\n", Conf_SSLOptions.DHFile);
+       if (array_bytes(&Conf_SSLOptions.KeyFilePassword))
+               puts("  SSLKeyFilePassword = <secret>"  );
+       array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
+}
+#endif
+
 static char *
 strdup_warn(const char *str)
 {
@@ -202,10 +235,16 @@ Conf_Test( void )
        printf( "  MotdPhrase = %s\n", Conf_MotdPhrase );
        printf( "  ChrootDir = %s\n", Conf_Chroot );
        printf( "  PidFile = %s\n", Conf_PidFile);
+       printf("  Listen = %s\n", Conf_ListenAddress);
        fputs("  Ports = ", stdout);
 
        ports_puts(&Conf_ListenPorts);
-       printf("  Listen = %s\n", Conf_ListenAddress);
+#ifdef SSL_SUPPORT
+       fputs("  SSLPorts = ", stdout);
+       ports_puts(&Conf_SSLOptions.ListenPorts);
+       ConfSSL_Puts();
+#endif
+
        pwd = getpwuid( Conf_UID );
        if( pwd ) printf( "  ServerUID = %s\n", pwd->pw_name );
        else printf( "  ServerUID = %ld\n", (long)Conf_UID );
@@ -248,6 +287,9 @@ Conf_Test( void )
                printf( "  Name = %s\n", Conf_Server[i].name );
                printf( "  Host = %s\n", Conf_Server[i].host );
                printf( "  Port = %u\n", (unsigned int)Conf_Server[i].port );
+#ifdef SSL_SUPPORT
+               printf( "  SSLConnect = %s\n", Conf_Server[i].SSLConnect?"yes":"no");
+#endif
                printf( "  MyPassword = %s\n", Conf_Server[i].pwd_in );
                printf( "  PeerPassword = %s\n", Conf_Server[i].pwd_out );
                printf( "  Group = %d\n", Conf_Server[i].group );
@@ -543,7 +585,9 @@ Read_Config( bool ngircd_starting )
        strcpy( section, "" );
        Init_Server_Struct( &New_Server );
        New_Server_Idx = NONE;
-
+#ifdef SSL_SUPPORT
+       ConfSSL_Init();
+#endif
        /* Read configuration file */
        while( true ) {
                if( ! fgets( str, LINE_LEN, fd )) break;
@@ -923,6 +967,37 @@ Handle_GLOBAL( int Line, char *Var, char *Arg )
                }
                return;
        }
+
+#ifdef SSL_SUPPORT
+       if( strcasecmp( Var, "SSLPorts" ) == 0 ) {
+               ports_parse(&Conf_SSLOptions.ListenPorts, Line, Arg);
+               return;
+       }
+
+       if( strcasecmp( Var, "SSLKeyFile" ) == 0 ) {
+               assert(Conf_SSLOptions.KeyFile == NULL );
+               Conf_SSLOptions.KeyFile = strdup_warn(Arg);
+               return;
+       }
+       if( strcasecmp( Var, "SSLCertFile" ) == 0 ) {
+               assert(Conf_SSLOptions.CertFile == NULL );
+               Conf_SSLOptions.CertFile = strdup_warn(Arg);
+               return;
+       }
+
+       if( strcasecmp( Var, "SSLKeyFilePassword" ) == 0 ) {
+               assert(array_bytes(&Conf_SSLOptions.KeyFilePassword) == 0);
+               if (!array_copys(&Conf_SSLOptions.KeyFilePassword, Arg))
+                       Config_Error( LOG_ERR, "%s, line %d (section \"Global\"): Could not copy %s: %s!",
+                                                               NGIRCd_ConfFile, Line, Var, strerror(errno));
+               return;
+       }
+       if( strcasecmp( Var, "SSLDHFile" ) == 0 ) {
+               assert(Conf_SSLOptions.DHFile == NULL);
+               Conf_SSLOptions.DHFile = strdup_warn( Arg );
+                return;
+        }
+#endif
        Config_Error(LOG_ERR, "%s, line %d (section \"Global\"): Unknown variable \"%s\"!",
                                                                NGIRCd_ConfFile, Line, Var);
 } /* Handle_GLOBAL */
@@ -1032,6 +1107,12 @@ Handle_SERVER( int Line, char *Var, char *Arg )
                                                                                NGIRCd_ConfFile, Line, port );
                return;
        }
+#ifdef SSL_SUPPORT
+       if( strcasecmp( Var, "SSLConnect" ) == 0 ) {
+               New_Server.SSLConnect = Check_ArgIsTrue(Arg);
+               return;
+        }
+#endif
        if( strcasecmp( Var, "Group" ) == 0 ) {
                /* Server group */
 #ifdef HAVE_ISDIGIT
index 6ec5bce909010e47075b672542bb398bf071ddd8..0e5b2abd96565dbd4434620e8ced5338d284c594 100644 (file)
@@ -24,6 +24,9 @@
 #include "portab.h"
 #include "tool.h"
 #include "ng_ipaddr.h"
+#include "resolve.h"
+#include "conf-ssl.h"
+
 
 typedef struct _Conf_Oper
 {
@@ -46,8 +49,23 @@ typedef struct _Conf_Server
        CONN_ID conn_id;                /* ID of server connection or NONE */
        ng_ipaddr_t bind_addr;          /* source address to use for outgoing connections */
        ng_ipaddr_t dst_addr[2];        /* list of addresses to connect to */
+#ifdef SSL_SUPPORT
+       bool SSLConnect;                /* connect() using SSL? */
+#endif
 } CONF_SERVER;
 
+
+#ifdef SSL_SUPPORT
+struct SSLOptions {
+       char *KeyFile;
+       char *CertFile;
+       char *DHFile;
+       array ListenPorts;
+       array KeyFilePassword;
+};
+#endif
+
+
 typedef struct _Conf_Channel
 {
        char name[CHANNEL_NAME_LEN];    /* Name of the channel */
index a0f7f242abce3f424fae292d871ea89804cba661..0b21d3a12b66e27fdfd392f20b235e19ba6a9d7d 100644 (file)
@@ -15,6 +15,7 @@
 #define CONN_MODULE
 
 #include "portab.h"
+#include "conf-ssl.h"
 #include "io.h"
 
 #include "imp.h"
@@ -58,6 +59,7 @@
 #include "ngircd.h"
 #include "client.h"
 #include "conf.h"
+#include "conn-ssl.h"
 #include "conn-zip.h"
 #include "conn-func.h"
 #include "log.h"
@@ -99,6 +101,11 @@ int deny_severity = LOG_ERR;
 
 static void server_login PARAMS((CONN_ID idx));
 
+#ifdef SSL_SUPPORT
+extern struct SSLOptions Conf_SSLOptions;
+static void cb_connserver_login_ssl PARAMS((int sock, short what));
+static void cb_clientserver_ssl PARAMS((int sock, short what));
+#endif
 static void cb_Read_Resolver_Result PARAMS(( int sock, UNUSED short what));
 static void cb_Connect_to_Server PARAMS(( int sock, UNUSED short what));
 static void cb_clientserver PARAMS((int sock, short what));
@@ -112,6 +119,22 @@ cb_listen(int sock, short irrelevant)
 }
 
 
+#ifdef SSL_SUPPORT
+static void
+cb_listen_ssl(int sock, short irrelevant)
+{
+       int fd;
+       (void) irrelevant;
+       fd = New_Connection(sock);
+       if (fd < 0)
+               return;
+
+       NumConnections++;
+       io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
+}
+#endif
+
+
 static void
 cb_connserver(int sock, UNUSED short what)
 {
@@ -166,6 +189,13 @@ cb_connserver(int sock, UNUSED short what)
        if (res >= 0) /* connect succeeded, remove all additional addresses */
                memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].dst_addr));
        Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
+#ifdef SSL_SUPPORT
+       if ( Conn_OPTION_ISSET( &My_Connections[idx], CONN_SSL_CONNECT )) {
+               io_event_setcb( sock, cb_connserver_login_ssl );
+               io_event_add( sock, IO_WANTWRITE|IO_WANTREAD );
+               return;
+       }
+#endif
        server_login(idx);
 }
 
@@ -185,24 +215,88 @@ server_login(CONN_ID idx)
 }
 
 
+#ifdef SSL_SUPPORT
+static void
+cb_connserver_login_ssl(int sock, short unused)
+{
+       CONN_ID idx = Socket2Index(sock);
+
+       assert(idx >= 0);
+       if (idx < 0) {
+               io_close(sock);
+               return;
+       }
+       (void) unused;
+       switch (ConnSSL_Connect( &My_Connections[idx])) {
+       case 1: break;
+       case 0: LogDebug("ConnSSL_Connect: not ready");
+               return;
+       case -1:
+               Log(LOG_INFO, "SSL connection on socket %d failed", sock);
+               Conn_Close(idx, "Can't connect!", NULL, false);
+               return;
+       }
+
+       Log( LOG_INFO, "SSL Connection %d with \"%s:%d\" established.", idx,
+                       My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port );
+
+       server_login(idx);
+}
+#endif
+
+
 static void
 cb_clientserver(int sock, short what)
 {
-       CONN_ID idx = Socket2Index( sock );
-       if (idx <= NONE) {
-#ifdef DEBUG
-               Log(LOG_WARNING, "WTF: cb_clientserver wants to write on unknown socket?!");
+       CONN_ID idx = Socket2Index(sock);
+
+       assert(idx >= 0);
+
+       if (idx < 0) {
+               io_close(sock);
+               return;
+       }
+#ifdef SSL_SUPPORT
+       if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE)))
+               Read_Request( idx ); /* if TLS layer needs to write additional data, call Read_Request instead so SSL/TLS can continue */
+#else
+       if (what & IO_WANTREAD)
+               Read_Request( idx );
 #endif
+       if (what & IO_WANTWRITE)
+               Handle_Write( idx );
+}
+
+
+#ifdef SSL_SUPPORT
+static void
+cb_clientserver_ssl(int sock, short what)
+{
+       CONN_ID idx = Socket2Index(sock);
+
+       assert(idx >= 0);
+
+       if (idx < 0) {
                io_close(sock);
                return;
        }
 
+       switch (ConnSSL_Accept(&My_Connections[idx])) {
+               case 1: break;  /* OK */
+               case 0: return; /* EAGAIN: this callback will be invoked again by the io layer */
+               default:
+                       Conn_Close( idx, "Socket closed!", "SSL accept error", false );
+                       return;
+       }
        if (what & IO_WANTREAD)
-               Read_Request( idx );
+               Read_Request(idx);
 
        if (what & IO_WANTWRITE)
-               Handle_Write( idx );
+               Handle_Write(idx);
+
+       io_event_setcb(sock, cb_clientserver);  /* SSL handshake completed */
 }
+#endif
 
 
 GLOBAL void
@@ -323,8 +417,12 @@ Conn_InitListeners( void )
 
        while (listen_addr) {
                ngt_TrimStr(listen_addr);
-               if (*listen_addr)
+               if (*listen_addr) {
                        created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen);
+#ifdef SSL_SUPPORT
+                       created += ports_initlisteners(&Conf_SSLOptions.ListenPorts, listen_addr, cb_listen_ssl);
+#endif
+               }
 
                listen_addr = strtok(NULL, ",");
        }
@@ -477,6 +575,44 @@ NewListener(const char *listen_addr, UINT16 Port)
        return sock;
 } /* NewListener */
 
+#ifdef SSL_SUPPORT
+/*
+ * SSL/TLS connections require extra treatment:
+ * When either CONN_SSL_WANT_WRITE or CONN_SSL_WANT_READ is set, we
+ * need to take care of that first, before checking read/write buffers.
+ * For instance, while we might have data in our write buffer, the
+ * TLS/SSL protocol might need to read internal data first for TLS/SSL
+ * writes to succeed.
+ *
+ * If this function returns true, such a condition is met and we have
+ * to reverse the condition (check for read even if we've data to write,
+ * do not check for read but writeability even if write-buffer is empty).
+ */
+static bool
+SSL_WantRead(const CONNECTION *c)
+{
+       if (Conn_OPTION_ISSET(c, CONN_SSL_WANT_READ)) {
+               io_event_add(c->sock, IO_WANTREAD);
+               return true;
+       }
+       return false;
+}
+static bool
+SSL_WantWrite(const CONNECTION *c)
+{
+       if (Conn_OPTION_ISSET(c, CONN_SSL_WANT_WRITE)) {
+               io_event_add(c->sock, IO_WANTWRITE);
+               return true;
+       }
+       return false;
+}
+#else
+static inline bool
+SSL_WantRead(UNUSED const CONNECTION *c) { return false; }
+static inline bool
+SSL_WantWrite(UNUSED const CONNECTION *c) { return false; }
+#endif
+
 
 /**
  * "Main Loop": Loop until shutdown or restart is signalled.
@@ -532,7 +668,8 @@ Conn_Handler(void)
                        if (wdatalen > 0)
 #endif
                        {
-                               /* Set the "WANTWRITE" flag on this socket */
+                               if (SSL_WantRead(&My_Connections[i]))
+                                       continue;
                                io_event_add(My_Connections[i].sock,
                                             IO_WANTWRITE);
                        }
@@ -542,7 +679,10 @@ Conn_Handler(void)
                for (i = 0; i < Pool_Size; i++) {
                        if (My_Connections[i].sock <= NONE)
                                continue;
-
+#ifdef SSL_SUPPORT
+                       if (SSL_WantWrite(&My_Connections[i]))
+                               continue; /* TLS/SSL layer needs to write data; deal with this first */
+#endif
                        if (Resolve_INPROGRESS(&My_Connections[i].res_stat)) {
                                /* Wait for completion of resolver sub-process ... */
                                io_event_del(My_Connections[i].sock,
@@ -816,7 +956,12 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 
        /* Search client, if any (re-check!) */
        c = Conn_GetClient( Idx );
-
+#ifdef SSL_SUPPORT
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
+               Log( LOG_INFO, "SSL Connection %d shutting down", Idx );
+               ConnSSL_Free(&My_Connections[Idx]);
+       }
+#endif
        /* Shut down socket */
        if (! io_close(My_Connections[Idx].sock)) {
                /* Oops, we can't close the socket!? This is ... ugly! */
@@ -966,9 +1111,15 @@ Handle_Write( CONN_ID Idx )
            ("Handle_Write() called for connection %d, %ld bytes pending ...",
             Idx, wdatalen);
 
-       len = write(My_Connections[Idx].sock,
-                   array_start(&My_Connections[Idx].wbuf), wdatalen );
-
+#ifdef SSL_SUPPORT
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
+               len = ConnSSL_Write(&My_Connections[Idx], array_start(&My_Connections[Idx].wbuf), wdatalen);
+       } else
+#endif
+       {
+               len = write(My_Connections[Idx].sock,
+                           array_start(&My_Connections[Idx].wbuf), wdatalen );
+       }
        if( len < 0 ) {
                if (errno == EAGAIN || errno == EINTR)
                        return true;
@@ -1170,6 +1321,11 @@ Read_Request( CONN_ID Idx )
                return;
        }
 
+#ifdef SSL_SUPPORT
+       if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL))
+               len = ConnSSL_Read( &My_Connections[Idx], readbuf, sizeof(readbuf));
+       else
+#endif
        len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
        if (len == 0) {
                Log(LOG_INFO, "%s:%u (%s) is closing the connection ...",
@@ -1551,7 +1707,16 @@ New_Server( int Server , ng_ipaddr_t *dest)
                Init_Conn_Struct( new_sock );
                Conf_Server[Server].conn_id = NONE;
        }
-
+#ifdef SSL_SUPPORT
+       if (Conf_Server[Server].SSLConnect && !ConnSSL_PrepareConnect( &My_Connections[new_sock],
+                                                               &Conf_Server[Server] ))
+       {
+               Log(LOG_ALERT, "Could not initialize SSL for outgoing connection");
+               Conn_Close( new_sock, "Could not initialize SSL for outgoing connection", NULL, false );
+               Init_Conn_Struct( new_sock );
+               Conf_Server[Server].conn_id = NONE;
+       }
+#endif
        LogDebug("Registered new connection %d on socket %d.",
                                new_sock, My_Connections[new_sock].sock );
        Conn_OPTION_ADD( &My_Connections[new_sock], CONN_ISCONNECTING );
@@ -1773,4 +1938,19 @@ Conn_GetClient( CONN_ID Idx )
        return c ? c->client : NULL;
 }
 
+#ifdef SSL_SUPPORT
+/* we cannot access My_Connections in irc-info.c */
+GLOBAL bool
+Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len)
+{
+       return ConnSSL_GetCipherInfo(&My_Connections[Idx], buf, len);
+}
+
+
+GLOBAL bool
+Conn_UsesSSL(CONN_ID Idx)
+{
+       return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL);
+}
+#endif
 /* -eof- */
index 3bb76ab39d13379f24ee469a2a97a91deb500ca7..cbfcc8f1735dea657b2d635ad617bfc716a3241f 100644 (file)
 #define CONN_ZIP               4       /* zlib compressed link */
 #endif
 
+#include "conf-ssl.h"
 
+#ifdef SSL_SUPPORT
+#define CONN_SSL_CONNECT       8       /* wait for ssl connect to finish */
+#define CONN_SSL               16      /* this connection is SSL encrypted */
+#define CONN_SSL_WANT_WRITE    32      /* SSL/TLS library needs to write protocol data */
+#define CONN_SSL_WANT_READ     64      /* SSL/TLS library needs to read protocol data */
+#endif
 typedef int CONN_ID;
 
 #include "client.h"
@@ -74,6 +81,9 @@ typedef struct _Connection
 #ifdef ZLIB
        ZIPDATA zip;                    /* Compression information */
 #endif  /* ZLIB */
+#ifdef SSL_SUPPORT
+       struct ConnSSL_State    ssl_state;      /* SSL/GNUTLS state information */
+#endif
 } CONNECTION;
 
 GLOBAL CONNECTION *My_Connections;
@@ -98,6 +108,12 @@ GLOBAL void Conn_Close PARAMS(( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool In
 GLOBAL void Conn_SyncServerStruct PARAMS(( void ));
 
 GLOBAL CLIENT* Conn_GetClient PARAMS((CONN_ID i));
+#ifdef SSL_SUPPORT
+GLOBAL bool Conn_GetCipherInfo PARAMS((CONN_ID Idx, char *buf, size_t len));
+GLOBAL bool Conn_UsesSSL PARAMS((CONN_ID Idx));
+#else
+static inline bool Conn_UsesSSL(UNUSED CONN_ID Idx) { return false; }
+#endif
 #endif
 
 /* -eof- */
index 808a85703fa48defffe9128fe2cb503beb3533bd..34198bf3e7e2b30ff8a0679d3dbdcbbb0633f547 100644 (file)
@@ -1167,6 +1167,23 @@ Show_MOTD_End(CLIENT *Client)
        return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
 }
 
+#ifdef SSL_SUPPORT
+static bool Show_MOTD_SSLInfo(CLIENT *Client)
+{
+       bool ret = true;
+       char buf[COMMAND_LEN] = "Connected using Cipher ";
+
+       if (!Conn_GetCipherInfo(Client_Conn(Client), buf + 23, sizeof buf - 23))
+               return true;
+
+       if (!Show_MOTD_Sendline(Client, buf))
+               ret = false;
+
+       return ret;
+}
+#else
+static inline bool Show_MOTD_SSLInfo(UNUSED CLIENT *c) { return true; }
+#endif
 
 GLOBAL bool
 IRC_Show_MOTD( CLIENT *Client )
@@ -1181,13 +1198,17 @@ IRC_Show_MOTD( CLIENT *Client )
                        return DISCONNECTED;
                if (!Show_MOTD_Sendline(Client, Conf_MotdPhrase))
                        return DISCONNECTED;
-
-               return Show_MOTD_End(Client);
+               goto out;
        }
 
        fd = fopen( Conf_MotdFile, "r" );
        if( ! fd ) {
                Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
+               if (Conn_UsesSSL(Client_Conn(Client))) {
+                       if (!Show_MOTD_Start(Client))
+                               return DISCONNECTED;
+                       goto out;
+               }
                return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
        }
 
@@ -1205,6 +1226,9 @@ IRC_Show_MOTD( CLIENT *Client )
                }
        }
        fclose(fd);
+out:
+       if (!Show_MOTD_SSLInfo(Client))
+               return DISCONNECTED;
        return Show_MOTD_End(Client);
 } /* IRC_Show_MOTD */
 
index 97e5733b512069cf943fb2efea36e7ded2202239..d9428ed4bacc3c4f028f0f8eac7e7252e0021e85 100644 (file)
@@ -41,6 +41,7 @@
 #include "defines.h"
 #include "resolve.h"
 #include "conn.h"
+#include "conf-ssl.h"
 #include "client.h"
 #include "channel.h"
 #include "conf.h"
@@ -367,6 +368,10 @@ Fill_Version( void )
 
        strlcat( NGIRCd_VersionAddition, "ZLIB", sizeof NGIRCd_VersionAddition );
 #endif
+#ifdef SSL_SUPPORT
+       if ( NGIRCd_VersionAddition[0] ) strlcat( NGIRCd_VersionAddition, "+", sizeof NGIRCd_VersionAddition );
+       strlcat( NGIRCd_VersionAddition, "SSL", sizeof NGIRCd_VersionAddition );
+#endif
 #ifdef TCPWRAP
        if( NGIRCd_VersionAddition[0] )
                        strlcat( NGIRCd_VersionAddition, "+", sizeof NGIRCd_VersionAddition );
@@ -465,7 +470,10 @@ NGIRCd_Rehash( void )
 
        /* Create new pre-defined channels */
        Channel_InitPredefined( );
-       
+
+       if (!ConnSSL_InitLibrary())
+               Log(LOG_WARNING, "Re-Initializing SSL failed, using old keys");
+
        /* Start listening on sockets */
        Conn_InitListeners( );
 
@@ -726,6 +734,9 @@ NGIRCd_Init( bool NGIRCd_NoDaemon )
        if (initialized)
                return true;
 
+       if (!ConnSSL_InitLibrary())
+               Log(LOG_WARNING, "Warning: Error during SSL initialization, continuing");
+
        if( Conf_Chroot[0] ) {
                if( chdir( Conf_Chroot ) != 0 ) {
                        Log( LOG_ERR, "Can't chdir() in ChrootDir (%s): %s", Conf_Chroot, strerror( errno ));