Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package weechat for openSUSE:Factory checked in at 2026-07-21 23:08:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/weechat (Old) and /work/SRC/openSUSE:Factory/.weechat.new.24530 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "weechat" Tue Jul 21 23:08:54 2026 rev:96 rq:1366796 version:4.9.4 Changes: -------- --- /work/SRC/openSUSE:Factory/weechat/weechat.changes 2026-07-06 12:35:29.233988238 +0200 +++ /work/SRC/openSUSE:Factory/.weechat.new.24530/weechat.changes 2026-07-21 23:09:05.947628089 +0200 @@ -1,0 +2,19 @@ +Mon Jul 20 14:50:08 UTC 2026 - Hunter Wardlaw <[email protected]> + +- Update to 4.9.4: + + Changed + * core: improve speed of display of long words in chat area (#2336) + + Fixed + * core: fix infinite loop when option weechat.look.read_marker_string + is set to a string with a width of zero (#2337) + * core: fix integer overflow in size calculation when evaluating + "${hide:...}" and "${base_encode:...}" (#2335) + * logger: fix path traversal in log file name when a buffer local + variable contains the char used internally to protect directory + separators (#2340) + * relay: fix authentication bypass with the "plain" password hash + algorithm (GHSA-68ff-gq39-pqjm) + +------------------------------------------------------------------- Old: ---- weechat-4.9.3.tar.xz weechat-4.9.3.tar.xz.asc New: ---- weechat-4.9.4.tar.xz weechat-4.9.4.tar.xz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ weechat.spec ++++++ --- /var/tmp/diff_new_pack.RrbnFP/_old 2026-07-21 23:09:06.839658577 +0200 +++ /var/tmp/diff_new_pack.RrbnFP/_new 2026-07-21 23:09:06.843658713 +0200 @@ -17,7 +17,7 @@ Name: weechat -Version: 4.9.3 +Version: 4.9.4 Release: 0 Summary: Multi-protocol extensible Chat Client License: GPL-3.0-or-later ++++++ weechat-4.9.3.tar.xz -> weechat-4.9.4.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/CHANGELOG.md new/weechat-4.9.4/CHANGELOG.md --- old/weechat-4.9.3/CHANGELOG.md 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/CHANGELOG.md 2026-07-19 15:39:40.000000000 +0200 @@ -6,6 +6,19 @@ # WeeChat ChangeLog +## Version 4.9.4 (2026-07-19) + +### Changed + +- core: improve speed of display of long words in chat area ([#2336](https://github.com/weechat/weechat/issues/2336)) + +### Fixed + +- core: fix infinite loop when option weechat.look.read_marker_string is set to a string with a width of zero ([#2337](https://github.com/weechat/weechat/issues/2337)) +- core: fix integer overflow in size calculation when evaluating "${hide:...}" and "${base_encode:...}" ([#2335](https://github.com/weechat/weechat/issues/2335)) +- logger: fix path traversal in log file name when a buffer local variable contains the char used internally to protect directory separators ([#2340](https://github.com/weechat/weechat/issues/2340)) +- relay: fix authentication bypass with the "plain" password hash algorithm ([GHSA-68ff-gq39-pqjm](https://github.com/weechat/weechat/security/advisories/GHSA-68ff-gq39-pqjm) + ## Version 4.9.3 (2026-07-05) ### Fixed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/src/core/core-eval.c new/weechat-4.9.4/src/core/core-eval.c --- old/weechat-4.9.3/src/core/core-eval.c 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/src/core/core-eval.c 2026-07-19 15:39:40.000000000 +0200 @@ -28,6 +28,7 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> +#include <limits.h> #include <regex.h> #include <time.h> #include <sys/time.h> @@ -373,6 +374,11 @@ { length_hide_char = strlen (hide_char); length = utf8_strlen (ptr_string + 1); + if ((length_hide_char > 0) && (length >= INT_MAX / length_hide_char)) + { + free (hide_char); + return strdup (""); + } hidden_string = malloc ((length * length_hide_char) + 1); if (hidden_string) { @@ -903,6 +909,8 @@ ptr_string++; length = strlen (ptr_string); + if (length >= (INT_MAX - 9) / 4) + goto end; result = malloc ((length * 4) + 8 + 1); if (!result) goto end; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/src/gui/curses/gui-curses-chat.c new/weechat-4.9.4/src/gui/curses/gui-curses-chat.c --- old/weechat-4.9.3/src/gui/curses/gui-curses-chat.c 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/src/gui/curses/gui-curses-chat.c 2026-07-19 15:39:40.000000000 +0200 @@ -213,6 +213,11 @@ if (!read_marker_string || !read_marker_string[0]) read_marker_string = default_string; size_on_screen = utf8_strlen_screen (read_marker_string); + if (size_on_screen <= 0) + { + read_marker_string = default_string; + size_on_screen = utf8_strlen_screen (read_marker_string); + } gui_window_set_weechat_color (GUI_WINDOW_OBJECTS(window)->win_chat, GUI_COLOR_CHAT_READ_MARKER); gui_chat_clrtoeol (window); @@ -591,6 +596,7 @@ { char *data, *ptr_data, *end_line, saved_char; int chars_displayed, pos_saved_char, chars_to_display, num_displayed; + int chars_remaining; chars_displayed = 0; @@ -613,6 +619,7 @@ word_end = NULL; ptr_data = data; + chars_remaining = gui_chat_strlen_screen (ptr_data); while (ptr_data && ptr_data[0]) { chars_displayed += gui_chat_display_prefix_suffix ( @@ -626,7 +633,7 @@ apply_style_inactive, nick_offline); - chars_to_display = gui_chat_strlen_screen (ptr_data); + chars_to_display = chars_remaining; /* too long for current line */ if (window->win_chat_cursor_x + chars_to_display > gui_chat_get_real_width (window)) @@ -652,6 +659,7 @@ apply_style_inactive, nick_offline); } + chars_remaining -= gui_chat_strlen_screen (ptr_data); ptr_data[pos_saved_char] = saved_char; if (pos_saved_char == 0) break; @@ -678,6 +686,7 @@ } if (!ptr_data[0]) break; + chars_remaining = 0; ptr_data += strlen (ptr_data); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/src/plugins/logger/logger.c new/weechat-4.9.4/src/plugins/logger/logger.c --- old/weechat-4.9.3/src/plugins/logger/logger.c 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/src/plugins/logger/logger.c 2026-07-19 15:39:40.000000000 +0200 @@ -352,8 +352,10 @@ char * logger_get_mask_expanded (struct t_gui_buffer *buffer, const char *mask) { - char *mask2, *mask3, *mask4, *mask5, *mask6, *mask7, *mask8, *dir_separator; - int length; + char *mask2, *mask3, *mask4, *mask5, *dir_separator; + char *expanded, *replaced, **items; + const char *ptr_replacement_char; + int length, i, num_items; time_t seconds; struct tm *date_tmp; @@ -361,9 +363,8 @@ mask3 = NULL; mask4 = NULL; mask5 = NULL; - mask6 = NULL; - mask7 = NULL; - mask8 = NULL; + items = NULL; + num_items = 0; dir_separator = weechat_info_get ("dir_separator", ""); if (!dir_separator) @@ -380,45 +381,59 @@ if (strftime (mask2, length, mask, date_tmp) == 0) mask2[0] = '\0'; + ptr_replacement_char = weechat_config_string ( + logger_config_file_replacement_char); + /* - * we first replace directory separator (commonly '/') by \001 because - * buffer mask can contain this char, and will be replaced by replacement - * char ('_' by default) + * local variables are expanded in each directory level of the mask + * separately: their values are not trusted (for example an IRC channel + * name is chosen by the server), so any directory separator they contain + * is replaced by the replacement char, and only the separators coming from + * the mask itself are kept when the levels are joined again; this way a + * buffer local variable can not add a directory level to the path of the + * log file */ - mask3 = weechat_string_replace (mask2, dir_separator, "\001"); + items = weechat_string_split (mask2, dir_separator, NULL, 0, 0, &num_items); + if (items) + { + for (i = 0; i < num_items; i++) + { + expanded = weechat_buffer_string_replace_local_var (buffer, + items[i]); + if (!expanded) + goto end; + replaced = weechat_string_replace (expanded, dir_separator, + ptr_replacement_char); + free (expanded); + if (!replaced) + goto end; + free (items[i]); + items[i] = replaced; + } + mask3 = weechat_string_rebuild_split_string ((const char **)items, + dir_separator, 0, -1); + } + else + { + /* empty mask */ + mask3 = strdup (mask2); + } if (!mask3) goto end; - mask4 = weechat_buffer_string_replace_local_var (buffer, mask3); - if (!mask4) - goto end; - - mask5 = weechat_string_replace (mask4, - dir_separator, - weechat_config_string (logger_config_file_replacement_char)); - if (!mask5) - goto end; - #ifdef __CYGWIN__ - mask6 = weechat_string_replace (mask5, "\\", - weechat_config_string (logger_config_file_replacement_char)); + mask4 = weechat_string_replace (mask3, "\\", ptr_replacement_char); #else - mask6 = strdup (mask5); + mask4 = strdup (mask3); #endif /* __CYGWIN__ */ - if (!mask6) - goto end; - - /* restore directory separator */ - mask7 = weechat_string_replace (mask6, - "\001", dir_separator); - if (!mask7) + if (!mask4) goto end; /* convert to lower case? */ if (weechat_config_boolean (logger_config_file_name_lower_case)) - mask8 = weechat_string_tolower (mask7); + mask5 = weechat_string_tolower (mask4); else - mask8 = strdup (mask7); + mask5 = strdup (mask4); if (weechat_logger_plugin->debug) { @@ -427,19 +442,17 @@ "decoded mask = \"%s\"", LOGGER_PLUGIN_NAME, weechat_buffer_get_string (buffer, "name"), - mask, mask8); + mask, mask5); } end: free (dir_separator); free (mask2); + weechat_string_free_split (items); free (mask3); free (mask4); - free (mask5); - free (mask6); - free (mask7); - return mask8; + return mask5; } /* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/src/plugins/relay/relay-auth.c new/weechat-4.9.4/src/plugins/relay/relay-auth.c --- old/weechat-4.9.3/src/plugins/relay/relay-auth.c 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/src/plugins/relay/relay-auth.c 2026-07-19 15:39:40.000000000 +0200 @@ -584,6 +584,15 @@ switch (hash_algo) { + case RELAY_AUTH_PASSWORD_HASH_PLAIN: + /* + * plain password is not handled here: it is checked by the + * function relay_auth_check_password_plain; receiving the "plain" + * algo in a hashed password means the client is trying to + * authenticate with the wrong form, so it is rejected + */ + rc = -1; + break; case RELAY_AUTH_PASSWORD_HASH_SHA256: case RELAY_AUTH_PASSWORD_HASH_SHA512: relay_auth_parse_sha ( @@ -599,7 +608,7 @@ else if (!relay_auth_check_hash_sha (str_hash_algo, salt, salt_size, hash_sha, relay_password)) { - rc = -4;; + rc = -4; } free (salt_hexa); free (salt); @@ -637,6 +646,9 @@ case RELAY_NUM_PASSWORD_HASH_ALGOS: rc = -4; break; + default: + rc = -1; + break; } end: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/tests/unit/core/test-core-eval.cpp new/weechat-4.9.4/tests/unit/core/test-core-eval.cpp --- old/weechat-4.9.3/tests/unit/core/test-core-eval.cpp 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/tests/unit/core/test-core-eval.cpp 2026-07-19 15:39:40.000000000 +0200 @@ -457,8 +457,9 @@ struct t_hashtable *pointers, *extra_vars, *options; struct t_config_option *ptr_option; struct t_gui_buffer *test_buffer; - char *value, str_value[256], str_expr[256], *error; + char *value, str_value[256], str_expr[256], *error, *big_expr, *pos; const char *ptr_debug_output; + int big_size; long number; time_t time_now; @@ -633,6 +634,25 @@ WEE_CHECK_EVAL("********", "${hide:*,password}"); WEE_CHECK_EVAL("\u2603\u2603\u2603", "${hide:${esc:\u2603},abc}"); + /* + * hidden chars: the product (hide char length * number of chars) must not + * overflow the size of the allocated output (would corrupt the heap) + */ + big_size = 65536; + big_expr = (char *)malloc ((big_size * 2) + 16); + pos = big_expr; + memcpy (pos, "${hide:", 7); + pos += 7; + memset (pos, 'x', big_size); + pos += big_size; + *pos++ = ','; + memset (pos, 'y', big_size); + pos += big_size; + *pos++ = '}'; + *pos = '\0'; + WEE_CHECK_EVAL("", big_expr); + free (big_expr); + /* test cut of chars (invalid values) */ WEE_CHECK_EVAL("", "${cut:}"); WEE_CHECK_EVAL("", "${cut:0,}"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/tests/unit/plugins/logger/test-logger.cpp new/weechat-4.9.4/tests/unit/plugins/logger/test-logger.cpp --- old/weechat-4.9.3/tests/unit/plugins/logger/test-logger.cpp 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/tests/unit/plugins/logger/test-logger.cpp 2026-07-19 15:39:40.000000000 +0200 @@ -29,6 +29,9 @@ { #include "src/gui/gui-buffer.h" #include "src/plugins/logger/logger.h" + +extern char *logger_get_mask_expanded (struct t_gui_buffer *buffer, + const char *mask); } TEST_GROUP(Logger) @@ -112,7 +115,46 @@ TEST(Logger, GetMaskExpanded) { - /* TODO: write tests */ + char *str; + + /* empty mask */ + WEE_TEST_STR("", logger_get_mask_expanded (gui_buffers, "")); + + /* mask without any special char */ + WEE_TEST_STR("test.weechatlog", + logger_get_mask_expanded (gui_buffers, "test.weechatlog")); + + /* local variable of buffer is expanded (buffer "name" == "weechat") */ + WEE_TEST_STR("weechat.weechatlog", + logger_get_mask_expanded (gui_buffers, "$name.weechatlog")); + + /* directory separators of the mask itself are kept as directory levels */ + WEE_TEST_STR("dir1/dir2/weechat.weechatlog", + logger_get_mask_expanded (gui_buffers, + "dir1/dir2/$name.weechatlog")); + + gui_buffer_set (gui_buffers, "localvar_set_testmask", "aaa/bbb"); + + /* + * a directory separator inside a local variable value is replaced and can + * not add a directory level to the path + */ + WEE_TEST_STR("aaa_bbb.weechatlog", + logger_get_mask_expanded (gui_buffers, + "$testmask.weechatlog")); + + /* + * path traversal: the char used internally to protect directory separators + * (0x01) must not be turned into a directory separator when it comes from a + * local variable value (it is kept as-is in the file name) + */ + gui_buffer_set (gui_buffers, "localvar_set_testmask", + "aaa\001..\001..\001bbb"); + WEE_TEST_STR("aaa\001..\001..\001bbb.weechatlog", + logger_get_mask_expanded (gui_buffers, + "$testmask.weechatlog")); + + gui_buffer_set (gui_buffers, "localvar_del_testmask", ""); } /* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/tests/unit/plugins/relay/test-relay-auth.cpp new/weechat-4.9.4/tests/unit/plugins/relay/test-relay-auth.cpp --- old/weechat-4.9.3/tests/unit/plugins/relay/test-relay-auth.cpp 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/tests/unit/plugins/relay/test-relay-auth.cpp 2026-07-19 15:39:40.000000000 +0200 @@ -29,7 +29,10 @@ #include <string.h> #include <ctype.h> #include <time.h> +#include <gcrypt.h> #include "src/core/core-config-file.h" +#include "src/core/core-crypto.h" +#include "src/core/core-string.h" #include "src/plugins/relay/relay.h" #include "src/plugins/relay/relay-auth.h" #include "src/plugins/relay/relay-client.h" @@ -509,5 +512,111 @@ TEST(RelayAuth, PasswordHash) { - /* TODO: write tests */ + struct t_relay_client *client; + const char *password = "password"; + char salt[1024], salt_pass[1024], hash[1024], hash_hexa[2048]; + char hashed_password[4096]; + time_t time_now; + int hash_size, salt_size; + + client = (struct t_relay_client *)calloc (1, sizeof (*client)); + CHECK(client); + client->protocol = RELAY_PROTOCOL_API; + + /* invalid arguments */ + LONGS_EQUAL(-4, relay_auth_password_hash (client, NULL, NULL)); + LONGS_EQUAL(-4, relay_auth_password_hash (client, "sha256:abcd", NULL)); + LONGS_EQUAL(-4, relay_auth_password_hash (client, NULL, "password")); + + /* missing separator between algo and hash */ + LONGS_EQUAL(-4, relay_auth_password_hash (client, "", "password")); + LONGS_EQUAL(-4, relay_auth_password_hash (client, "sha256", "password")); + + /* unknown hash algorithm */ + LONGS_EQUAL(-1, relay_auth_password_hash (client, ":abcd", "password")); + LONGS_EQUAL(-1, relay_auth_password_hash (client, "zzz:abcd", "password")); + + /* + * algo "plain" must always be rejected in a hashed password: it is + * checked by relay_auth_check_password_plain, and accepting it here + * would authenticate the client without any password check + */ + LONGS_EQUAL(-1, relay_auth_password_hash (client, "plain:", "password")); + LONGS_EQUAL(-1, relay_auth_password_hash (client, "plain:test", "password")); + LONGS_EQUAL(-1, relay_auth_password_hash (client, "plain:password", + "password")); + + /* same test with protocol "weechat", after "plain" was negotiated */ + client->protocol = RELAY_PROTOCOL_WEECHAT; + client->password_hash_algo = RELAY_AUTH_PASSWORD_HASH_PLAIN; + LONGS_EQUAL(-1, relay_auth_password_hash (client, "plain:", "password")); + LONGS_EQUAL(-1, relay_auth_password_hash (client, "plain:password", + "password")); + + /* no authentication supported with protocol "weechat" */ + client->password_hash_algo = -1; + LONGS_EQUAL(-1, relay_auth_password_hash (client, "sha256:abcd", + "password")); + + /* + * nominal case: authentication OK with protocol "api", where the salt is + * the current time (as unix timestamp) + */ + client->protocol = RELAY_PROTOCOL_API; + + /* SHA256 */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), "%ld%s", time_now, password); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA256, hash, &hash_size)); + string_base_encode ("16", hash, hash_size, hash_hexa); + snprintf (hashed_password, sizeof (hashed_password), + "sha256:%ld:%s", time_now, hash_hexa); + LONGS_EQUAL(0, relay_auth_password_hash (client, hashed_password, password)); + /* wrong password with the same (valid) form: invalid password (hash) */ + LONGS_EQUAL(-4, relay_auth_password_hash (client, hashed_password, "wrong")); + + /* SHA512 */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), "%ld%s", time_now, password); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA512, hash, &hash_size)); + string_base_encode ("16", hash, hash_size, hash_hexa); + snprintf (hashed_password, sizeof (hashed_password), + "sha512:%ld:%s", time_now, hash_hexa); + LONGS_EQUAL(0, relay_auth_password_hash (client, hashed_password, password)); + + /* PBKDF2 (SHA256), with the default number of iterations (100000) */ + time_now = time (NULL); + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (password, strlen (password), + GCRY_MD_SHA256, + salt, strlen (salt), + 100000, hash, &hash_size)); + string_base_encode ("16", hash, hash_size, hash_hexa); + snprintf (hashed_password, sizeof (hashed_password), + "pbkdf2+sha256:%ld:100000:%s", time_now, hash_hexa); + LONGS_EQUAL(0, relay_auth_password_hash (client, hashed_password, password)); + + /* + * nominal case: authentication OK with protocol "weechat", where the salt + * is the server nonce followed by a client nonce, both in hexadecimal + */ + client->protocol = RELAY_PROTOCOL_WEECHAT; + client->password_hash_algo = RELAY_AUTH_PASSWORD_HASH_SHA256; + client->nonce = strdup ("abcd"); + + /* salt = server nonce ("abcd") + client nonce ("1234") */ + salt_size = string_base_decode ("16", "abcd1234", salt); + memcpy (salt_pass, salt, salt_size); + memcpy (salt_pass + salt_size, password, strlen (password)); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, salt_size + strlen (password), + GCRY_MD_SHA256, hash, &hash_size)); + string_base_encode ("16", hash, hash_size, hash_hexa); + snprintf (hashed_password, sizeof (hashed_password), + "sha256:abcd1234:%s", hash_hexa); + LONGS_EQUAL(0, relay_auth_password_hash (client, hashed_password, password)); + + free (client->nonce); + free (client); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/weechat-4.9.3/version.sh new/weechat-4.9.4/version.sh --- old/weechat-4.9.3/version.sh 2026-07-05 15:40:23.000000000 +0200 +++ new/weechat-4.9.4/version.sh 2026-07-19 15:39:40.000000000 +0200 @@ -41,8 +41,8 @@ # devel-number the devel version as hex number ("0x04010000" for "4.1.0-dev") # -weechat_stable="4.9.3" -weechat_devel="4.9.3" +weechat_stable="4.9.4" +weechat_devel="4.9.4" stable_major=$(echo "${weechat_stable}" | cut -d"." -f1) stable_minor=$(echo "${weechat_stable}" | cut -d"." -f2)
