From ef3327d372c159bd2a395d6854843982a5e9c54d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 13 Sep 2008 15:10:32 +0200 Subject: [PATCH] TLS/SSL support: code changes. This adds the required code to enable ssl/tls support during compile and run time, respectively. --- configure.in | 52 ++++++++++- src/ngircd/Makefile.am | 4 +- src/ngircd/array.c | 8 ++ src/ngircd/conf.c | 85 ++++++++++++++++- src/ngircd/conf.h | 18 ++++ src/ngircd/conn.c | 208 ++++++++++++++++++++++++++++++++++++++--- src/ngircd/conn.h | 16 ++++ src/ngircd/irc-info.c | 28 +++++- src/ngircd/ngircd.c | 13 ++- 9 files changed, 410 insertions(+), 22 deletions(-) diff --git a/configure.in b/configure.in index 36f0bc28..61bf08e9 100644 --- a/configure.in +++ b/configure.in @@ -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- diff --git a/src/ngircd/Makefile.am b/src/ngircd/Makefile.am index 1a5119f2..39ade59c 100644 --- a/src/ngircd/Makefile.am +++ b/src/ngircd/Makefile.am @@ -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 diff --git a/src/ngircd/array.c b/src/ngircd/array.c index ff7f02ce..1e56b719 100644 --- a/src/ngircd/array.c +++ b/src/ngircd/array.c @@ -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) diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c index ca561109..a60a10e7 100644 --- a/src/ngircd/conf.c +++ b/src/ngircd/conf.c @@ -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 = " ); + 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 diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h index 6ec5bce9..0e5b2abd 100644 --- a/src/ngircd/conf.h +++ b/src/ngircd/conf.h @@ -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 */ diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index a0f7f242..0b21d3a1 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -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- */ diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h index 3bb76ab3..cbfcc8f1 100644 --- a/src/ngircd/conn.h +++ b/src/ngircd/conn.h @@ -28,7 +28,14 @@ #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- */ diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 808a8570..34198bf3 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -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 */ diff --git a/src/ngircd/ngircd.c b/src/ngircd/ngircd.c index 97e5733b..d9428ed4 100644 --- a/src/ngircd/ngircd.c +++ b/src/ngircd/ngircd.c @@ -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 )); -- 2.39.2