summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2021-06-25 10:44:35 +0200
committerSébastien Helleu <flashcode@flashtux.org>2021-06-25 11:15:22 +0200
commit0fb88527ce38e8b791a48802e160225aa38743cd (patch)
tree35597e6ce0745fb98616bbb3200cc35decfe8af3 /src
parent7a0020f067922a8616e5ac313bbc59f07683e4a8 (diff)
downloadweechat-0fb88527ce38e8b791a48802e160225aa38743cd.zip
irc: implement IRCv3.2 SASL authentication, add command /auth (closes #413)
Diffstat (limited to 'src')
-rw-r--r--src/plugins/irc/irc-command.c114
-rw-r--r--src/plugins/irc/irc-protocol.c21
-rw-r--r--src/plugins/irc/irc-server.c60
-rw-r--r--src/plugins/irc/irc-server.h6
4 files changed, 180 insertions, 21 deletions
diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c
index 71e7771e7..0df532365 100644
--- a/src/plugins/irc/irc-command.c
+++ b/src/plugins/irc/irc-command.c
@@ -793,6 +793,95 @@ IRC_COMMAND_CALLBACK(allserv)
}
/*
+ * Callback for command "/auth": authenticates with SASL.
+ */
+
+IRC_COMMAND_CALLBACK(auth)
+{
+ char str_msg_auth[512];
+ int sasl_mechanism;
+
+ IRC_BUFFER_GET_SERVER(buffer);
+ IRC_COMMAND_CHECK_SERVER("auth", 1, 1);
+
+ /* make C compiler happy */
+ (void) pointer;
+ (void) data;
+
+ if (ptr_server->sasl_temp_username)
+ {
+ free (ptr_server->sasl_temp_username);
+ ptr_server->sasl_temp_username = NULL;
+ }
+ if (ptr_server->sasl_temp_password)
+ {
+ free (ptr_server->sasl_temp_password);
+ ptr_server->sasl_temp_password = NULL;
+ }
+
+ if ((argc < 3) && !irc_server_sasl_enabled (ptr_server))
+ {
+ weechat_printf (
+ ptr_server->buffer,
+ _("%s%s: \"%s\" command can only be executed if SASL is enabled "
+ "via server options \"sasl_*\" (or you must give username and "
+ "password)"),
+ weechat_prefix ("error"), IRC_PLUGIN_NAME, "auth");
+ return WEECHAT_RC_OK;
+ }
+
+ if (weechat_hashtable_has_key (ptr_server->cap_list, "sasl"))
+ {
+ /* SASL capability already enabled, authenticate */
+ sasl_mechanism = IRC_SERVER_OPTION_INTEGER(
+ ptr_server, IRC_SERVER_OPTION_SASL_MECHANISM);
+ if ((sasl_mechanism >= 0)
+ && (sasl_mechanism < IRC_NUM_SASL_MECHANISMS))
+ {
+ if (argc > 2)
+ {
+ ptr_server->sasl_temp_username = strdup (argv[1]);
+ ptr_server->sasl_temp_password = strdup (argv_eol[2]);
+ }
+ snprintf (str_msg_auth, sizeof (str_msg_auth),
+ "AUTHENTICATE %s",
+ irc_sasl_mechanism_string[sasl_mechanism]);
+ weechat_string_toupper (str_msg_auth);
+ irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL,
+ str_msg_auth);
+ }
+ }
+ else
+ {
+ /* "sasl" capability supported by the server? */
+ if (weechat_hashtable_has_key (ptr_server->cap_ls, "sasl"))
+ {
+ /*
+ * request "sasl" capability, then the server should ask
+ * immediately to authenticate by sending a message
+ * "AUTHENTICATE +"
+ */
+ if (argc > 2)
+ {
+ ptr_server->sasl_temp_username = strdup (argv[1]);
+ ptr_server->sasl_temp_password = strdup (argv_eol[2]);
+ }
+ irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL,
+ "CAP REQ sasl");
+ }
+ else
+ {
+ weechat_printf (
+ ptr_server->buffer,
+ _("%s%s: SASL is not supported by the server"),
+ weechat_prefix ("error"), IRC_PLUGIN_NAME);
+ }
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
* Displays a ctcp action on a channel.
*/
@@ -6474,6 +6563,31 @@ irc_command_init ()
" do a whois on my nick on all servers:\n"
" /allserv /whois $nick"),
NULL, &irc_command_allserv, NULL, NULL);
+ weechat_hook_command (
+ "auth",
+ N_("authenticate with SASL"),
+ N_("[<username> <password>]"),
+ N_("username: SASL username (content is evaluated, see /help eval; "
+ "server options are evaluated with ${irc_server.xxx} and ${server} "
+ "is replaced by the server name)\n"
+ "password: SASL password or path to file with private key "
+ "(content is evaluated, see /help eval; server options are "
+ "evaluated with ${irc_server.xxx} and ${server} is replaced by the "
+ "server name)\n"
+ "\n"
+ "If username and password are not provided, the values from server "
+ "options \"sasl_username\" and \"sasl_password\" (or \"sasl_key\") "
+ "are used.\n"
+ "\n"
+ "Examples:\n"
+ " authenticate with username/password defined in the server:\n"
+ " /auth\n"
+ " authenticate as a different user:\n"
+ " /auth user2 password2\n"
+ " authenticate as a different user with mechanism "
+ "ecdsa-nist256p-challenge:\n"
+ " /auth user2 ${weechat_config_dir}/ecdsa2.pem"),
+ NULL, &irc_command_auth, NULL, NULL);
weechat_hook_command_run ("/away", &irc_command_run_away, NULL, NULL);
weechat_hook_command (
"ban",
diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c
index 9a003e13a..7cb1bfa3d 100644
--- a/src/plugins/irc/irc-protocol.c
+++ b/src/plugins/irc/irc-protocol.c
@@ -398,23 +398,19 @@ IRC_PROTOCOL_CALLBACK(account)
IRC_PROTOCOL_CALLBACK(authenticate)
{
int sasl_mechanism;
- char *sasl_username, *sasl_password, *answer, *sasl_error;
- const char *sasl_key;
+ char *sasl_username, *sasl_password, *sasl_key, *answer, *sasl_error;
IRC_PROTOCOL_MIN_ARGS(2);
if (!irc_server_sasl_enabled (server))
return WEECHAT_RC_OK;
+ irc_server_sasl_get_creds (server, &sasl_username, &sasl_password,
+ &sasl_key);
+
sasl_mechanism = IRC_SERVER_OPTION_INTEGER(
server, IRC_SERVER_OPTION_SASL_MECHANISM);
- sasl_username = irc_server_eval_expression (
- server,
- IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_USERNAME));
- sasl_password = irc_server_eval_expression (
- server,
- IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_PASSWORD));
- sasl_key = IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_KEY);
+
answer = NULL;
sasl_error = NULL;
switch (sasl_mechanism)
@@ -471,6 +467,8 @@ IRC_PROTOCOL_CALLBACK(authenticate)
free (sasl_username);
if (sasl_password)
free (sasl_password);
+ if (sasl_key)
+ free (sasl_key);
if (sasl_error)
free (sasl_error);
@@ -6621,8 +6619,9 @@ IRC_PROTOCOL_CALLBACK(sasl_end_fail)
ignored, argc, argv, argv_eol);
sasl_fail = IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_SASL_FAIL);
- if ((sasl_fail == IRC_SERVER_SASL_FAIL_RECONNECT)
- || (sasl_fail == IRC_SERVER_SASL_FAIL_DISCONNECT))
+ if (!server->is_connected
+ && ((sasl_fail == IRC_SERVER_SASL_FAIL_RECONNECT)
+ || (sasl_fail == IRC_SERVER_SASL_FAIL_DISCONNECT)))
{
irc_server_disconnect (
server, 0,
diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c
index d20c7479c..09146a92f 100644
--- a/src/plugins/irc/irc-server.c
+++ b/src/plugins/irc/irc-server.c
@@ -93,7 +93,7 @@ char *irc_server_options[IRC_SERVER_NUM_OPTIONS][2] =
{ "sasl_password", "" },
{ "sasl_key", "", },
{ "sasl_timeout", "15" },
- { "sasl_fail", "continue" },
+ { "sasl_fail", "reconnect" },
{ "autoconnect", "off" },
{ "autoreconnect", "on" },
{ "autoreconnect_delay", "10" },
@@ -509,6 +509,33 @@ irc_server_eval_fingerprint (struct t_irc_server *server)
}
/*
+ * Gets SASL credentials on server (uses temporary SASL username/password if
+ * set by the command /auth <user> <pass>).
+ */
+
+void
+irc_server_sasl_get_creds (struct t_irc_server *server,
+ char **username, char **password, char **key)
+{
+ const char *ptr_username, *ptr_password, *ptr_key;
+
+ ptr_username = (server->sasl_temp_username) ?
+ server->sasl_temp_username :
+ IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_USERNAME);
+ ptr_password = (server->sasl_temp_password) ?
+ server->sasl_temp_password :
+ IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_PASSWORD);
+ /* temporary password can also be a path to file with private key */
+ ptr_key = (server->sasl_temp_password) ?
+ server->sasl_temp_password :
+ IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_KEY);
+
+ *username = irc_server_eval_expression (server, ptr_username);
+ *password = irc_server_eval_expression (server, ptr_password);
+ *key = irc_server_eval_expression (server, ptr_key);
+}
+
+/*
* Checks if SASL is enabled on server.
*
* Returns:
@@ -520,18 +547,13 @@ int
irc_server_sasl_enabled (struct t_irc_server *server)
{
int sasl_mechanism, rc;
- char *sasl_username, *sasl_password;
- const char *sasl_key;
+ char *sasl_username, *sasl_password, *sasl_key;
+
+ irc_server_sasl_get_creds (server,
+ &sasl_username, &sasl_password, &sasl_key);
sasl_mechanism = IRC_SERVER_OPTION_INTEGER(
server, IRC_SERVER_OPTION_SASL_MECHANISM);
- sasl_username = irc_server_eval_expression (
- server,
- IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_USERNAME));
- sasl_password = irc_server_eval_expression (
- server,
- IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_PASSWORD));
- sasl_key = IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_KEY);
/*
* SASL is enabled if one of these conditions is true:
@@ -550,6 +572,8 @@ irc_server_sasl_enabled (struct t_irc_server *server)
free (sasl_username);
if (sasl_password)
free (sasl_password);
+ if (sasl_key)
+ free (sasl_key);
return rc;
}
@@ -1468,6 +1492,8 @@ irc_server_alloc (const char *name)
new_server->sasl_scram_salted_pwd = NULL;
new_server->sasl_scram_salted_pwd_size = 0;
new_server->sasl_scram_auth_message = NULL;
+ new_server->sasl_temp_username = NULL;
+ new_server->sasl_temp_password = NULL;
new_server->is_connected = 0;
new_server->ssl_connected = 0;
new_server->disconnected = 0;
@@ -1970,6 +1996,16 @@ irc_server_free_sasl_data (struct t_irc_server *server)
free (server->sasl_scram_auth_message);
server->sasl_scram_auth_message = NULL;
}
+ if (server->sasl_temp_username)
+ {
+ free (server->sasl_temp_username);
+ server->sasl_temp_username = NULL;
+ }
+ if (server->sasl_temp_password)
+ {
+ free (server->sasl_temp_password);
+ server->sasl_temp_password = NULL;
+ }
}
/*
@@ -5914,6 +5950,8 @@ irc_server_hdata_server_cb (const void *pointer, void *data,
WEECHAT_HDATA_VAR(struct t_irc_server, sasl_scram_salted_pwd, OTHER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, sasl_scram_salted_pwd_size, INTEGER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, sasl_scram_auth_message, STRING, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_server, sasl_temp_username, STRING, 0, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_irc_server, sasl_temp_password, STRING, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, is_connected, INTEGER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, ssl_connected, INTEGER, 0, NULL, NULL);
WEECHAT_HDATA_VAR(struct t_irc_server, disconnected, INTEGER, 0, NULL, NULL);
@@ -6554,6 +6592,8 @@ irc_server_print_log ()
weechat_log_printf (" sasl_scram_salted_pwd . . : (hidden)");
weechat_log_printf (" sasl_scram_salted_pwd_size: %d", ptr_server->sasl_scram_salted_pwd_size);
weechat_log_printf (" sasl_scram_auth_message . : (hidden)");
+ weechat_log_printf (" sasl_temp_username. . . . : '%s'", ptr_server->sasl_temp_username);
+ weechat_log_printf (" sasl_temp_password. . . . : (hidden)");
weechat_log_printf (" is_connected. . . . . . . : %d", ptr_server->is_connected);
weechat_log_printf (" ssl_connected . . . . . . : %d", ptr_server->ssl_connected);
weechat_log_printf (" disconnected. . . . . . . : %d", ptr_server->disconnected);
diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h
index 2dbb98ff9..7058f3d00 100644
--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ -197,6 +197,8 @@ struct t_irc_server
char *sasl_scram_salted_pwd; /* salted password for SASL SCRAM */
int sasl_scram_salted_pwd_size; /* size of salted password for SASL SCRAM*/
char *sasl_scram_auth_message; /* auth message for SASL SCRAM */
+ char *sasl_temp_username; /* temp SASL username (set by /auth cmd) */
+ char *sasl_temp_password; /* temp SASL password (set by /auth cmd) */
int is_connected; /* 1 if WeeChat is connected to server */
int ssl_connected; /* = 1 if connected with SSL */
int disconnected; /* 1 if server has been disconnected */
@@ -310,6 +312,10 @@ extern int irc_server_strncasecmp (struct t_irc_server *server,
int max);
extern char *irc_server_eval_expression (struct t_irc_server *server,
const char *string);
+extern void irc_server_sasl_get_creds (struct t_irc_server *server,
+ char **username,
+ char **password,
+ char **key);
extern int irc_server_sasl_enabled (struct t_irc_server *server);
extern char *irc_server_get_name_without_port (const char *name);
extern int irc_server_set_addresses (struct t_irc_server *server,