1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-29 22:36:38 +02:00

irc: allow ${irc_server.xxx} and ${server} in server evaluated options (closes #1144)

The server option "ssl_fingerprint" is now evaluated when it is used (during
SSL connection), instead of when it is set with command /set.
This commit is contained in:
Sébastien Helleu
2018-02-05 21:41:03 +01:00
parent e2b439d046
commit f889306c5e
25 changed files with 1149 additions and 631 deletions
+34 -92
View File
@@ -23,7 +23,6 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <limits.h>
#include <pwd.h>
@@ -998,10 +997,6 @@ irc_config_server_check_value_cb (const void *pointer, void *data,
char *error;
long number;
struct t_infolist *infolist;
#ifdef HAVE_GNUTLS
char *fingerprint_eval, **fingerprints, *str_sizes;
int i, j, rc, algo, length;
#endif /* HAVE_GNUTLS */
/* make C compiler happy */
(void) data;
@@ -1053,82 +1048,6 @@ irc_config_server_check_value_cb (const void *pointer, void *data,
return 0;
}
break;
case IRC_SERVER_OPTION_SSL_FINGERPRINT:
#ifdef HAVE_GNUTLS
if (!value || !value[0])
break;
fingerprint_eval = weechat_string_eval_expression (
value, NULL, NULL, NULL);
if (!fingerprint_eval || !fingerprint_eval[0])
{
weechat_printf (
NULL,
_("%s%s: the evaluated fingerprint must not be "
"empty"),
weechat_prefix ("error"),
IRC_PLUGIN_NAME);
if (fingerprint_eval)
free (fingerprint_eval);
return 0;
}
fingerprints = weechat_string_split (
(fingerprint_eval) ? fingerprint_eval : value,
",", 0, 0, NULL);
if (!fingerprints)
{
free (fingerprint_eval);
return 1;
}
rc = 0;
for (i = 0; fingerprints[i]; i++)
{
length = strlen (fingerprints[i]);
algo = irc_server_fingerprint_search_algo_with_size (
length * 4);
if (algo < 0)
{
rc = -1;
break;
}
for (j = 0; j < length; j++)
{
if (!isxdigit ((unsigned char)fingerprints[i][j]))
{
rc = -2;
break;
}
}
if (rc < 0)
break;
}
weechat_string_free_split (fingerprints);
free (fingerprint_eval);
switch (rc)
{
case -1: /* invalid size */
str_sizes = irc_server_fingerprint_str_sizes ();
weechat_printf (
NULL,
_("%s%s: invalid fingerprint size, the "
"number of hexadecimal digits must be "
"one of: %s"),
weechat_prefix ("error"),
IRC_PLUGIN_NAME,
(str_sizes) ? str_sizes : "?");
if (str_sizes)
free (str_sizes);
return 0;
case -2: /* invalid content */
weechat_printf (
NULL,
_("%s%s: invalid fingerprint, it must "
"contain only hexadecimal digits (0-9, "
"a-f)"),
weechat_prefix ("error"), IRC_PLUGIN_NAME);
return 0;
}
#endif /* HAVE_GNUTLS */
break;
case IRC_SERVER_OPTION_SPLIT_MSG_MAX_LENGTH:
if (!value || !value[0])
break;
@@ -1560,7 +1479,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
option_name, "string",
N_("list of hostname/port or IP/port for server (separated by "
"comma) "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1687,7 +1608,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
"fingerprints can be separated by commas; if this option "
"is set, the other checks on certificates are NOT "
"performed (option \"ssl_verify\") "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1720,7 +1643,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
config_file, section,
option_name, "string",
N_("password for server "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1784,7 +1709,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
option_name, "string",
N_("username for SASL authentication; this option is not used "
"for mechanism \"external\" "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1803,7 +1730,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
N_("password for SASL authentication; this option is not used "
"for mechanisms \"ecdsa-nist256p-challenge\" and "
"\"external\" "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1925,7 +1854,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
config_file, section,
option_name, "string",
N_("nicknames to use on server (separated by comma) "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1962,7 +1893,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
config_file, section,
option_name, "string",
N_("user name to use on server "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -1979,7 +1912,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
config_file, section,
option_name, "string",
N_("real name to use on server "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -2016,7 +1951,10 @@ irc_config_server_new_option (struct t_config_file *config_file,
"executing command and the auto-join of channels; examples: "
"\"+R\" (to set mode \"R\"), \"+R-i\" (to set mode \"R\" "
"and remove \"i\"); see /help mode for the complete mode "
"syntax (note: content is evaluated, see /help eval)"),
"syntax "
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -2036,7 +1974,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
"auto-join of channels (many commands can be separated by "
"\";\", use \"\\;\" for a semicolon, special variables "
"$nick, $channel and $server are replaced by their value) "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
@@ -2077,7 +2017,9 @@ irc_config_server_new_option (struct t_config_file *config_file,
"channels (separated by a space) (example: \"#channel1,"
"#channel2,#channel3 key1,key2\" where #channel1 and "
"#channel2 are protected by key1 and key2) "
"(note: content is evaluated, see /help eval)"),
"(note: content is evaluated, see /help eval; server "
"options are evaluated with ${irc_server.xxx} and "
"${server} is replaced by the server name)"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
+6 -6
View File
@@ -467,9 +467,9 @@ irc_ctcp_replace_variables (struct t_irc_server *server, const char *format)
* $username: user name, example:
* name
*/
username = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_USERNAME),
NULL, NULL, NULL);
username = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_USERNAME));
if (username)
{
temp = weechat_string_replace (res, "$username", username);
@@ -484,9 +484,9 @@ irc_ctcp_replace_variables (struct t_irc_server *server, const char *format)
* $realname: real name, example:
* John doe
*/
realname = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_REALNAME),
NULL, NULL, NULL);
realname = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_REALNAME));
if (realname)
{
temp = weechat_string_replace (res, "$realname", realname);
+12 -12
View File
@@ -248,12 +248,12 @@ IRC_PROTOCOL_CALLBACK(authenticate)
{
sasl_mechanism = IRC_SERVER_OPTION_INTEGER(
server, IRC_SERVER_OPTION_SASL_MECHANISM);
sasl_username = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_USERNAME),
NULL, NULL, NULL);
sasl_password = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_PASSWORD),
NULL, NULL, NULL);
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;
switch (sasl_mechanism)
@@ -2496,9 +2496,9 @@ IRC_PROTOCOL_CALLBACK(001)
WEECHAT_HOOK_SIGNAL_STRING, server->name);
/* set usermode when connected */
usermode = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_USERMODE),
NULL, NULL, NULL);
usermode = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_USERMODE));
if (usermode && usermode[0])
{
irc_server_sendf (server,
@@ -2510,9 +2510,9 @@ IRC_PROTOCOL_CALLBACK(001)
free (usermode);
/* execute command when connected */
server_command = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_COMMAND),
NULL, NULL, NULL);
server_command = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_COMMAND));
if (server_command && server_command[0])
{
/* split command on ';' which can be escaped with '\;' */
+176 -26
View File
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef _WIN32
#include <winsock.h>
@@ -337,6 +338,152 @@ irc_server_strncasecmp (struct t_irc_server *server,
return rc;
}
/*
* Evaluates a string using the server as context:
* ${irc_server.xxx} and ${server} are replaced by a server option and the
* server name.
*
* Returns the evaluated string.
*
* Note: result must be freed after use.
*/
char *
irc_server_eval_expression (struct t_irc_server *server, const char *string)
{
struct t_hashtable *pointers, *extra_vars;
char *value;
pointers = weechat_hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_POINTER,
NULL, NULL);
extra_vars = weechat_hashtable_new (
32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
if (server)
{
if (pointers)
weechat_hashtable_set (pointers, "irc_server", server);
if (extra_vars)
weechat_hashtable_set (extra_vars, "server", server->name);
}
value = weechat_string_eval_expression (string,
pointers, extra_vars, NULL);
if (pointers)
weechat_hashtable_free (pointers);
if (extra_vars)
weechat_hashtable_free (extra_vars);
return value;
}
/*
* Evaluates and returns the fingerprint.
*
* Returns the evaluated fingerprint, NULL if the fingerprint option is
* invalid.
*
* Note: result must be freed after use.
*/
char *
irc_server_eval_fingerprint (struct t_irc_server *server)
{
#ifdef HAVE_GNUTLS
const char *ptr_fingerprint;
char *fingerprint_eval, **fingerprints, *str_sizes;
int i, j, rc, algo, length;
ptr_fingerprint = IRC_SERVER_OPTION_STRING(server,
IRC_SERVER_OPTION_SSL_FINGERPRINT);
/* empty fingerprint is just ignored (considered OK) */
if (!ptr_fingerprint || !ptr_fingerprint[0])
return strdup ("");
/* evaluate fingerprint */
fingerprint_eval = irc_server_eval_expression (server, ptr_fingerprint);
if (!fingerprint_eval || !fingerprint_eval[0])
{
weechat_printf (
server->buffer,
_("%s%s: the evaluated fingerprint for server \"%s\" must not be "
"empty"),
weechat_prefix ("error"),
IRC_PLUGIN_NAME,
server->name);
if (fingerprint_eval)
free (fingerprint_eval);
return NULL;
}
/* split fingerprint */
fingerprints = weechat_string_split (fingerprint_eval, ",", 0, 0, NULL);
if (!fingerprints)
return fingerprint_eval;
rc = 0;
for (i = 0; fingerprints[i]; i++)
{
length = strlen (fingerprints[i]);
algo = irc_server_fingerprint_search_algo_with_size (length * 4);
if (algo < 0)
{
rc = -1;
break;
}
for (j = 0; j < length; j++)
{
if (!isxdigit ((unsigned char)fingerprints[i][j]))
{
rc = -2;
break;
}
}
if (rc < 0)
break;
}
weechat_string_free_split (fingerprints);
switch (rc)
{
case -1: /* invalid size */
str_sizes = irc_server_fingerprint_str_sizes ();
weechat_printf (
server->buffer,
_("%s%s: invalid fingerprint size for server \"%s\", the "
"number of hexadecimal digits must be "
"one of: %s"),
weechat_prefix ("error"),
IRC_PLUGIN_NAME,
server->name,
(str_sizes) ? str_sizes : "?");
if (str_sizes)
free (str_sizes);
free (fingerprint_eval);
return NULL;
case -2: /* invalid content */
weechat_printf (
server->buffer,
_("%s%s: invalid fingerprint for server \"%s\", it must "
"contain only hexadecimal digits (0-9, "
"a-f)"),
weechat_prefix ("error"), IRC_PLUGIN_NAME, server->name);
free (fingerprint_eval);
return NULL;
}
return fingerprint_eval;
#else
return strdup ("");
#endif /* HAVE_GNUTLS */
}
/*
* Checks if SASL is enabled on server.
*
@@ -354,12 +501,12 @@ irc_server_sasl_enabled (struct t_irc_server *server)
sasl_mechanism = IRC_SERVER_OPTION_INTEGER(
server, IRC_SERVER_OPTION_SASL_MECHANISM);
sasl_username = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_USERNAME),
NULL, NULL, NULL);
sasl_password = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_SASL_PASSWORD),
NULL, NULL, NULL);
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);
/*
@@ -423,8 +570,7 @@ irc_server_set_addresses (struct t_irc_server *server, const char *addresses)
if (addresses && addresses[0])
{
addresses_eval = weechat_string_eval_expression (addresses,
NULL, NULL, NULL);
addresses_eval = irc_server_eval_expression (server, addresses);
if (server->addresses_eval
&& (strcmp (server->addresses_eval, addresses_eval) == 0))
{
@@ -551,7 +697,7 @@ irc_server_set_nicks (struct t_irc_server *server, const char *nicks)
}
/* evaluate value */
nicks2 = weechat_string_eval_expression (nicks, NULL, NULL, NULL);
nicks2 = irc_server_eval_expression (server, nicks);
/* set new nicks */
server->nicks_array = weechat_string_split (
@@ -3503,15 +3649,15 @@ irc_server_login (struct t_irc_server *server)
const char *capabilities;
char *password, *username, *realname, *username2;
password = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_PASSWORD),
NULL, NULL, NULL);
username = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_USERNAME),
NULL, NULL, NULL);
realname = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_REALNAME),
NULL, NULL, NULL);
password = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_PASSWORD));
username = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_USERNAME));
realname = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_REALNAME));
capabilities = IRC_SERVER_OPTION_STRING(
server, IRC_SERVER_OPTION_CAPABILITIES);
@@ -4230,8 +4376,12 @@ irc_server_gnutls_callback (const void *pointer, void *data,
/* get fingerprint option in server */
ptr_fingerprint = IRC_SERVER_OPTION_STRING(server,
IRC_SERVER_OPTION_SSL_FINGERPRINT);
fingerprint_eval = weechat_string_eval_expression (ptr_fingerprint,
NULL, NULL, NULL);
fingerprint_eval = irc_server_eval_fingerprint (server);
if (!fingerprint_eval)
{
rc = -1;
goto end;
}
/* set match options */
fingerprint_match = (ptr_fingerprint && ptr_fingerprint[0]) ? 0 : 1;
@@ -4963,9 +5113,9 @@ irc_server_autojoin_create_buffers (struct t_irc_server *server)
return;
/* evaluate server option "autojoin" */
autojoin = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN),
NULL, NULL, NULL);
autojoin = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN));
/* extract channel names from autojoin option */
if (autojoin && autojoin[0])
@@ -5036,9 +5186,9 @@ irc_server_autojoin_channels (struct t_irc_server *server)
else
{
/* auto-join when connecting to server for first time */
autojoin = weechat_string_eval_expression (
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN),
NULL, NULL, NULL);
autojoin = irc_server_eval_expression (
server,
IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_AUTOJOIN));
if (!server->disable_autojoin && autojoin && autojoin[0])
irc_command_join_server (server, autojoin, 0, 0);
if (autojoin)
+2
View File
@@ -280,6 +280,8 @@ extern int irc_server_strcasecmp (struct t_irc_server *server,
extern int irc_server_strncasecmp (struct t_irc_server *server,
const char *string1, const char *string2,
int max);
extern char *irc_server_eval_expression (struct t_irc_server *server,
const char *string);
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,