Parcourir la source

Merge branch 'ssl'

* ssl: (24 commits)
  * Cleanup symbol tables when unloading
  * Only leaf bots should reprocesses servers on server-use-ssl changing
  * Fix path to libssl_defs
  * Update docs
  * Link libcrypto in at runtime to avoid mismatched libcrypto/libssl
  * Move ssl.{c,h} to libssl.{c,h}
  * Fix cases that should be graceful failures when loading SSL
  * Auto switch server list if server-use-ssl changes
  * Update docs
  * Log when using SSL on IRC
  * Add 'servers6-ssl'
  * Load SSL on-demand at runtime via dlopen() if needed
  * Cleanup default ports for EFNet SSL servers
  * Refactor some of the SSL code into ssl.c
  * Automatically generate symbols definitions
  * Add runtime dynamic loader / symbol table handling
  * Include ssl_use even if SSL is not compiled in
  * Use the 'servers-ssl' list if 'use-ssl' is set
  * Add 'server-use-ssl' boolean
  * Add 'server-port-ssl'
  ...
Bryan Drewery il y a 15 ans
Parent
commit
5fbf8e4d86

+ 2 - 2
Makefile.in

@@ -39,7 +39,7 @@ STRIP = @STRIP@
 DIFF = @DIFF@
 
 #LIBS = @LIBS@ @ZLIB@
-LIBS = @LIBS@ @SSL_LIBS@
+LIBS = @LIBS@
 
 DEBCXXFLAGS = -DDEBUG -fno-inline -g3 -ggdb3 -O0 -Wshadow -Wpointer-arith -Wcast-align @GCC3DEB@ @GCC4DEB@
 CFLGS = @GCC3@ -fno-rtti @SSL_INCLUDES@
@@ -102,7 +102,7 @@ clean:  cleanutils
 
 distclean: clean
 	@rm -rf *-$(VERSION)/ autom4te.cache/ autoscan.log configure.scan
-	@rm -rf src/.deps/ src/compat/.deps/ src/strucutres/.deps/ src/mod/*.mod/.deps/ src/crypto/.deps
+	@rm -rf src/.deps/ src/compat/.deps/ src/strucutres/.deps/ src/mod/*.mod/.deps/ src/crypto/.deps src/.defs/
 	-+@cd lib && $(MAKE) distclean
 	@rm -f $(STATICMAKEFILES) $(CONFIGFILES)
 

+ 2 - 0
autotools/configure.ac

@@ -217,6 +217,8 @@ if [ "$GIT_REQUIRED" = "1" ]; then
 fi
 ]
 
+src/generate_defs.sh
+
 echo ""
 echo ""
 echo "------------ Configuring BDLIB ------------"

+ 1 - 0
autotools/includes/acinclude.m4

@@ -547,6 +547,7 @@ LIBS="$save_LIBS"
 
 AC_SUBST(SSL_INCLUDES)
 AC_SUBST(SSL_LIBS)
+AC_DEFINE_UNQUOTED(EGG_SSL_EXT, 1, [Defines whether or not SSL is supported])dnl
 ])
 
 dnl  EGG_HEADER_STDC()

+ 3 - 0
config.h.in

@@ -13,6 +13,9 @@
 /* big endian */
 #undef B_ENDIAN
 
+/* Defines whether or not SSL is supported */
+#undef EGG_SSL_EXT
+
 /* Defines the current pack version */
 #undef EGG_VERSION
 

+ 6 - 0
configure

@@ -5379,6 +5379,10 @@ LIBS="$save_LIBS"
 
 
 
+cat >>confdefs.h <<_ACEOF
+#define EGG_SSL_EXT 1
+_ACEOF
+
 
 
 #AC_SUBST(ZLIB)dnl
@@ -9017,6 +9021,8 @@ if [ "$GIT_REQUIRED" = "1" ]; then
 fi
 
 
+src/generate_defs.sh
+
 echo ""
 echo ""
 echo "------------ Configuring BDLIB ------------"

+ 3 - 0
doc/UPDATES

