From f2b97631e1209d60e77f2a918809c88bd37fdd04 Mon Sep 17 00:00:00 2001 From: Patrick Okraku Date: Wed, 11 Oct 2023 21:43:34 +0200 Subject: [PATCH 1/4] Added support for SCRAM-SHA-1, SCRAM-SHA-256 and SCRAM-SHA-512 --- docs/help/in/network.in | 4 +- src/irc/core/irc-core.c | 4 + src/irc/core/irc-servers-setup.c | 24 ++- src/irc/core/irc-servers.h | 2 + src/irc/core/meson.build | 2 + src/irc/core/sasl.c | 72 ++++++++ src/irc/core/sasl.h | 3 + src/irc/core/scram.c | 303 +++++++++++++++++++++++++++++++ src/irc/core/scram.h | 27 +++ 9 files changed, 435 insertions(+), 6 deletions(-) create mode 100644 src/irc/core/scram.c create mode 100644 src/irc/core/scram.h diff --git a/docs/help/in/network.in b/docs/help/in/network.in index 788c1c65..16ff9f47 100644 --- a/docs/help/in/network.in +++ b/docs/help/in/network.in @@ -36,8 +36,8 @@ -cmdmax: Specifies the maximum number of commands to perform before starting the internal flood protection. -sasl_mechanism Specifies the mechanism to use for the SASL authentication. - At the moment irssi only supports the 'plain' and the - 'external' mechanisms. + Irssi supports: PLAIN, EXTERNAL, SCRAM-SHA-1, SCRAM-SHA-256 + and SCRAM-SHA-512 Use '' to disable the authentication. -sasl_username Specifies the username to use during the SASL authentication. -sasl_password Specifies the password to use during the SASL authentication. diff --git a/src/irc/core/irc-core.c b/src/irc/core/irc-core.c index 725ae28a..136bff85 100644 --- a/src/irc/core/irc-core.c +++ b/src/irc/core/irc-core.c @@ -77,6 +77,10 @@ static void destroy_server_connect(SERVER_CONNECT_REC *conn) g_free_not_null(ircconn->alternate_nick); g_free_not_null(ircconn->sasl_username); g_free_not_null(ircconn->sasl_password); + + if (ircconn->scram_session != NULL) { + scram_session_free(ircconn->scram_session); + } } void irc_core_init(void) diff --git a/src/irc/core/irc-servers-setup.c b/src/irc/core/irc-servers-setup.c index c1603a48..a575ee34 100644 --- a/src/irc/core/irc-servers-setup.c +++ b/src/irc/core/irc-servers-setup.c @@ -128,11 +128,27 @@ static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn, conn->sasl_password = g_strdup(ircnet->sasl_password); } else g_warning("The fields sasl_username and sasl_password are either missing or empty"); - } - else if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "external")) { + } else if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "SCRAM-SHA-1") || + !g_ascii_strcasecmp(ircnet->sasl_mechanism, "SCRAM-SHA-256") || + !g_ascii_strcasecmp(ircnet->sasl_mechanism, "SCRAM-SHA-512")) { + /* The SCRAM-SHA-* methods need both the username and the password */ + if (ircnet->sasl_username != NULL && *ircnet->sasl_username && + ircnet->sasl_password != NULL && *ircnet->sasl_password) { + if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "SCRAM-SHA-1")) + conn->sasl_mechanism = SASL_MECHANISM_SCRAM_SHA_1; + if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "SCRAM-SHA-256")) + conn->sasl_mechanism = SASL_MECHANISM_SCRAM_SHA_256; + if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "SCRAM-SHA-512")) + conn->sasl_mechanism = SASL_MECHANISM_SCRAM_SHA_512; + + conn->sasl_username = g_strdup(ircnet->sasl_username); + conn->sasl_password = g_strdup(ircnet->sasl_password); + } else + g_warning("The fields sasl_username and sasl_password are either " + "missing or empty"); + } else if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "external")) { conn->sasl_mechanism = SASL_MECHANISM_EXTERNAL; - } - else + } else g_warning("Unsupported SASL mechanism \"%s\" selected", ircnet->sasl_mechanism); } } diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index 6e78c4da..01605b7d 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * 63 is the maximum hostname length defined by the protocol. 10 is a common @@ -54,6 +55,7 @@ struct _IRC_SERVER_CONNECT_REC { int sasl_mechanism; char *sasl_username; char *sasl_password; + SCRAM_SESSION_REC *scram_session; int max_cmds_at_once; int cmd_queue_speed; diff --git a/src/irc/core/meson.build b/src/irc/core/meson.build index 81559f3e..a63ff214 100644 --- a/src/irc/core/meson.build +++ b/src/irc/core/meson.build @@ -28,6 +28,7 @@ libirc_core_a = static_library('irc_core', 'modes.c', 'netsplit.c', 'sasl.c', + 'scram.c', 'servers-idle.c', 'servers-redirect.c', ), @@ -70,6 +71,7 @@ install_headers( 'module.h', 'netsplit.h', 'sasl.h', + 'scram.h', 'servers-idle.h', 'servers-redirect.h', ), diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 9bc40ff2..e9689b12 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -80,6 +80,18 @@ static void sasl_start(IRC_SERVER_REC *server, const char *data, const char *fro case SASL_MECHANISM_EXTERNAL: irc_send_cmd_now(server, "AUTHENTICATE EXTERNAL"); break; + + case SASL_MECHANISM_SCRAM_SHA_1: + irc_send_cmd_now(server, "AUTHENTICATE SCRAM-SHA-1"); + break; + + case SASL_MECHANISM_SCRAM_SHA_256: + irc_send_cmd_now(server, "AUTHENTICATE SCRAM-SHA-256"); + break; + + case SASL_MECHANISM_SCRAM_SHA_512: + irc_send_cmd_now(server, "AUTHENTICATE SCRAM-SHA-512"); + break; } server->sasl_timeout = g_timeout_add(SASL_TIMEOUT, (GSourceFunc) sasl_timeout, server); } @@ -223,6 +235,54 @@ void sasl_send_response(IRC_SERVER_REC *server, GString *response) g_free(enc); } +/* + * Sends AUTHENTICATE messages to log in via SCRAM. + */ +static void scram_authenticate(IRC_SERVER_REC *server, const char *data, const char *digest) +{ + char *output; + int ret; + size_t output_len; + IRC_SERVER_CONNECT_REC *conn = server->connrec; + + if (conn->scram_session == NULL) { + conn->scram_session = + scram_session_create(digest, conn->sasl_username, conn->sasl_password); + + if (conn->scram_session == NULL) { + g_error("Could not create SCRAM session with digest %s", digest); + irc_send_cmd_now(server, "AUTHENTICATE *"); + return; + } + } + + ret = scram_process(conn->scram_session, data, &output, &output_len); + + if (ret == SCRAM_IN_PROGRESS) { + // Authentication is still in progress + GString *resp = g_string_new(output); + sasl_send_response(server, resp); + g_string_free(resp, TRUE); + g_free(output); + } else if (ret == SCRAM_SUCCESS) { + // Authentication succeeded + irc_send_cmd_now(server, "AUTHENTICATE +"); + scram_session_free(conn->scram_session); + conn->scram_session = NULL; + } else if (ret == SCRAM_ERROR) { + // Authentication failed + irc_send_cmd_now(server, "AUTHENTICATE *"); + + if (conn->scram_session->error != NULL) { + g_warning("SASL SCRAM authentication failed: %s", + conn->scram_session->error); + } + + scram_session_free(conn->scram_session); + conn->scram_session = NULL; + } +} + /* * Called when the incoming SASL request is completely received. */ @@ -258,6 +318,18 @@ static void sasl_step_complete(IRC_SERVER_REC *server, GString *data) /* Empty response */ sasl_send_response(server, NULL); break; + + case SASL_MECHANISM_SCRAM_SHA_1: + scram_authenticate(server, data->str, "SHA1"); + break; + + case SASL_MECHANISM_SCRAM_SHA_256: + scram_authenticate(server, data->str, "SHA256"); + break; + + case SASL_MECHANISM_SCRAM_SHA_512: + scram_authenticate(server, data->str, "SHA512"); + break; } } diff --git a/src/irc/core/sasl.h b/src/irc/core/sasl.h index 04d0cd9d..67c8567b 100644 --- a/src/irc/core/sasl.h +++ b/src/irc/core/sasl.h @@ -25,6 +25,9 @@ enum { SASL_MECHANISM_NONE = 0, SASL_MECHANISM_PLAIN, SASL_MECHANISM_EXTERNAL, + SASL_MECHANISM_SCRAM_SHA_1, + SASL_MECHANISM_SCRAM_SHA_256, + SASL_MECHANISM_SCRAM_SHA_512, SASL_MECHANISM_MAX }; diff --git a/src/irc/core/scram.c b/src/irc/core/scram.c new file mode 100644 index 00000000..42812ccc --- /dev/null +++ b/src/irc/core/scram.c @@ -0,0 +1,303 @@ +/* + scram.c : irssi + + Copyright (C) 2023 Patrick Okraku + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "module.h" +#include +#include +#include + +#define NONCE_LENGTH 18 +#define CLIENT_KEY "Client Key" +#define SERVER_KEY "Server Key" + +// EVP_MD_CTX_create() and EVP_MD_CTX_destroy() were renamed in OpenSSL 1.1.0 +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) +#define EVP_MD_CTX_new(ctx) EVP_MD_CTX_create(ctx) +#define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy(ctx) +#endif + +SCRAM_SESSION_REC *scram_session_create(const char *digest, const char *username, + const char *password) +{ + SCRAM_SESSION_REC *session; + const EVP_MD *md; +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) + OpenSSL_add_all_algorithms(); +#endif + md = EVP_get_digestbyname(digest); + + if (md == NULL) { + // Unknown message digest + return NULL; + } + + session = g_new0(SCRAM_SESSION_REC, 1); + session->digest = md; + session->digest_size = EVP_MD_size(md); + session->username = g_strdup(username); + session->password = g_strdup(password); + return session; +} + +void scram_session_free(SCRAM_SESSION_REC *session) +{ + if (session == NULL) { + return; + } + + g_free(session->username); + g_free(session->password); + g_free(session->client_nonce_b64); + g_free(session->client_first_message_bare); + g_free(session->salted_password); + g_free(session->auth_message); + g_free(session->error); + + g_free(session); +} + +static int create_nonce(void *buffer, size_t length) +{ + return RAND_bytes(buffer, length); +} + +static int create_SHA(SCRAM_SESSION_REC *session, const unsigned char *input, size_t input_len, + unsigned char *output, unsigned int *output_len) +{ + EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); + + if (!EVP_DigestInit_ex(md_ctx, session->digest, NULL)) { + session->error = g_strdup("Message digest initialization failed"); + EVP_MD_CTX_free(md_ctx); + return SCRAM_ERROR; + } + + if (!EVP_DigestUpdate(md_ctx, input, input_len)) { + session->error = g_strdup("Message digest update failed"); + EVP_MD_CTX_free(md_ctx); + return SCRAM_ERROR; + } + + if (!EVP_DigestFinal_ex(md_ctx, output, output_len)) { + session->error = g_strdup("Message digest finalization failed"); + EVP_MD_CTX_free(md_ctx); + return SCRAM_ERROR; + } + + EVP_MD_CTX_free(md_ctx); + return SCRAM_IN_PROGRESS; +} + +static scram_status process_client_first(SCRAM_SESSION_REC *session, char **output, + size_t *output_len) +{ + char nonce[NONCE_LENGTH]; + + if (!create_nonce(nonce, NONCE_LENGTH)) { + session->error = g_strdup("Could not create client nonce"); + return SCRAM_ERROR; + } + + session->client_nonce_b64 = g_base64_encode((guchar *) nonce, NONCE_LENGTH); + *output = g_strdup_printf("n,,n=%s,r=%s", session->username, session->client_nonce_b64); + *output_len = strlen(*output); + session->client_first_message_bare = g_strdup(*output + 3); + session->step++; + return SCRAM_IN_PROGRESS; +} + +static scram_status process_server_first(SCRAM_SESSION_REC *session, const char *data, + char **output, size_t *output_len) +{ + char **params, *client_final_message_without_proof, *salt, *server_nonce_b64, + *client_proof_b64; + unsigned char *client_key, stored_key[EVP_MAX_MD_SIZE], *client_signature, *client_proof; + unsigned int i, param_count, iteration_count, client_key_len, stored_key_len; + gsize salt_len = 0; + size_t client_nonce_len; + + params = g_strsplit(data, ",", -1); + param_count = g_strv_length(params); + + if (param_count < 3) { + session->error = g_strdup_printf("Invalid server-first-message: %s", data); + g_strfreev(params); + return SCRAM_ERROR; + } + + server_nonce_b64 = NULL; + salt = NULL; + iteration_count = 0; + + for (i = 0; i < param_count; i++) { + if (!strncmp(params[i], "r=", 2)) { + g_free(server_nonce_b64); + server_nonce_b64 = g_strdup(params[i] + 2); + } else if (!strncmp(params[i], "s=", 2)) { + g_free(salt); + salt = g_strdup(params[i] + 2); + } else if (!strncmp(params[i], "i=", 2)) { + iteration_count = strtoul(params[i] + 2, NULL, 10); + } + } + + g_strfreev(params); + + if (server_nonce_b64 == NULL || *server_nonce_b64 == '\0' || salt == NULL || + *salt == '\0' || iteration_count == 0) { + session->error = g_strdup_printf("Invalid server-first-message: %s", data); + g_free(server_nonce_b64); + g_free(salt); + return SCRAM_ERROR; + } + + client_nonce_len = strlen(session->client_nonce_b64); + + // The server can append his nonce to the client's nonce + if (strlen(server_nonce_b64) < client_nonce_len || + strncmp(server_nonce_b64, session->client_nonce_b64, client_nonce_len)) { + session->error = g_strdup_printf("Invalid server nonce: %s", server_nonce_b64); + return SCRAM_ERROR; + } + + g_base64_decode_inplace((gchar *) salt, &salt_len); + + // SaltedPassword := Hi(Normalize(password), salt, i) + session->salted_password = g_malloc(session->digest_size); + + PKCS5_PBKDF2_HMAC(session->password, strlen(session->password), (unsigned char *) salt, + salt_len, iteration_count, session->digest, session->digest_size, + session->salted_password); + + // AuthMessage := client-first-message-bare + "," + + // server-first-message + "," + + // client-final-message-without-proof + client_final_message_without_proof = g_strdup_printf("c=biws,r=%s", server_nonce_b64); + + session->auth_message = g_strdup_printf("%s,%s,%s", session->client_first_message_bare, + data, client_final_message_without_proof); + + // ClientKey := HMAC(SaltedPassword, "Client Key") + client_key = g_malloc0(session->digest_size); + + HMAC(session->digest, session->salted_password, session->digest_size, + (unsigned char *) CLIENT_KEY, strlen(CLIENT_KEY), client_key, &client_key_len); + + // StoredKey := H(ClientKey) + if (!create_SHA(session, client_key, session->digest_size, stored_key, &stored_key_len)) { + g_free(client_final_message_without_proof); + g_free(server_nonce_b64); + g_free(salt); + g_free(client_key); + return SCRAM_ERROR; + } + + // ClientSignature := HMAC(StoredKey, AuthMessage) + client_signature = g_malloc0(session->digest_size); + HMAC(session->digest, stored_key, stored_key_len, (unsigned char *) session->auth_message, + strlen((char *) session->auth_message), client_signature, NULL); + + // ClientProof := ClientKey XOR ClientSignature + client_proof = g_malloc0(client_key_len); + + for (i = 0; i < client_key_len; i++) { + client_proof[i] = client_key[i] ^ client_signature[i]; + } + + client_proof_b64 = g_base64_encode((guchar *) client_proof, client_key_len); + + *output = g_strdup_printf("%s,p=%s", client_final_message_without_proof, client_proof_b64); + *output_len = strlen(*output); + + g_free(server_nonce_b64); + g_free(salt); + g_free(client_final_message_without_proof); + g_free(client_key); + g_free(client_signature); + g_free(client_proof); + g_free(client_proof_b64); + + session->step++; + return SCRAM_IN_PROGRESS; +} + +static scram_status process_server_final(SCRAM_SESSION_REC *session, const char *data) +{ + char *verifier; + unsigned char *server_key, *server_signature; + unsigned int server_key_len = 0, server_signature_len = 0; + gsize verifier_len = 0; + + if (strlen(data) < 3 || (data[0] != 'v' && data[1] != '=')) { + return SCRAM_ERROR; + } + + verifier = g_strdup(data + 2); + g_base64_decode_inplace(verifier, &verifier_len); + + // ServerKey := HMAC(SaltedPassword, "Server Key") + server_key = g_malloc0(session->digest_size); + HMAC(session->digest, session->salted_password, session->digest_size, + (unsigned char *) SERVER_KEY, strlen(SERVER_KEY), server_key, &server_key_len); + + // ServerSignature := HMAC(ServerKey, AuthMessage) + server_signature = g_malloc0(session->digest_size); + HMAC(session->digest, server_key, session->digest_size, + (unsigned char *) session->auth_message, strlen((char *) session->auth_message), + server_signature, &server_signature_len); + + if (verifier_len == server_signature_len && + memcmp(verifier, server_signature, verifier_len) == 0) { + g_free(verifier); + g_free(server_key); + g_free(server_signature); + return SCRAM_SUCCESS; + } else { + g_free(verifier); + g_free(server_key); + g_free(server_signature); + return SCRAM_ERROR; + } +} + +scram_status scram_process(SCRAM_SESSION_REC *session, const char *input, char **output, + size_t *output_len) +{ + scram_status status; + + switch (session->step) { + case 0: + status = process_client_first(session, output, output_len); + break; + case 1: + status = process_server_first(session, input, output, output_len); + break; + case 2: + status = process_server_final(session, input); + break; + default: + *output = NULL; + *output_len = 0; + status = SCRAM_ERROR; + break; + } + + return status; +} \ No newline at end of file diff --git a/src/irc/core/scram.h b/src/irc/core/scram.h new file mode 100644 index 00000000..ee605142 --- /dev/null +++ b/src/irc/core/scram.h @@ -0,0 +1,27 @@ +#ifndef IRSSI_IRC_CORE_SCRAM_H +#define IRSSI_IRC_CORE_SCRAM_H + +#include + +typedef struct { + const EVP_MD *digest; + size_t digest_size; + char *username; + char *password; + char *client_nonce_b64; + char *client_first_message_bare; + unsigned char *salted_password; + char *auth_message; + char *error; + int step; +} SCRAM_SESSION_REC; + +typedef enum { SCRAM_ERROR = 0, SCRAM_IN_PROGRESS, SCRAM_SUCCESS } scram_status; + +SCRAM_SESSION_REC *scram_session_create(const char *digset, const char *username, + const char *password); +void scram_session_free(SCRAM_SESSION_REC *session); +scram_status scram_process(SCRAM_SESSION_REC *session, const char *input, char **output, + size_t *output_len); + +#endif \ No newline at end of file From 98b391f62e986e743589b15af866fcbd6072964b Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Mon, 1 Apr 2024 16:33:36 +0200 Subject: [PATCH 2/4] minor cleanup --- src/irc/core/sasl.c | 6 +++--- src/irc/core/scram.c | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index e9689b12..1695fc4c 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -250,7 +250,7 @@ static void scram_authenticate(IRC_SERVER_REC *server, const char *data, const c scram_session_create(digest, conn->sasl_username, conn->sasl_password); if (conn->scram_session == NULL) { - g_error("Could not create SCRAM session with digest %s", digest); + g_critical("Could not create SCRAM session with digest %s", digest); irc_send_cmd_now(server, "AUTHENTICATE *"); return; } @@ -260,13 +260,13 @@ static void scram_authenticate(IRC_SERVER_REC *server, const char *data, const c if (ret == SCRAM_IN_PROGRESS) { // Authentication is still in progress - GString *resp = g_string_new(output); + GString *resp = g_string_new_len(output, output_len); sasl_send_response(server, resp); g_string_free(resp, TRUE); g_free(output); } else if (ret == SCRAM_SUCCESS) { // Authentication succeeded - irc_send_cmd_now(server, "AUTHENTICATE +"); + sasl_send_response(server, NULL); scram_session_free(conn->scram_session); conn->scram_session = NULL; } else if (ret == SCRAM_ERROR) { diff --git a/src/irc/core/scram.c b/src/irc/core/scram.c index 42812ccc..4c950140 100644 --- a/src/irc/core/scram.c +++ b/src/irc/core/scram.c @@ -137,7 +137,8 @@ static scram_status process_server_first(SCRAM_SESSION_REC *session, const char param_count = g_strv_length(params); if (param_count < 3) { - session->error = g_strdup_printf("Invalid server-first-message: %s", data); + /* Invalid server-first-message */ + session->error = g_strdup_printf("%s", data); g_strfreev(params); return SCRAM_ERROR; } @@ -300,4 +301,4 @@ scram_status scram_process(SCRAM_SESSION_REC *session, const char *input, char * } return status; -} \ No newline at end of file +} From 08bb648850ca73695d5bf39c53dbd7e9846a0a94 Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Mon, 1 Apr 2024 16:33:57 +0200 Subject: [PATCH 3/4] proper sasl mechanism variable initialisation --- src/irc/core/irc-servers-setup.c | 7 +++++-- src/irc/core/irc-servers.c | 1 + src/irc/core/sasl.c | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/irc/core/irc-servers-setup.c b/src/irc/core/irc-servers-setup.c index a575ee34..2d94a48b 100644 --- a/src/irc/core/irc-servers-setup.c +++ b/src/irc/core/irc-servers-setup.c @@ -148,8 +148,11 @@ static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn, "missing or empty"); } else if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "external")) { conn->sasl_mechanism = SASL_MECHANISM_EXTERNAL; - } else - g_warning("Unsupported SASL mechanism \"%s\" selected", ircnet->sasl_mechanism); + } else { + g_warning("Unsupported SASL mechanism \"%s\" selected", + ircnet->sasl_mechanism); + conn->sasl_mechanism = SASL_MECHANISM_MAX; + } } } diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index 29f63c21..e3fe3143 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -475,6 +475,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn) server->send_message = send_message; server->query_find_func = (QUERY_REC * (*) (SERVER_REC *, const char *) ) irc_query_find; server->nick_comp_func = irc_nickcmp_rfc1459; + server->sasl_success = FALSE; server_connect_init((SERVER_REC *) server); return (SERVER_REC *) server; diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 1695fc4c..89ca4a9e 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -92,6 +92,12 @@ static void sasl_start(IRC_SERVER_REC *server, const char *data, const char *fro case SASL_MECHANISM_SCRAM_SHA_512: irc_send_cmd_now(server, "AUTHENTICATE SCRAM-SHA-512"); break; + + case SASL_MECHANISM_MAX: + signal_emit("server sasl failure", 2, server, + "Irssi: Unsupported SASL mechanism"); + irc_cap_finish_negotiation(server); + return; } server->sasl_timeout = g_timeout_add(SASL_TIMEOUT, (GSourceFunc) sasl_timeout, server); } From 2f2fa029f92706301ffebf04ce90e428d6c835bd Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Mon, 1 Apr 2024 16:37:35 +0200 Subject: [PATCH 4/4] up abi --- src/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index 59566dc8..9f6c54a2 100644 --- a/src/common.h +++ b/src/common.h @@ -6,7 +6,7 @@ #define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */ #define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */ -#define IRSSI_ABI_VERSION 52 +#define IRSSI_ABI_VERSION 53 #define DEFAULT_SERVER_ADD_PORT 6667 #define DEFAULT_SERVER_ADD_TLS_PORT 6697