From a903f16c68dbcdf812d2e47e2cc3caff34d99176 Mon Sep 17 00:00:00 2001 From: TingPing Date: Mon, 2 Sep 2013 14:24:37 -0400 Subject: Implement BLOWFISh, AES, and EXTERNAL SASL mechanisms Closes #657 --- src/common/inbound.c | 103 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 16 deletions(-) (limited to 'src/common/inbound.c') diff --git a/src/common/inbound.c b/src/common/inbound.c index bdac83f7..fca5f071 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1566,8 +1566,6 @@ void inbound_cap_ack (server *serv, char *nick, char *extensions, const message_tags_data *tags_data) { - char *pass; /* buffer for SASL password */ - EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions, NULL, NULL, 0, tags_data->timestamp); @@ -1603,20 +1601,25 @@ inbound_cap_ack (server *serv, char *nick, char *extensions, if (strstr (extensions, "sasl") != NULL) { - char *user; - serv->have_sasl = TRUE; + serv->sent_saslauth = FALSE; - user = (((ircnet *)serv->network)->user) - ? (((ircnet *)serv->network)->user) : prefs.hex_irc_user_name; - - EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLAUTH, serv->server_session, user, NULL, - NULL, NULL, 0, tags_data->timestamp); +#ifdef USE_OPENSSL + if (serv->loginmethod == LOGIN_SASLEXTERNAL) + { + serv->sasl_mech = MECH_EXTERNAL; + tcp_send_len (serv, "AUTHENTICATE EXTERNAL\r\n", 23); + } + else + { + /* default to most secure, it will fallback if not supported */ + serv->sasl_mech = MECH_AES; + tcp_send_len (serv, "AUTHENTICATE DH-AES\r\n", 21); + } +#else + serv->sasl_mech = MECH_PLAIN; tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20); - - pass = encode_sasl_pass (user, serv->password); - tcp_sendf (serv, "AUTHENTICATE %s\r\n", pass); - free (pass); +#endif } } @@ -1687,9 +1690,9 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str, } /* if the SASL password is set AND auth mode is set to SASL, request SASL auth */ - if (serv->loginmethod == LOGIN_SASL - && strcmp (extension, "sasl") == 0 - && strlen (serv->password) != 0) + if (!strcmp (extension, "sasl") + && ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0) + || (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert))) { strcat (buffer, "sasl "); want_cap = 1; @@ -1710,6 +1713,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str, if (!want_sasl) { /* if we use SASL, CAP END is dealt via raw numerics */ + serv->sent_capend = TRUE; tcp_send_len (serv, "CAP END\r\n", 9); } } @@ -1717,6 +1721,7 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str, void inbound_cap_nak (server *serv, const message_tags_data *tags_data) { + serv->sent_capend = TRUE; tcp_send_len (serv, "CAP END\r\n", 9); } @@ -1727,3 +1732,69 @@ inbound_cap_list (server *serv, char *nick, char *extensions, EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions, NULL, NULL, 0, tags_data->timestamp); } + +static const char *sasl_mechanisms[] = +{ + "PLAIN", + "DH-BLOWFISH", + "DH-AES", + "EXTERNAL" +}; + +void +inbound_sasl_authenticate (server *serv, char *data) +{ + char *user, *pass = NULL; + const char *mech = sasl_mechanisms[serv->sasl_mech]; + + user = (((ircnet*)serv->network)->user) + ? (((ircnet*)serv->network)->user) : prefs.hex_irc_user_name; + + switch (serv->sasl_mech) + { + case MECH_PLAIN: + pass = encode_sasl_pass_plain (user, serv->password); + break; +#ifdef USE_OPENSSL + case MECH_BLOWFISH: + pass = encode_sasl_pass_blowfish (user, serv->password, data); + break; + case MECH_AES: + pass = encode_sasl_pass_aes (user, serv->password, data); + break; + case MECH_EXTERNAL: + pass = g_strdup ("+"); + break; +#endif + } + + if (pass == NULL) + { + /* something went wrong abort */ + serv->sent_saslauth = TRUE; /* prevent trying PLAIN */ + tcp_sendf (serv, "AUTHENTICATE *\r\n"); + return; + } + + serv->sent_saslauth = TRUE; + tcp_sendf (serv, "AUTHENTICATE %s\r\n", pass); + g_free (pass); + + + EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLAUTH, serv->server_session, user, (char*)mech, + NULL, NULL, 0, 0); +} + +int +inbound_sasl_error (server *serv) +{ + /* If server sent 904 before we sent password, + * mech not support so fallback to next mech */ + if (!serv->sent_saslauth && serv->sasl_mech != MECH_EXTERNAL && serv->sasl_mech != MECH_PLAIN) + { + serv->sasl_mech -= 1; + tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[serv->sasl_mech]); + return 1; + } + return 0; +} -- cgit 1.4.1