@@ -15,6 +15,9 @@
   * Permanent owners can no longer be removed via cmd_mns_user
   * Fix +take clearing -fastop (fixes #371)
   * Added botbitch to mmode (fixes #139)
+  * Added SSL support
+    This includes new set options: 'servers-ssl', 'servers6-ssl', 'server-port-ssl', 'server-use-ssl'
+  * libcrypto (openssl) is now loaded at startup and is required.
 
 1.3.1 - http://wraith.botpack.net/milestone/1.3.1
   * Fix crash related to slowpart

+ 6 - 0
doc/help.txt

@@ -1617,6 +1617,10 @@ See also: reload, backup
                           after the alias is expanded. 
                           $bAliases may not reference other aliases.$b
 [N]  $bserver-port$b     Default port to use for server connections.
+[N]  $bserver-port-ssl$b Default port to use for SSL server connections.
+[B]  $bserver-use-ssl$b  Use SSL for IRC server connections?
+
+
 [B]  $bauth-chan$b       If set, auth cmds will work in channels as well as in msg, otherwise 
                           only in msg.
 [S]  $bauth-key$b        The authkey used during authing. Give to users if they need to auth. 
@@ -1649,7 +1653,9 @@ See also: reload, backup
 [D]  $bhijack$b          How to handle when a commonly used hijack method attempt is detected. 
  
 [L]  $bservers$b         Comma-separated list of servers the bot will use.
+[L]  $bservers-ssl$b     Comma-separated list of SSL servers to use if server-use-ssl is true.
 [L]  $bservers6$b        Comma-separated list of servers the bot will use (FOR IPv6).
+[L]  $bservers6-ssl$b    Comma-separated list of IPv6 SSL servers to use if server-use-ssl is true.
  
 [N]  $bmsgburst$b        How many messages to burst at once to server. (Too high will excess flood)
 [N]  $bmsgrate$b         How often (msecs) to dequeue msgs to the server. Only used on

+ 14 - 6
doc/settings.txt

@@ -54,19 +54,27 @@ irc.efnet.nl
 irc.inet.tele.dk
 irc.ipv6.he.net
 irc.ipv6.homelien.no
-irc.paraphysics.net
+irc.ipv6.paraphysics.net
 irc.underworld.no
 
 :servers_ssl
 efnet.xs4all.nl
-irc.choopa.ca
-irc.choopa.net
-irc.eversible.com
+irc.choopa.ca:9999
+irc.choopa.net:9999
+irc.eversible.com:9999
 irc.he.net
 irc.paraphysics.net
 irc.servercentral.net
-irc.shoutcast.com
-irc.umich.edu
+irc.shoutcast.com:8000
+irc.umich.edu:9999
+irc.underworld.no
+
+:servers6_ssl
+efnet.ipv6.xs4all.nl
+irc.choopa.ca:9999
+irc.choopa.net:9999
+irc.ipv6.he.net
+irc.ipv6.paraphysics.net
 irc.underworld.no
 
 :rbl

+ 3 - 0
src/Makefile.in

@@ -29,11 +29,14 @@ OBJS = auth.o \
 	dcc.o \
 	dccutil.o \
 	debug.o \
+	dl.o \
 	egg_timer.o \
 	enclink.o \
 	EncryptedStream.o \
 	flags.o \
 	garble.o \
+	libcrypto.o \
+	libssl.o \
 	log.o \
 	main.o \
 	match.o \

+ 1 - 1
src/cmds.c

@@ -4322,7 +4322,7 @@ static void rcmd_jump(char * frombot, char * fromhand, char * fromidx, char * pa
       }
 
       if (!port)
-        port = default_port;
+        port = (ssl_use ? default_port_ssl : default_port);
       strlcpy(newserver, other, 120); 
       newserverport = port; 
       strlcpy(newserverpass, par, 120); 

+ 1 - 1
src/crypt.c

@@ -11,7 +11,7 @@
 #include "settings.h"
 #include "misc.h"
 #include "base64.h"
-#include "src/crypto/crypto.h"
+#include "libcrypto.h"
 #include <stdarg.h>
 #include <bdlib/src/String.h>
 #include <bdlib/src/Stream.h>

+ 1 - 1
src/crypt.h

@@ -8,7 +8,7 @@
 #endif
 
 #include <sys/types.h>
-#include "src/crypto/crypto.h"
+#include "libcrypto.h"
 #include "users.h"
 
 #define SHA_HASH_LENGTH (SHA_DIGEST_LENGTH << 1)

+ 1 - 1
src/crypto/aes_util.c

@@ -2,7 +2,7 @@
  *
  */
 
-#include "crypto.h"
+#include "src/libcrypto.h"
 #include "src/compat/compat.h"
 #include <bdlib/src/String.h>
 

+ 1 - 1
src/crypto/bf_util.c

@@ -2,7 +2,7 @@
  *
  */
 
-#include "crypto.h"
+#include "src/libcrypto.h"
 #include "src/compat/compat.h"
 #include <bdlib/src/String.h>
 

+ 0 - 12
src/crypto/crypto.h

@@ -1,12 +0,0 @@
-#ifndef _CRYPTO_H
-#define _CRYPTO_H
-
-#include "aes_util.h"
-#include "bf_util.h"
-#include <openssl/crypto.h>
-#include <openssl/aes.h>
-#include <openssl/blowfish.h>
-#include <openssl/md5.h>
-#include <openssl/sha.h>
-
-#endif /* !_CRYPTO_H */

+ 35 - 0
src/dl.c

@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 1997 Robey Pointer
+ * Copyright (C) 1999 - 2002 Eggheads Development Team
+ * Copyright (C) 2002 - 2010 Bryan Drewery
+ *
+ * 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 2
+ * of the License, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * dl.c -- handles:
+ *   dlopen/dlsym and symbol table handling
+ *
+ */
+
+
+#include "common.h"
+#include "main.h"
+#include "dl.h"
+#include <bdlib/src/String.h>
+#include <bdlib/src/Array.h>
+#include <bdlib/src/HashTable.h>
+
+bd::HashTable<bd::String, FunctionPtr> dl_symbol_table;

+ 35 - 0
src/dl.h

@@ -0,0 +1,35 @@
+#ifndef _DL_H
+#define _DL_H
+
+#include "common.h"
+#include <dlfcn.h>
+
+#include <bdlib/src/String.h>
+#include <bdlib/src/HashTable.h>
+
+#define DLSYM(_handle, x) \
+  dlerror(); \
+  x##_t x; \
+  *(void **) (&x) = dlsym(_handle, #x); \
+  dlsym_error = dlerror(); \
+  if (dlsym_error) { \
+    sdprintf("%s", dlsym_error); \
+    return(1); \
+  }
+
+#define DLSYM_GLOBAL(_handle, x) do { \
+  dlerror(); \
+  dl_symbol_table[#x] = (FunctionPtr) ((x##_t) dlsym(_handle, #x)); \
+  my_symbols << #x; \
+  dlsym_error = dlerror(); \
+  if (dlsym_error) { \
+    sdprintf("%s", dlsym_error); \
+    return(1); \
+  } \
+} while (0)
+
+#define DLSYM_VAR(x) ((x##_t)dl_symbol_table[#x])
+
+extern bd::HashTable<bd::String, FunctionPtr> dl_symbol_table;
+
+#endif /* !_DL_H_ */

+ 23 - 0
src/generate_defs.sh

@@ -0,0 +1,23 @@
+#! /bin/bash
+
+mkdir -p src/.defs > /dev/null 2>&1
+
+for file in $(git grep -l DLSYM_GLOBAL|grep "\.c$"); do
+  defsFile="src/.defs/$(basename $file .c)_defs.h"
+  defsDefine=$(echo "_$(basename $file .c)_defs_h"| tr '[:lower:]' '[:upper:]')
+
+  cat > $defsFile << EOF
+#ifndef $defsDefine
+#define $defsDefine
+
+EOF
+  for symbol in $(sed -n -e 's/.*DLSYM_GLOBAL(.*, \([^)]*\).*/\1/p' $file|sort -u); do
+    key="_DLST_IDX_${symbol}"
+    printf "#define %-25s DLSYM_VAR(%s)\n" $symbol $symbol
+  done >> $defsFile
+  cat >> $defsFile << EOF
+
+#endif /* $defsDefine */
+EOF
+done
+

+ 113 - 0
src/libcrypto.c

@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 1997 Robey Pointer
+ * Copyright (C) 1999 - 2002 Eggheads Development Team
+ * Copyright (C) 2002 - 2010 Bryan Drewery
+ *
+ * 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 2
+ * of the License, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * libcrypto.c -- handles:
+ *   libcrypto handling
+ *
+ */
+
+
+#include "common.h"
+#include "main.h"
+#include "dl.h"
+#include <bdlib/src/String.h>
+#include <bdlib/src/Array.h>
+
+#include "libcrypto.h"
+
+void *libcrypto_handle = NULL;
+static bd::Array<bd::String> my_symbols;
+
+static int load_symbols(void *handle) {
+  const char *dlsym_error = NULL;
+
+  DLSYM_GLOBAL(handle, AES_cbc_encrypt);
+  DLSYM_GLOBAL(handle, AES_decrypt);
+  DLSYM_GLOBAL(handle, AES_encrypt);
+  DLSYM_GLOBAL(handle, AES_set_decrypt_key);
+  DLSYM_GLOBAL(handle, AES_set_encrypt_key);
+  DLSYM_GLOBAL(handle, BF_decrypt);
+  DLSYM_GLOBAL(handle, BF_encrypt);
+  DLSYM_GLOBAL(handle, BF_set_key);
+  DLSYM_GLOBAL(handle, ERR_error_string);
+  DLSYM_GLOBAL(handle, ERR_get_error);
+  DLSYM_GLOBAL(handle, OPENSSL_cleanse);
+  DLSYM_GLOBAL(handle, RAND_file_name);
+  DLSYM_GLOBAL(handle, RAND_load_file);
+  DLSYM_GLOBAL(handle, RAND_seed);
+  DLSYM_GLOBAL(handle, RAND_status);
+  DLSYM_GLOBAL(handle, RAND_write_file);
+  DLSYM_GLOBAL(handle, MD5_Final);
+  DLSYM_GLOBAL(handle, MD5_Init);
+  DLSYM_GLOBAL(handle, MD5_Update);
+  DLSYM_GLOBAL(handle, SHA1_Final);
+  DLSYM_GLOBAL(handle, SHA1_Init);
+  DLSYM_GLOBAL(handle, SHA1_Update);
+  DLSYM_GLOBAL(handle, SHA256_Final);
+  DLSYM_GLOBAL(handle, SHA256_Init);
+  DLSYM_GLOBAL(handle, SHA256_Update);
+
+  return 0;
+}
+
+
+int load_libcrypto() {
+  if (libcrypto_handle) {
+    return 0;
+  }
+
+  sdprintf("Loading libcrypto");
+
+  bd::Array<bd::String> libs_list(bd::String("libcrypto.so libcrypto.so.0.9.8 libcrypto.so.7 libcrypto.so.6").split(' '));
+
+  for (size_t i = 0; i < libs_list.length(); ++i) {
+    dlerror(); // Clear Errors
+    libcrypto_handle = dlopen(bd::String(libs_list[i]).c_str(), RTLD_LAZY);
+    if (libcrypto_handle) {
+      sdprintf("Found libcrypto: %s", bd::String(libs_list[i]).c_str());
+      break;
+    }
+  }
+  if (!libcrypto_handle) {
+    sdprintf("Unable to find libcrypto");
+    return(1);
+  }
+
+  load_symbols(libcrypto_handle);
+
+  return 0;
+}
+
+int unload_libcrypto() {
+  if (libcrypto_handle) {
+    // Cleanup symbol table
+    for (size_t i = 0; i < my_symbols.length(); ++i) {
+      dl_symbol_table.remove(my_symbols[i]);
+      static_cast<bd::String>(my_symbols[i]).clear();
+    }
+    my_symbols.clear();
+
+    dlclose(libcrypto_handle);
+    libcrypto_handle = NULL;
+    return 0;
+  }
+  return 1;
+}

+ 52 - 0
src/libcrypto.h

@@ -0,0 +1,52 @@
+#ifndef _LIBCRYPTO_H
+#define _LIBCRYPTO_H
+
+#include <openssl/crypto.h>
+#include <openssl/aes.h>
+#include <openssl/blowfish.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include "src/crypto/aes_util.h"
+#include "src/crypto/bf_util.h"
+
+#include "common.h"
+#include "dl.h"
+#include <bdlib/src/String.h>
+
+typedef void (*AES_cbc_encrypt_t)(const unsigned char*, unsigned char*, const unsigned long, const AES_KEY*, unsigned char*, const int);
+typedef void (*AES_decrypt_t)(const unsigned char*, unsigned char*, const AES_KEY*);
+typedef void (*AES_encrypt_t)(const unsigned char*, unsigned char*, const AES_KEY*);
+typedef int (*AES_set_decrypt_key_t)(const unsigned char*, const int, AES_KEY*);
+typedef int (*AES_set_encrypt_key_t)(const unsigned char*, const int, AES_KEY*);
+
+typedef void (*BF_decrypt_t)(BF_LONG*, const BF_KEY*);
+typedef void (*BF_encrypt_t)(BF_LONG*, const BF_KEY*);
+typedef void (*BF_set_key_t)(BF_KEY*, int, const unsigned char*);
+
+typedef char* (*ERR_error_string_t)(unsigned long, char*);
+typedef unsigned long (*ERR_get_error_t)(void);
+
+typedef void (*OPENSSL_cleanse_t)(void*, size_t);
+
+typedef const char* (*RAND_file_name_t)(char*, size_t);
+typedef int (*RAND_load_file_t)(const char*, long);
+typedef void (*RAND_seed_t)(const void*, int);
+typedef int (*RAND_status_t)(void);
+typedef int (*RAND_write_file_t)(const char*);
+
+typedef int (*MD5_Final_t)(unsigned char*, MD5_CTX*);
+typedef int (*MD5_Init_t)(MD5_CTX*);
+typedef int (*MD5_Update_t)(MD5_CTX*, const void*, size_t);
+typedef int (*SHA1_Final_t)(unsigned char*, SHA_CTX*);
+typedef int (*SHA1_Init_t)(SHA_CTX*);
+typedef int (*SHA1_Update_t)(SHA_CTX*, const void*, size_t);
+typedef int (*SHA256_Final_t)(unsigned char*, SHA256_CTX *);
+typedef int (*SHA256_Init_t)(SHA256_CTX*);
+typedef int (*SHA256_Update_t)(SHA256_CTX*, const void*, size_t);
+
+#include ".defs/libcrypto_defs.h"
+
+int load_libcrypto();
+int unload_libcrypto();
+
+#endif /* !_LIBCRYPTO_H */

+ 181 - 0
src/libssl.c

@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 1997 Robey Pointer
+ * Copyright (C) 1999 - 2002 Eggheads Development Team
+ * Copyright (C) 2002 - 2010 Bryan Drewery
+ *
+ * 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 2
+ * of the License, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * libssl.c -- handles:
+ *   libssl handling
+ *
+ */
+
+
+#include "common.h"
+#include "main.h"
+#include "dl.h"
+#include <bdlib/src/String.h>
+#include <bdlib/src/Array.h>
+
+#include "libssl.h"
+
+void *libssl_handle = NULL;
+static bd::Array<bd::String> my_symbols;
+#ifdef EGG_SSL_EXT
+SSL_CTX *ssl_ctx = NULL;
+char	*tls_rand_file = NULL;
+#endif
+int     ssl_use = 0; /* kyotou */
+
+static int seed_PRNG(void);
+
+static int load_symbols(void *handle) {
+  const char *dlsym_error = NULL;
+
+  DLSYM_GLOBAL(handle, SSL_get_error);
+  DLSYM_GLOBAL(handle, SSL_connect);
+  DLSYM_GLOBAL(handle, SSL_CTX_free);
+  DLSYM_GLOBAL(handle, SSL_CTX_new);
+  DLSYM_GLOBAL(handle, SSL_free);
+  DLSYM_GLOBAL(handle, SSL_library_init);
+  DLSYM_GLOBAL(handle, SSL_load_error_strings);
+  DLSYM_GLOBAL(handle, SSL_new);
+  DLSYM_GLOBAL(handle, SSL_pending);
+  DLSYM_GLOBAL(handle, SSL_read);
+  DLSYM_GLOBAL(handle, SSL_set_fd);
+  DLSYM_GLOBAL(handle, SSL_shutdown);
+  DLSYM_GLOBAL(handle, SSLv23_client_method);
+  DLSYM_GLOBAL(handle, SSL_write);
+
+  return 0;
+}
+
+
+int load_ssl() {
+  if (ssl_ctx) {
+    return 0;
+  }
+
+  sdprintf("Loading libssl");
+
+  bd::Array<bd::String> libs_list(bd::String("libssl.so libssl.so.0.9.8 libssl.so.7 libssl.so.6").split(' '));
+
+  for (size_t i = 0; i < libs_list.length(); ++i) {
+    dlerror(); // Clear Errors
+    libssl_handle = dlopen(bd::String(libs_list[i]).c_str(), RTLD_LAZY);
+    if (libssl_handle) {
+      sdprintf("Found libssl: %s", bd::String(libs_list[i]).c_str());
+      break;
+    }
+  }
+  if (!libssl_handle) {
+    sdprintf("Unable to find libssl");
+    return(1);
+  }
+
+  load_symbols(libssl_handle);
+
+#ifdef EGG_SSL_EXT
+  /* good place to init ssl stuff */
+  SSL_load_error_strings();
+  OpenSSL_add_ssl_algorithms();
+  ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+  if (!ssl_ctx) {
+    sdprintf("SSL_CTX_new() failed");
+    return 1;
+  }
+
+  if (seed_PRNG()) {
+    sdprintf("Wasn't able to properly seed the PRNG!");
+    return 1;
+  }
+#endif
+
+  return 0;
+}
+
+int unload_ssl() {
+  if (libssl_handle) {
+#ifdef EGG_SSL_EXT
+    /* cleanup mess when quiting */
+    if (ssl_ctx) {
+      SSL_CTX_free(ssl_ctx);
+      ssl_ctx = NULL;
+    }
+    if (tls_rand_file)
+      RAND_write_file(tls_rand_file);
+#endif
+
+    // Cleanup symbol table
+    for (size_t i = 0; i < my_symbols.length(); ++i) {
+      dl_symbol_table.remove(my_symbols[i]);
+      static_cast<bd::String>(my_symbols[i]).clear();
+    }
+    my_symbols.clear();
+
+    dlclose(libssl_handle);
+    libssl_handle = NULL;
+    return 0;
+  }
+  return 1;
+}
+
+#ifdef EGG_SSL_EXT
+static int seed_PRNG(void)
+{
+  char stackdata[1024];
+  static char rand_file[300];
+  FILE *fh;
+
+#if OPENSSL_VERSION_NUMBER >= 0x00905100
+  if (RAND_status())
+    return 0;     /* PRNG already good seeded */
+#endif
+  /* if the device '/dev/urandom' is present, OpenSSL uses it by default.
+   * check if it's present, else we have to make random data ourselfs.
+   */
+  if ((fh = fopen("/dev/urandom", "r"))) {
+    fclose(fh);
+    // Try /dev/random if urandom is unavailable
+    if ((fh = fopen("/dev/random", "r"))) {
+      fclose(fh);
+      return 0;
+    }
+  }
+  if (RAND_file_name(rand_file, sizeof(rand_file)))
+    tls_rand_file = rand_file;
+  else
+    return 1;
+  if (!RAND_load_file(rand_file, 1024)) {
+    /* no .rnd file found, create new seed */
+    unsigned int c;
+    c = time(NULL);
+    RAND_seed(&c, sizeof(c));
+    c = getpid();
+    RAND_seed(&c, sizeof(c));
+    RAND_seed(stackdata, sizeof(stackdata));
+  }
+#if OPENSSL_VERSION_NUMBER >= 0x00905100
+  if (!RAND_status())
+    return 2;   /* PRNG still badly seeded */
+#endif
+  return 0;
+}
+#endif
+
+
+

+ 43 - 0
src/libssl.h

@@ -0,0 +1,43 @@
+#ifndef _LIBSSL_H
+#define _LIBSSL_H
+
+#include "common.h"
+#include "dl.h"
+#include <bdlib/src/String.h>
+
+#ifdef EGG_SSL_EXT
+# ifndef EGG_SSL_INCS
+#  include <openssl/ssl.h>
+#  include <openssl/err.h>
+#  include <openssl/rand.h>
+#  define EGG_SSL_INCS 1
+# endif
+#endif
+
+typedef int (*SSL_get_error_t)(const SSL *, int);
+typedef void (*SSL_free_t)(SSL *);
+typedef int (*SSL_connect_t)(SSL *);
+typedef int (*SSL_read_t)(SSL *, void*, int);
+typedef int (*SSL_write_t)(SSL *, const void*, int);
+typedef SSL* (*SSL_new_t)(SSL_CTX *);
+typedef const SSL_METHOD* (*SSLv23_client_method_t)(void);
+typedef int (*SSL_shutdown_t)(SSL *);
+typedef int (*SSL_set_fd_t)(SSL *, int);
+typedef int (*SSL_pending_t)(const SSL *);
+typedef void (*SSL_load_error_strings_t)(void);
+typedef int (*SSL_library_init_t)(void);
+typedef void (*SSL_CTX_free_t)(SSL_CTX *);
+typedef SSL_CTX* (*SSL_CTX_new_t)(const SSL_METHOD *);
+
+#include ".defs/libssl_defs.h"
+
+int load_ssl();
+int unload_ssl();
+
+#ifdef EGG_SSL_EXT
+extern SSL_CTX *ssl_ctx;
+extern char *tls_rand_file;
+#endif
+extern int ssl_use;
+
+#endif /* !_LIBSSL_H */

+ 10 - 1
src/main.c

@@ -26,7 +26,6 @@
  *
  */
 
-
 #include "common.h"
 #include "main.h"
 #include "userent.h"
@@ -197,6 +196,12 @@ void fatal(const char *s, int recoverable)
     }
   }
 
+#ifdef EGG_SSL_EXT
+  if (ssl_use) {
+    unload_ssl();
+  }
+#endif
+
   if (!recoverable) {
 //    if (conf.bot && conf.bot->pid_file)
 //      unlink(conf.bot->pid_file);
@@ -686,6 +691,10 @@ int main(int argc, char **argv)
   check_trace(1);
 #endif
 
+  if (load_libcrypto()) {
+    fatal("Unable to load libcrypto.", 0);
+  }
+
   /* Initialize variables and stuff */
   timer_update_now(&egg_timeval_now);
   now = egg_timeval_now.sec;

+ 2 - 2
src/mod/server.mod/cmdsserv.c

@@ -39,7 +39,7 @@ static void cmd_servers(int idx, char *par)
     i = 0;
     for (; x; x = x->next) {
         simple_snprintf(s, sizeof s, "  %s:%d %s", x->name, 
-		     x->port ? x->port : default_port, 
+		     x->port ? x->port : (ssl_use ? default_port_ssl : default_port),
 		     (i == curserv) ? "<- I am here" : "");
       dprintf(idx, "%s\n", s);
       i++;
@@ -93,7 +93,7 @@ static void cmd_jump(int idx, char *par)
         port = atoi(p);
     }
     if (!port)
-      port = default_port;
+      port = (ssl_use ? default_port_ssl : default_port);
     putlog(LOG_CMDS, "*", "#%s# jump %s %d %s", dcc[idx].nick, other, port, par);
     strlcpy(newserver, other, sizeof newserver);
     newserverport = port;

+ 3 - 2
src/mod/server.mod/server.c

@@ -87,6 +87,7 @@ struct server_list *serverlist = NULL;	/* old-style queue, still used by
 					   server list */
 interval_t cycle_time;			/* cycle time till next server connect */
 port_t default_port = 6667;		/* default IRC port */
+port_t default_port_ssl = 6697;		/* default IRC SSL port */
 bool trigger_on_ignore;	/* trigger bindings if user is ignored ? */
 int answer_ctcp = 1;		/* answer how many stacked ctcp's ? */
 static bool resolvserv;		/* in the process of resolving a server host */
@@ -820,7 +821,7 @@ void next_server(int *ptr, char *servname, port_t *port, char *pass)
 
     x->next = 0;
     x->name = strdup(servname);
-    x->port = *port ? *port : default_port;
+    x->port = *port ? *port : (ssl_use ? default_port_ssl : default_port);
     if (pass && pass[0]) {
       x->pass = strdup(pass);
     } else
@@ -844,7 +845,7 @@ void next_server(int *ptr, char *servname, port_t *port, char *pass)
     *ptr = 0;
   }				/* Start over at the beginning */
   strcpy(servname, x->name);
-  *port = x->port ? x->port : default_port;
+  *port = x->port ? x->port : (ssl_use ? default_port_ssl : default_port);
   if (x->pass)
     strcpy(pass, x->pass);
   else

+ 1 - 1
src/mod/server.mod/server.h

@@ -50,7 +50,7 @@ extern size_t		nick_len;
 extern bool		trigger_on_ignore, floodless, keepnick, in_deaf, in_callerid, have_cprivmsg, have_cnotice;
 extern int 		servidx, ctcp_mode, answer_ctcp, serv, curserv, default_alines, flood_count, burst;
 extern unsigned int     rolls;
-extern port_t		default_port, newserverport, curservport;
+extern port_t		default_port, default_port_ssl, newserverport, curservport;
 extern time_t		server_online, tried_jupenick, tried_nick, release_time, connect_bursting;
 extern interval_t	cycle_time;
 extern char		cursrvname[], botrealname[121], botuserhost[], ctcp_reply[1024],

+ 21 - 2
src/mod/server.mod/servmsg.c

@@ -1376,7 +1376,11 @@ static void server_activity(int idx, char *msg, int len)
 
   if (unlikely(trying_server)) {
     strlcpy(dcc[idx].nick, "(server)", sizeof(dcc[idx].nick));
-    putlog(LOG_SERV, "*", "Connected to %s", dcc[idx].host);
+    if (ssl_use) {
+      putlog(LOG_SERV, "*", "Connected to %s with SSL", dcc[idx].host);
+    } else {
+      putlog(LOG_SERV, "*", "Connected to %s", dcc[idx].host);
+    }
 
     trying_server = 0;
     /*
@@ -1924,7 +1928,12 @@ static void connect_server(void)
     }
 
     next_server(&curserv, botserver, &botserverport, pass);
-    putlog(LOG_SERV, "*", "Trying server %s:%d", botserver, botserverport);
+
+    if (ssl_use) {
+      putlog(LOG_SERV, "*", "Trying SSL server %s:%d", botserver, botserverport);
+    } else {
+      putlog(LOG_SERV, "*", "Trying server %s:%d", botserver, botserverport);
+    }
 
     dcc[newidx].port = botserverport;
     strlcpy(dcc[newidx].nick, "(server)", sizeof(dcc[newidx].nick));
@@ -2027,6 +2036,16 @@ static void server_dns_callback(int id, void *client_data, const char *host, bd:
     servidx = idx;
     sdprintf("Connecting to '%s' (serv: %d, servidx: %d)", dcc[idx].host, serv, servidx);
     setsockopt(serv, 6, TCP_NODELAY, &i, sizeof(int));
+#ifdef EGG_SSL_EXT
+    if (ssl_use) { /* kyotou */
+      if (net_switch_to_ssl(serv) == 0) {
+        putlog(LOG_SERV, "*", "SSL Failed to connect to %s (Error while switching to SSL)", dcc[servidx].host);
+        trying_server = 0;
+        lostdcc(servidx);
+        return;
+      }
+    }
+#endif
     /* Queue standard login */
     dcc[idx].timeval = now;
     SERVER_SOCKET.timeout_val = &server_timeout;

+ 141 - 6
src/net.c

@@ -83,7 +83,6 @@ port_t firewallport = 1080;    /* Default port of Sock4/5 firewalls        */
 #define PROXY_SUN     2
 #define PROXY_HTTP    3
 
-
 /* I need an UNSIGNED long for dcc type stuff
  */
 unsigned long my_atoul(const char *s)
@@ -153,6 +152,9 @@ void init_net()
   for (int i = 0; i < MAXSOCKS; i++) {
     bzero(&socklist[i], sizeof(socklist[i]));
     socklist[i].flags = SOCK_UNUSED;
+#ifdef EGG_SSL_EXT
+    socklist[i].ssl = NULL;
+#endif
     socklist[i].sock = -1;
   }
 }
