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

irc: fix crash in parsing of IRC channel modes (issue #1296, closes #1297)

Regression was introduced by commit b38b2abe3b.
This commit is contained in:
Sébastien Helleu
2019-01-31 21:13:58 +01:00
parent b38b2abe3b
commit 6e09499163
4 changed files with 134 additions and 141 deletions
+125 -135
View File
@@ -320,11 +320,13 @@ int
irc_mode_channel_set (struct t_irc_server *server,
struct t_irc_channel *channel,
const char *host,
const char *modes)
const char *modes,
const char *modes_arguments)
{
char *pos_args, *str_modes, set_flag, **argv, *pos, *ptr_arg, chanmode_type;
const char *pos, *ptr_arg;
char set_flag, **argv, chanmode_type;
int argc, current_arg, update_channel_modes, channel_modes_updated;
int smart_filter;
int smart_filter, end_modes;
struct t_irc_nick *ptr_nick;
struct t_irc_modelist *ptr_modelist;
struct t_irc_modelist_item *ptr_item;
@@ -335,23 +337,8 @@ irc_mode_channel_set (struct t_irc_server *server,
channel_modes_updated = 0;
argc = 0;
argv = NULL;
pos_args = strchr (modes, ' ');
if (pos_args)
{
str_modes = weechat_strndup (modes, pos_args - modes);
if (!str_modes)
return 0;
pos_args++;
while (pos_args[0] == ' ')
pos_args++;
argv = weechat_string_split (pos_args, " ", 0, 0, &argc);
}
else
{
str_modes = strdup (modes);
if (!str_modes)
return 0;
}
if (modes_arguments)
argv = weechat_string_split (modes_arguments, " ", 0, 0, &argc);
current_arg = 0;
@@ -359,119 +346,122 @@ irc_mode_channel_set (struct t_irc_server *server,
&& weechat_config_string (irc_config_look_smart_filter_mode)
&& weechat_config_string (irc_config_look_smart_filter_mode)[0]) ? 1 : 0;
if (str_modes && str_modes[0])
end_modes = 0;
set_flag = '+';
pos = modes;
while (pos[0])
{
set_flag = '+';
pos = str_modes;
while (pos && pos[0])
switch (pos[0])
{
switch (pos[0])
{
case ':':
case ' ':
break;
case '+':
set_flag = '+';
break;
case '-':
set_flag = '-';
break;
default:
update_channel_modes = 1;
chanmode_type = irc_mode_get_chanmode_type (server, pos[0]);
ptr_arg = NULL;
switch (chanmode_type)
{
case 'A': /* always argument */
update_channel_modes = 0;
ptr_arg = (current_arg < argc) ?
argv[current_arg] : NULL;
break;
case 'B': /* always argument */
ptr_arg = (current_arg < argc) ?
argv[current_arg] : NULL;
break;
case 'C': /* argument if set */
ptr_arg = ((set_flag == '+') && (current_arg < argc)) ?
argv[current_arg] : NULL;
break;
case 'D': /* no argument */
break;
}
if (ptr_arg)
current_arg++;
if (smart_filter
&& !irc_mode_smart_filtered (server, pos[0]))
{
smart_filter = 0;
}
if (pos[0] == 'k')
{
/* channel key */
if (set_flag == '-')
{
if (channel->key)
{
free (channel->key);
channel->key = NULL;
}
}
else if ((set_flag == '+')
&& ptr_arg && (strcmp (ptr_arg, "*") != 0))
{
/* replace key for +k, but ignore "*" as new key */
if (channel->key)
free (channel->key);
channel->key = strdup (ptr_arg);
}
}
else if (pos[0] == 'l')
{
/* channel limit */
if (set_flag == '-')
channel->limit = 0;
if ((set_flag == '+') && ptr_arg)
{
channel->limit = atoi (ptr_arg);
}
}
else if ((chanmode_type != 'A')
&& (irc_server_get_prefix_mode_index (server,
pos[0]) >= 0))
{
/* mode for nick */
case ':':
break;
case ' ':
end_modes = 1;
break;
case '+':
set_flag = '+';
break;
case '-':
set_flag = '-';
break;
default:
update_channel_modes = 1;
chanmode_type = irc_mode_get_chanmode_type (server, pos[0]);
ptr_arg = NULL;
switch (chanmode_type)
{
case 'A': /* always argument */
update_channel_modes = 0;
if (ptr_arg)
ptr_arg = (current_arg < argc) ?
argv[current_arg] : NULL;
break;
case 'B': /* always argument */
ptr_arg = (current_arg < argc) ?
argv[current_arg] : NULL;
break;
case 'C': /* argument if set */
ptr_arg = ((set_flag == '+') && (current_arg < argc)) ?
argv[current_arg] : NULL;
break;
case 'D': /* no argument */
break;
}
if (ptr_arg)
current_arg++;
if (smart_filter
&& !irc_mode_smart_filtered (server, pos[0]))
{
smart_filter = 0;
}
if (pos[0] == 'k')
{
/* channel key */
if (set_flag == '-')
{
if (channel->key)
{
ptr_nick = irc_nick_search (server, channel,
ptr_arg);
if (ptr_nick)
free (channel->key);
channel->key = NULL;
}
}
else if ((set_flag == '+')
&& ptr_arg && (strcmp (ptr_arg, "*") != 0))
{
/* replace key for +k, but ignore "*" as new key */
if (channel->key)
free (channel->key);
channel->key = strdup (ptr_arg);
}
}
else if (pos[0] == 'l')
{
/* channel limit */
if (set_flag == '-')
channel->limit = 0;
if ((set_flag == '+') && ptr_arg)
{
channel->limit = atoi (ptr_arg);
}
}
else if ((chanmode_type != 'A')
&& (irc_server_get_prefix_mode_index (server,
pos[0]) >= 0))
{
/* mode for nick */
update_channel_modes = 0;
if (ptr_arg)
{
ptr_nick = irc_nick_search (server, channel,
ptr_arg);
if (ptr_nick)
{
irc_nick_set_mode (server, channel, ptr_nick,
(set_flag == '+'), pos[0]);
/*
* disable smart filtering if mode is sent
* to me, or based on the nick speaking time
*/
if (smart_filter
&& ((irc_server_strcasecmp (server,
ptr_nick->name,
server->nick) == 0)
|| irc_channel_nick_speaking_time_search (server,
channel,
ptr_nick->name,
1)))
{
irc_nick_set_mode (server, channel, ptr_nick,
(set_flag == '+'), pos[0]);
/*
* disable smart filtering if mode is sent
* to me, or based on the nick speaking time
*/
if (smart_filter
&& ((irc_server_strcasecmp (server,
ptr_nick->name,
server->nick) == 0)
|| irc_channel_nick_speaking_time_search (server,
channel,
ptr_nick->name,
1)))
{
smart_filter = 0;
}
smart_filter = 0;
}
}
}
else if (chanmode_type == 'A')
}
else if (chanmode_type == 'A')
{
/* modelist modes */
if (ptr_arg)
{
/* modelist modes */
ptr_modelist = irc_modelist_search (channel, pos[0]);
if (ptr_modelist)
{
@@ -489,21 +479,21 @@ irc_mode_channel_set (struct t_irc_server *server,
}
}
}
}
if (update_channel_modes)
{
irc_mode_channel_update (server, channel, set_flag,
pos[0], ptr_arg);
channel_modes_updated = 1;
}
break;
}
pos++;
if (update_channel_modes)
{
irc_mode_channel_update (server, channel, set_flag,
pos[0], ptr_arg);
channel_modes_updated = 1;
}
break;
}
if (end_modes)
break;
pos++;
}
if (str_modes)
free (str_modes);
if (argv)
weechat_string_free_split (argv);
+2 -1
View File
@@ -28,7 +28,8 @@ extern char irc_mode_get_chanmode_type (struct t_irc_server *server,
extern int irc_mode_channel_set (struct t_irc_server *server,
struct t_irc_channel *channel,
const char *host,
const char *modes);
const char *modes,
const char *modes_arguments);
extern void irc_mode_user_set (struct t_irc_server *server, const char *modes,
int reset_modes);
+3
View File
@@ -257,6 +257,9 @@ irc_modelist_item_new (struct t_irc_modelist *modelist,
{
struct t_irc_modelist_item *new_item;
if (!mask)
return NULL;
/* alloc memory for new item */
if ((new_item = malloc (sizeof (*new_item))) == NULL)
{
+4 -5
View File
@@ -1398,9 +1398,8 @@ IRC_PROTOCOL_CALLBACK(mode)
IRC_PROTOCOL_CHECK_HOST;
pos_modes = (argv[3][0] == ':') ? argv[3] + 1 : argv[3];
pos_modes_args = NULL;
if (argc > 4)
pos_modes_args = (argv_eol[4][0] == ':') ? argv_eol[4] + 1 : argv_eol[4];
pos_modes_args = (argc > 4) ?
((argv_eol[4][0] == ':') ? argv_eol[4] + 1 : argv_eol[4]) : NULL;
if (irc_channel_is_channel (server, argv[2]))
{
@@ -1409,7 +1408,7 @@ IRC_PROTOCOL_CALLBACK(mode)
if (ptr_channel)
{
smart_filter = irc_mode_channel_set (server, ptr_channel, host,
pos_modes);
pos_modes, pos_modes_args);
}
local_mode = (irc_server_strcasecmp (server, nick, server->nick) == 0);
ptr_nick = irc_nick_search (server, ptr_channel, nick);
@@ -3546,7 +3545,7 @@ IRC_PROTOCOL_CALLBACK(324)
if (argc > 4)
{
(void) irc_mode_channel_set (server, ptr_channel, host,
ptr_channel->modes);
ptr_modes, NULL);
}
}
if (!ptr_channel