diff options
Diffstat (limited to 'src/common/inbound.c')
-rw-r--r-- | src/common/inbound.c | 117 |
1 files changed, 113 insertions, 4 deletions
diff --git a/src/common/inbound.c b/src/common/inbound.c index 78a126f7..9b38f7c7 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1648,7 +1648,10 @@ inbound_identified (server *serv) /* 'MODE +e MYSELF' on freenode */ static const char *sasl_mechanisms[] = { "PLAIN", - "EXTERNAL" + "EXTERNAL", + "SCRAM-SHA-1", + "SCRAM-SHA-256", + "SCRAM-SHA-512" }; static void @@ -1689,6 +1692,12 @@ inbound_toggle_caps (server *serv, const char *extensions_str, gboolean enable) #ifdef USE_OPENSSL if (serv->loginmethod == LOGIN_SASLEXTERNAL) serv->sasl_mech = MECH_EXTERNAL; + else if (serv->loginmethod == LOGIN_SASL_SCRAM_SHA_1) + serv->sasl_mech = MECH_SCRAM_SHA_1; + else if (serv->loginmethod == LOGIN_SASL_SCRAM_SHA_256) + serv->sasl_mech = MECH_SCRAM_SHA_256; + else if (serv->loginmethod == LOGIN_SASL_SCRAM_SHA_512) + serv->sasl_mech = MECH_SCRAM_SHA_512; #endif /* Mechanism either defaulted to PLAIN or server gave us list */ tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[serv->sasl_mech]); @@ -1766,6 +1775,30 @@ get_supported_mech (server *serv, const char *list) break; } } + else if (serv->loginmethod == LOGIN_SASL_SCRAM_SHA_1) + { + if (!strcmp(mechs[i], "SCRAM-SHA-1")) + { + ret = MECH_SCRAM_SHA_1; + break; + } + } + else if (serv->loginmethod == LOGIN_SASL_SCRAM_SHA_256) + { + if (!strcmp(mechs[i], "SCRAM-SHA-256")) + { + ret = MECH_SCRAM_SHA_256; + break; + } + } + else if (serv->loginmethod == LOGIN_SASL_SCRAM_SHA_512) + { + if (!strcmp(mechs[i], "SCRAM-SHA-512")) + { + ret = MECH_SCRAM_SHA_512; + break; + } + } else #endif if (!strcmp (mechs[i], "PLAIN")) @@ -1821,7 +1854,11 @@ 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 (!g_strcmp0 (extension, "sasl") && - ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0) + (((serv->loginmethod == LOGIN_SASL + || serv->loginmethod == LOGIN_SASL_SCRAM_SHA_1 + || serv->loginmethod == LOGIN_SASL_SCRAM_SHA_256 + || serv->loginmethod == LOGIN_SASL_SCRAM_SHA_512) + && strlen (serv->password) != 0) || serv->loginmethod == LOGIN_SASLEXTERNAL)) { if (value) @@ -1902,7 +1939,7 @@ inbound_cap_list (server *serv, char *nick, char *extensions, } static void -plain_authenticate(server *serv, char *user, char *password) +plain_authenticate (server *serv, char *user, char *password) { char *pass = encode_sasl_pass_plain (user, password); @@ -1933,11 +1970,71 @@ plain_authenticate(server *serv, char *user, char *password) tcp_sendf (serv, "AUTHENTICATE +\r\n"); } +#ifdef USE_OPENSSL +/* + * Sends AUTHENTICATE messages to log in via SCRAM. + */ +static void +scram_authenticate (server *serv, const char *data, const char *digest, + const char *user, const char *password) +{ + char *encoded, *decoded, *output; + scram_status status; + size_t output_len; + gsize decoded_len; + + if (serv->scram_session == NULL) + { + serv->scram_session = scram_create_session (digest, user, password); + + if (serv->scram_session == NULL) + { + PrintTextf (serv->server_session, _("Could not create SCRAM session with digest %s"), digest); + g_warning ("Could not create SCRAM session with digest %s", digest); + tcp_sendf (serv, "AUTHENTICATE *\r\n"); + return; + } + } + + decoded = g_base64_decode (data, &decoded_len); + status = scram_process (serv->scram_session, decoded, &output, &output_len); + g_free (decoded); + + if (status == SCRAM_IN_PROGRESS) + { + // Authentication is still in progress + encoded = g_base64_encode ((guchar *) output, output_len); + tcp_sendf (serv, "AUTHENTICATE %s\r\n", encoded); + g_free (encoded); + g_free (output); + } + else if (status == SCRAM_SUCCESS) + { + // Authentication succeeded + tcp_sendf (serv, "AUTHENTICATE +\r\n"); + g_clear_pointer (&serv->scram_session, scram_free_session); + } + else if (status == SCRAM_ERROR) + { + // Authentication failed + tcp_sendf (serv, "AUTHENTICATE *\r\n"); + + if (serv->scram_session->error != NULL) + { + PrintTextf (serv->server_session, _("SASL SCRAM authentication failed: %s"), serv->scram_session->error); + g_info ("SASL SCRAM authentication failed: %s", serv->scram_session->error); + } + + g_clear_pointer (&serv->scram_session, scram_free_session); + } +} +#endif + void inbound_sasl_authenticate (server *serv, char *data) { ircnet *net = (ircnet*)serv->network; - char *user, *pass = NULL; + char *user; const char *mech = sasl_mechanisms[serv->sasl_mech]; /* Got a list of supported mechanisms from outdated inspircd @@ -1959,6 +2056,15 @@ inbound_sasl_authenticate (server *serv, char *data) case MECH_EXTERNAL: tcp_sendf (serv, "AUTHENTICATE +\r\n"); break; + case MECH_SCRAM_SHA_1: + scram_authenticate(serv, data, "SHA1", user, serv->password); + return; + case MECH_SCRAM_SHA_256: + scram_authenticate(serv, data, "SHA256", user, serv->password); + return; + case MECH_SCRAM_SHA_512: + scram_authenticate(serv, data, "SHA512", user, serv->password); + return; #endif } @@ -1969,6 +2075,9 @@ inbound_sasl_authenticate (server *serv, char *data) void inbound_sasl_error (server *serv) { +#ifdef USE_OPENSSL + g_clear_pointer (&serv->scram_session, scram_free_session); +#endif /* Just abort, not much we can do */ tcp_sendf (serv, "AUTHENTICATE *\r\n"); } |