@@ -407,6 +409,13 @@ void real_killsock(register int sock, const char *file, int line)
 
   int i = -1;
   if ((i = findanysnum(sock)) != -1) {
+#ifdef EGG_SSL_EXT
+    if (socklist[i].ssl) {
+      SSL_shutdown(socklist[i].ssl);
+      SSL_free(socklist[i].ssl);
+      socklist[i].ssl = NULL;
+    }
+#endif
     close(socklist[i].sock);
     if (socklist[i].inbuf != NULL) {
       delete socklist[i].inbuf;
@@ -610,6 +619,70 @@ int open_telnet_raw(int sock, const char *ipIn, port_t sport, bool proxy_on, int
   return sock;
 }
 
+#ifdef EGG_SSL_EXT
+int net_switch_to_ssl(int sock) {
+  int i = 0;
+
+  if (load_ssl()) {
+    debug0("Error while switching to SSL - error loading library");
+    return 0;
+  }
+
+  debug0("net_switch_to_ssl()");
+  sleep(3); // Give some time to let the connect() go through.
+  for (i = 0; i < MAXSOCKS; ++i) {
+    if (socklist[i].sock == sock && !(socklist[i].flags & SOCK_UNUSED)) {
+      break;
+    }
+  }
+  if (i == MAXSOCKS) {
+    debug0("Error while swithing to SSL - sock not found in list");
+    return 0;
+  }
+
+  if (socklist[i].ssl) {
+    debug0("Error while swithing to SSL - already in ssl");
+    return 0;
+  }
+  socklist[i].ssl = SSL_new(ssl_ctx);
+  if (!socklist[i].ssl) {
+    debug0("Error while swithing to SSL - SSL_new() error");
+    return 0;
+  }
+
+  SSL_set_fd(socklist[i].ssl, socklist[i].sock);
+  int err = SSL_connect(socklist[i].ssl);
+  int timeout = 0;
+
+  while (err <= 0) {
+    if (timeout++ > 500) {
+      err = 0;
+      break;
+    }
+    int errs = SSL_get_error(socklist[i].ssl,err);
+    if ((errs != SSL_ERROR_WANT_READ) && (errs != SSL_ERROR_WANT_WRITE) && (errs != SSL_ERROR_WANT_X509_LOOKUP)) {
+      putlog(LOG_DEBUG, "*", "SSL_connect() = %d, %s", err, (char *)ERR_error_string(ERR_get_error(), NULL));
+      SSL_shutdown(socklist[i].ssl);
+      SSL_free(socklist[i].ssl);
+      socklist[i].ssl = NULL;
+      return 0;
+    }
+    usleep(1000);
+    err = SSL_connect(socklist[i].ssl);
+  }
+
+  if (err == 1) {
+    debug0("SSL_connect() success");
+    return 1;
+  }
+  debug0("Error while SSL_connect()");
+  SSL_shutdown(socklist[i].ssl);
+  SSL_free(socklist[i].ssl);
+  socklist[i].ssl = NULL;
+  return 0;
+}
+#endif
+
 /* Ordinary non-binary connection attempt */
 int open_telnet(const char *ip, port_t port, bool proxy, int identd)
 {
@@ -970,6 +1043,9 @@ static int sockread(char *s, int *len)
     /* Something happened */
     for (i = 0; i < MAXSOCKS; i++) {
       if ((!(socklist[i].flags & SOCK_UNUSED)) && ((FD_ISSET(socklist[i].sock, &fd)) ||
+#ifdef EGG_SSL_EXT
+            ((socklist[i].ssl) && (SSL_pending(socklist[i].ssl))) ||
+#endif
 	  ((socklist[i].sock == STDOUT) && (!backgrd) && (FD_ISSET(STDIN, &fd))))) {
 	if (socklist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
 	  /* Listening socket -- don't read, just return activity */
@@ -990,9 +1066,28 @@ static int sockread(char *s, int *len)
 	  return i;
 	}
 	errno = 0;
-	if (unlikely((socklist[i].sock == STDOUT) && !backgrd))
+	if (unlikely((socklist[i].sock == STDOUT) && !backgrd)) {
 	  x = read(STDIN, s, grab);
-	else
+#ifdef EGG_SSL_EXT
+        } else if (socklist[i].ssl) {
+            x = SSL_read(socklist[i].ssl,s,grab);
+            if (x < 0) {
+              int err = SSL_get_error(socklist[i].ssl, x);
+              x = -1;
+              switch (err) {
+                case SSL_ERROR_WANT_READ:
+                  errno = EAGAIN;
+                  break;
+                case SSL_ERROR_WANT_WRITE:
+                  errno = EAGAIN;
+                  break;
+                case SSL_ERROR_WANT_X509_LOOKUP:
+                  errno = EAGAIN;
+                  break;
+              }
+            }
+#endif
+        } else
           x = read(socklist[i].sock, s, grab);
 
 	if (x <= 0) {		/* eof */
@@ -1279,8 +1374,28 @@ void tputs(register int z, const char *s, size_t len)
       *(socklist[i].outbuf) += bd::String(s, len);
       return;
     }
-    /* Try. */
-    x = write(z, s, len);
+#ifdef EGG_SSL_EXT
+    if (socklist[i].ssl) {
+      x = SSL_write(socklist[i].ssl,s,len);
+      if (x < 0) {
+        int err = SSL_get_error(socklist[i].ssl, x);
+        x = -1;
+        switch (err) {
+          case SSL_ERROR_WANT_READ:
+            errno = EAGAIN;
+            break;
+          case SSL_ERROR_WANT_WRITE:
+            errno = EAGAIN;
+            break;
+          case SSL_ERROR_WANT_X509_LOOKUP:
+            errno = EAGAIN;
+            break;
+        }
+      }
+    } else
+#endif
+      /* Try. */
+      x = write(z, s, len);
     if (x == -1)
       x = 0;
     if ((size_t) x < len) {
@@ -1369,7 +1484,27 @@ void dequeue_sockets()
 	(socklist[i].outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
       /* Trick tputs into doing the work */
       errno = 0;
-      x = write(socklist[i].sock, socklist[i].outbuf->data(), socklist[i].outbuf->length());
+#ifdef EGG_SSL_EXT
+      if (socklist[i].ssl) {
+           x = write(socklist[i].sock, socklist[i].outbuf->data(), socklist[i].outbuf->length());
+           if (x < 0) {
+             int err = SSL_get_error(socklist[i].ssl, x);
+             x = -1;
+             switch (err) {
+               case SSL_ERROR_WANT_READ:
+                 errno = EAGAIN;
+                 break;
+               case SSL_ERROR_WANT_WRITE:
+                 errno = EAGAIN;
+                 break;
+               case SSL_ERROR_WANT_X509_LOOKUP:
+                 errno = EAGAIN;
+                 break;
+             }
+           }
+      } else
+#endif
+        x = write(socklist[i].sock, socklist[i].outbuf->data(), socklist[i].outbuf->length());
       if ((x < 0) && (errno != EAGAIN)
 #ifdef EBADSLT
 	  && (errno != EBADSLT)

+ 6 - 0
src/net.h

@@ -12,6 +12,8 @@
 #include <setjmp.h>
 #include <bdlib/src/String.h>
 
+#include "libssl.h"
+
 namespace bd {
   class Stream;
 }
@@ -84,6 +86,9 @@ typedef struct {
   int iseed;                            /* botlink in seed */
   int gz; /* gzip compression */
   int enclink;				/* new encrypted botlink */
+#ifdef EGG_SSL_EXT
+  SSL *ssl;
+#endif
   bd::String* inbuf;
   bd::String* outbuf;
   char *host;
@@ -139,6 +144,7 @@ void init_net(void);
 int sock_read(bd::Stream&);
 void sock_write(bd::Stream&, int);
 bool socket_run();
+int net_switch_to_ssl(int sock);
 
 extern union sockaddr_union 		cached_myip4_so;
 #ifdef USE_IPV6

+ 26 - 13
src/set.c

@@ -122,26 +122,32 @@ static variable_t vars[] = {
  VAR("rbl-servers",	rbl_servers,		VAR_STRING|VAR_LIST|VAR_SHUFFLE|VAR_NOLHUB,	0, 0, DEFAULT_RBL),
  VAR("realname",	botrealname,		VAR_STRING|VAR_NOLHUB,				0, 0, "* I'm too lame to read BitchX.doc *"),
  VAR("server-port",	&default_port,		VAR_INT|VAR_SHORT|VAR_NOLHUB,			0, 65535, "6667"),
+ VAR("server-port-ssl",	&default_port_ssl,	VAR_INT|VAR_SHORT|VAR_NOLHUB,			0, 65535, "6697"),
+ VAR("server-use-ssl",	&ssl_use,		VAR_INT|VAR_BOOL|VAR_NOLHUB,			0, 1, "0"),
  VAR("servers",		&serverlist,		VAR_SERVERS|VAR_LIST|VAR_SHUFFLE|VAR_NOLHUB|VAR_NOLDEF,	0, 0, DEFAULT_SERVERS),
+ VAR("servers-ssl",	&serverlist,		VAR_SERVERS|VAR_LIST|VAR_SHUFFLE|VAR_NOLHUB|VAR_NOLDEF,	0, 0, DEFAULT_SERVERS_SSL),
  VAR("servers6",	&serverlist,		VAR_SERVERS|VAR_LIST|VAR_SHUFFLE|VAR_NOLHUB|VAR_NOLDEF,	0, 0, DEFAULT_SERVERS6),
+ VAR("servers6-ssl",	&serverlist,		VAR_SERVERS|VAR_LIST|VAR_SHUFFLE|VAR_NOLHUB|VAR_NOLDEF,	0, 0, DEFAULT_SERVERS6_SSL),
  VAR("trace",		&trace,			VAR_INT|VAR_DETECTED,				0, 4, "die"),
  VAR("usermode",	&usermode,		VAR_WORD|VAR_NOLHUB,				0, 0, "+iws"),
  VAR(NULL,		NULL,			0,						0, 0, NULL)
 };
 
 
-static bool use_server_type(const char *name)
+static inline variable_t *var_get_var_by_name(const char *name);
+
+static const char* get_server_type()
 {
-  if (!conf.bot->hub) {
-    if (!strcmp(name, "servers")) {
-      if (conf.bot->net.host6 || conf.bot->net.ip6) /* we want to use the servers6 entry. */
-        return 0;
-    } else if (!strcmp(name, "servers6")) {
-      if (!conf.bot->net.host6 && !conf.bot->net.ip6) /* we probably want to use the normal server list.. */
-        return 0;
-    }
+  if (!ssl_use && !conf.bot->net.host6 && !conf.bot->net.ip6) {
+    return "servers";
+  } else if (!ssl_use && (conf.bot->net.host6 || conf.bot->net.ip6)) {
+    return "servers6";
+  } else if (ssl_use && !conf.bot->net.host6 && !conf.bot->net.ip6) {
+    return "servers-ssl";
+  } else if (ssl_use && (conf.bot->net.host6 || conf.bot->net.ip6)) {
+    return "servers6-ssl";
   }
-  return 1;
+  return "";
 }
 
 /* sanitize the variable data string */
@@ -382,7 +388,7 @@ sdprintf("var (mem): %s -> %s", var->name, datain ? datain : "(NULL)");
       --p;
       *p = ':';
     }
-  } else if ((var->flags & VAR_SERVERS) && use_server_type(var->name)) {
+  } else if ((var->flags & VAR_SERVERS) && !strcmp(get_server_type(), var->name)) {
     if (var->mem && *(struct server_list **)var->mem) {
       clearq(*(struct server_list **) var->mem);
       *(struct server_list **)var->mem = NULL;
@@ -397,6 +403,13 @@ sdprintf("var (mem): %s -> %s", var->name, datain ? datain : "(NULL)");
     }
   }
 
+  if (!conf.bot->hub && !strcmp(var->name, "server-use-ssl")) {
+    // Need to reload the server settings since we may want a different list now
+    sdprintf("server-use-ssl changed, reprocessing server list");
+    variable_t *servers = var_get_var_by_name(get_server_type());
+    var_set_mem(servers, servers->ldata ? servers->ldata : servers->gdata ? servers->gdata : NULL);
+  }
+
   if (datap)
     free(datap);
 
@@ -453,14 +466,14 @@ const char *var_string(variable_t *var)
   } else if (var->flags & VAR_SERVERS) {
     /* only bother setting/checking if we have 'serverlist' alloc'd */
     if (*(struct server_list **)var->mem) {
-      if (!use_server_type(var->name))
+      if (strcmp(var->name, get_server_type()))
         return NULL;
 
       struct server_list *n = NULL;
       char list[2048] = "", buf[101] = "";
 
       for (n = (*(struct server_list **)var->mem); n; n = n->next) {
-        if (n->port && n->port != default_port)
+        if (n->port && n->port != (ssl_use ? default_port_ssl : default_port))
           simple_snprintf(buf, sizeof(buf), "%s:%d", n->name, n->port);
         else
           strlcat(buf, n->name, sizeof(buf));

+ 1 - 0
src/types.h

@@ -15,6 +15,7 @@
 
 /* It's used in so many places, let's put it here */
 typedef int (*Function) ();
+typedef intptr_t (*FunctionPtr) ();
 
 #if !HAVE_SOCKLEN_T
 typedef int socklen_t;