aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarius Halden <marius.h@lden.org>2015-11-08 08:58:37 +0100
committerMarius Halden <marius.h@lden.org>2016-05-07 14:26:17 +0200
commitf6119b76d73b9cdff3cbfd902675a36bcacbcd48 (patch)
tree6c6f1581fd53a5b3094bfdc46838c2c893760a20
parentf0ff36f558329d096526004d4d912973bafd3904 (diff)
Start adding ssl support
-rw-r--r--conf.c39
-rw-r--r--conf.h5
-rwxr-xr-xconfigure4
-rw-r--r--irc.c13
-rw-r--r--irc.h11
-rw-r--r--lib/ssl_client.h3
-rw-r--r--lib/ssl_gnutls.c35
-rw-r--r--root_commands.c10
8 files changed, 120 insertions, 0 deletions
diff --git a/conf.c b/conf.c
index 8c2439e7..c0ecd889 100644
--- a/conf.c
+++ b/conf.c
@@ -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);
diff --git a/conf.h b/conf.h
index cd600775..e504f637 100644
--- a/conf.h
+++ b/conf.h
@@ -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[]);
diff --git a/configure b/configure
index 9cc81794..d2979130 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/irc.c b/irc.c
index 563f230f..3703f08f 100644
--- a/irc.c
+++ b/irc.c
@@ -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);
diff --git a/irc.h b/irc.h
index 5ce7b07d..26e0c0a3 100644
--- a/irc.h
+++ b/irc.h
@@ -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 },