diff options
author | Marius Halden <marius.h@lden.org> | 2015-11-08 08:58:37 +0100 |
---|---|---|
committer | Marius Halden <marius.h@lden.org> | 2016-05-07 14:26:17 +0200 |
commit | f6119b76d73b9cdff3cbfd902675a36bcacbcd48 (patch) | |
tree | 6c6f1581fd53a5b3094bfdc46838c2c893760a20 | |
parent | f0ff36f558329d096526004d4d912973bafd3904 (diff) |
Start adding ssl support
-rw-r--r-- | conf.c | 39 | ||||
-rw-r--r-- | conf.h | 5 | ||||
-rwxr-xr-x | configure | 4 | ||||
-rw-r--r-- | irc.c | 13 | ||||
-rw-r--r-- | irc.h | 11 | ||||
-rw-r--r-- | lib/ssl_client.h | 3 | ||||
-rw-r--r-- | lib/ssl_gnutls.c | 35 | ||||
-rw-r--r-- | root_commands.c | 10 |
8 files changed, 120 insertions, 0 deletions
@@ -70,6 +70,11 @@ conf_t *conf_load(int argc, char *argv[]) conf->ft_listen = NULL; conf->protocols = NULL; conf->cafile = NULL; +#ifdef WITH_GNUTLS + conf->ssl = FALSE; + conf->ssl_cert = NULL; + conf->ssl_key = NULL; +#endif /* WITH_GNUTLS */ proxytype = 0; i = conf_loadini(conf, global.conf_file); @@ -171,6 +176,23 @@ conf_t *conf_load(int argc, char *argv[]) return NULL; } +#ifdef WITH_GNUTLS + if (conf->ssl && (!conf->ssl_cert || !conf->ssl_key)) { + fprintf(stderr, "Error: SSL enabled but cert or key is missing\n"); + return NULL; + } + + if (conf->ssl && conf->ssl_cert && access(conf->ssl_cert, R_OK) != 0) { + fprintf(stderr, "Error: Could not read SSL Cert %s: %s\n", conf->ssl_cert, strerror(errno)); + return NULL; + } + + if (conf->ssl && conf->ssl_key && access(conf->ssl_key, R_OK) != 0) { + fprintf(stderr, "Error: Could not read SSL Key %s: %s\n", conf->ssl_key, strerror(errno)); + return NULL; + } +#endif /* WITH_GNUTLS */ + return conf; } @@ -343,6 +365,23 @@ static int conf_loadini(conf_t *conf, char *file) } else if (g_strcasecmp(ini->key, "cafile") == 0) { g_free(conf->cafile); conf->cafile = g_strdup(ini->value); +#ifdef WITH_GNUTLS + } else if (g_strcasecmp(ini->key, "ssl") == 0) { + if (g_strcasecmp(ini->value, "true") == 0) { + conf->ssl = TRUE; + } else if (g_strcasecmp(ini->value, "false") == 0) { + conf->ssl = FALSE; + } else { + fprintf(stderr, "Invalid %s value: %s\n", ini->key, ini->value); + return 0; + } + } else if (g_strcasecmp(ini->key, "ssl_cert") == 0) { + g_free(conf->ssl_cert); + conf->ssl_cert; + } else if (g_strcasecmp(ini->key, "ssl_key") == 0) { + g_free(conf->ssl_key); + conf->ssl_key; +#endif /* WITH_GNUTLS */ } else { fprintf(stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n", ini->key, ini->line); @@ -55,6 +55,11 @@ typedef struct conf { char *ft_listen; char **protocols; char *cafile; +#ifdef WITH_GNUTLS + int ssl; + char *ssl_cert; + char *ssl_key; +#endif } conf_t; G_GNUC_MALLOC conf_t *conf_load(int argc, char *argv[]); @@ -612,6 +612,10 @@ if [ "$ret" = "0" ]; then exit 1 fi; +if [ "$ssl" = "gnutls" ]; then + echo '#define WITH_GNUTLS' >> config.h +fi + echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings if detect_nameser_has_ns_types; then @@ -36,6 +36,7 @@ static char *set_eval_charset(set_t *set, char *value); static char *set_eval_password(set_t *set, char *value); static char *set_eval_bw_compat(set_t *set, char *value); static char *set_eval_utf8_nicks(set_t *set, char *value); +static char *set_eval_certfp(set_t *set, char *value); irc_t *irc_new(int fd) { @@ -135,6 +136,12 @@ irc_t *irc_new(int fd) s = set_add(&b->set, "to_char", ": ", set_eval_to_char, irc); s = set_add(&b->set, "typing_notice", "false", set_eval_bool, irc); s = set_add(&b->set, "utf8_nicks", "false", set_eval_utf8_nicks, irc); +#ifdef WITH_GNUTLS + if (global.conf->ssl) { + s = set_add(&b->set, "_certfp", NULL, set_eval_certfp, irc); + s->flags = SET_NULL_OK | SET_HIDDEN; + } +#endif irc->root = iu = irc_user_new(irc, ROOT_NICK); iu->host = g_strdup(myhost); @@ -973,6 +980,12 @@ static char *set_eval_utf8_nicks(set_t *set, char *value) return set_eval_bool(set, value); } +static char *set_eval_certfp(set_t *set, char *value) +{ + /* XXX: What should we do here? */ + return value; +} + void register_irc_plugin(const struct irc_plugin *p) { irc_plugins = g_slist_prepend(irc_plugins, (gpointer) p); @@ -26,6 +26,10 @@ #ifndef _IRC_H #define _IRC_H +//#ifdef WITH_GNUTLS +# include <gnutls/gnutls.h> +//#endif + #define IRC_MAX_LINE 512 #define IRC_MAX_ARGS 16 @@ -88,6 +92,13 @@ typedef struct irc { struct irc_user *root; struct irc_user *user; +//#ifdef WITH_GNUTLS + int ssl; + char *certfp; + + gnutls_session_t ssl_session; +//#endif + char *password; /* HACK: Used to save the user's password, but before logging in, this may contain a password we should send to identify after USER/NICK are received. */ diff --git a/lib/ssl_client.h b/lib/ssl_client.h index d2e12534..e307a6ce 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -32,6 +32,7 @@ is completed. */ #include <glib.h> +#include "irc.h" #include "proxy.h" /* Some generic error codes. Especially SSL_AGAIN is important if you @@ -71,6 +72,8 @@ G_MODULE_EXPORT void *ssl_starttls(int fd, char *hostname, gboolean verify, ssl_ G_MODULE_EXPORT int ssl_read(void *conn, char *buf, int len); G_MODULE_EXPORT int ssl_write(void *conn, const char *buf, int len); +G_MODULE_EXPORT gboolean ssl_accept(irc_t *irc); + /* Now needed by most SSL libs. See for more info: http://www.gnu.org/software/gnutls/manual/gnutls.html#index-gnutls_005frecord_005fcheck_005fpending-209 http://www.openssl.org/docs/ssl/SSL_pending.html diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index c9b35fff..1be3e1ed 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -33,6 +33,8 @@ #include "sock.h" #include "stdlib.h" #include "bitlbee.h" +#include "config.h" +#include "irc.h" int ssl_errno = 0; @@ -125,6 +127,39 @@ void *ssl_connect(char *host, int port, gboolean verify, ssl_input_function func return conn; } +gboolean ssl_setup_server() +{ + gnutls_certificate_credentials_t x509_cred; + + gnutls_certificate_allocate_credentials(&x509_cred); + gnutls_certificate_set_x509_key_file(x509_cred, global.conf->ssl_cert, global.conf->ssl_key, GNUTLS_X509_FMT_PEM); + + return TRUE; +} + +gboolean ssl_accept(irc_t *irc) +{ + int ret; + + gnutls_init(&irc->ssl_session, GNUTLS_SERVER); + gnutls_transport_set_int(irc->ssl_session, irc->fd); + + do { + ret = gnutls_handshake(irc->ssl_session); + } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret < 0) { + close(irc->fd); + gnutls_deinit(irc->ssl_session); + + fprintf(stderr, "SSL handshake failed (%s)\n", gnutls_strerror(ret)); + + return FALSE; + } + + return TRUE; +} + void *ssl_starttls(int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data) { struct scd *conn = g_new0(struct scd, 1); diff --git a/root_commands.c b/root_commands.c index dcf7a7ed..d731b0d9 100644 --- a/root_commands.c +++ b/root_commands.c @@ -1315,6 +1315,13 @@ static void cmd_nick(irc_t *irc, char **cmd) irc_rootmsg(irc, "This command is deprecated. Try: account %s set display_name", cmd[1]); } +#ifdef WITH_GNUTLS +static void cmd_certfp(irc_t *irc, char **cmd) +{ + irc_rootmsg(irc, "Show current/set new certfp"); +} +#endif + /* Maybe this should be a stand-alone command as well? */ static void bitlbee_whatsnew(irc_t *irc) { @@ -1365,6 +1372,9 @@ command_t root_commands[] = { { "set", 0, cmd_set, 0 }, { "transfer", 0, cmd_transfer, 0 }, { "yes", 0, cmd_yesno, 0 }, +#ifdef WITH_GNUTLS + { "certfp", 1, cmd_certfp, 0 }, +#endif /* Not expecting too many plugins adding root commands so just make a dumb array with some empty entried at the end. */ { NULL }, |