1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-12 22:24:47 +02:00

Compare commits

...

59 Commits

Author SHA1 Message Date
aizu-m bc3f14eacb core: fix buffer overflow in function network_pass_socks5proxy (#2325)
bound the configured proxy username and password before they are copied into the fixed stack buffer in network_pass_socks5proxy, otherwise a login longer than the buffer (a long password or token) overruns it while building the SOCKS5 auth request.
2026-06-12 17:26:48 +02:00
Sébastien Helleu f07a63755c core: add CVE IDs in ChangeLog 2026-06-09 22:13:57 +02:00
Sébastien Helleu c6f30816dd tests: increase buffer size for injection of fake IRC message 2026-06-07 08:51:20 +02:00
aizu-m c55b5836f0 relay: fix out-of-bounds read in relay_http_print_log_request (#2324) 2026-06-06 14:37:21 +02:00
Sébastien Helleu e93db7f99d relay: limit size of partial message received while reading an HTTP request to prevent memory exhaustion
A relay client could send data with no end-of-line (an unterminated method
or header line) and dribble its payload, making WeeChat accumulate it in the
partial message buffer that grew without limit, until all memory was
exhausted. This path is reachable before authentication during websocket
initialization with the "weechat" and "irc" protocols.

The accumulated partial message is now bounded by
RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH: once the limit is reached, the extra
data is ignored.
2026-06-06 14:37:21 +02:00
aizu-m 22ee76cdd6 xfer: fix out-of-bounds read in xfer_chat_recv_cb on empty line (#2323) 2026-06-06 14:33:34 +02:00
aizu-m cf2d0733d3 irc: fix out-of-bounds read in DCC command with quoted filename (#2322) 2026-06-06 14:31:35 +02:00
aizu-m 75b72e7f69 xfer: replace directory separator in remote nick by underscore in download filename (#2321) 2026-06-06 14:21:34 +02:00
Sébastien Helleu 03a6d9306a api: fix infinite loop in function string_replace when the search string is empty 2026-06-06 14:19:37 +02:00
Sébastien Helleu 398cfc473a relay: limit size of received websocket frame and HTTP body to prevent memory exhaustion
A relay client could announce a huge websocket frame (or HTTP body via
"Content-Length") and dribble its payload, making WeeChat accumulate it
in a buffer that grew without limit, until all memory was exhausted. The
websocket frame path is reachable before authentication with the
"weechat" and "irc" protocols.

The announced websocket frame length and HTTP "Content-Length" are now
bounded by WEBSOCKET_FRAME_MAX_LENGTH and RELAY_HTTP_BODY_MAX_LENGTH: an
oversized websocket frame closes the connection, and an oversized body is
rejected.
2026-06-06 14:19:17 +02:00
Sébastien Helleu e5df225d9f irc: limit size of data received from the server to prevent memory exhaustion
A malicious or compromised IRC server could send data with no end-of-line
(or a flood of "005" messages), making WeeChat accumulate it in a buffer
that grew without limit, until all memory was exhausted.

The unterminated received message and the accumulated "005" (ISUPPORT)
data are now bounded by IRC_SERVER_RECV_MSG_MAX_LENGTH and
IRC_SERVER_ISUPPORT_MAX_LENGTH: extra data is ignored once the limit is
reached.
2026-06-06 14:17:41 +02:00
Sébastien Helleu f5fa814fa4 core: fix timing attack on TOTP validation (GHSA-vhv8-g2r9-cwcc)
weecrypto_totp_validate compared the generated and client-supplied OTPs
with strcmp and broke out of the time-window loop on the first match.
Both choices leaked information via response timing: strcmp leaked the
expected OTP digit-by-digit (shrinking the brute-force search from
~10^digits to a handful of guesses within the 30-second window), and
the early break leaked which window offset matched.

Compare in constant time with string_memcmp_constant_time and always
iterate the full window, OR-ing the result into otp_ok without an
early exit.

This affects both relay protocols (which call totp_validate via the
public info hook) and any other caller of the info hook.
2026-06-06 14:10:15 +02:00
Sébastien Helleu 34cbe56a6f relay/irc: fix timing attack on PASS command (GHSA-vhv8-g2r9-cwcc)
The IRC relay protocol's PASS handler compared the server password with
the client-supplied value using strcmp, leaking the password byte-by-byte
via response timing. This is the same class of bug fixed for the api and
weechat protocols, on a separate code path that did not go through
relay_auth_check_password_plain.

Extract the HMAC-then-constant-time-compare logic from
relay_auth_check_password_plain into relay_auth_password_equals, then
use it in both the plain-auth wrapper and the IRC PASS handler.
2026-06-06 14:08:23 +02:00
Sébastien Helleu a17a80f1d0 relay: fix timing attack on password authentication (GHSA-vhv8-g2r9-cwcc)
The relay authentication used non-constant-time comparisons (strcasecmp,
strcmp) to verify password hashes and plaintext passwords, allowing an
attacker to derive the expected hash byte-by-byte from response timing
and then authenticate without knowing the password.

- SHA/PBKDF2 hex hash comparisons: normalize the client-supplied hash to
  uppercase and compare in constant time over the fixed expected length.
- Plaintext password comparison: HMAC-SHA256 both passwords with a fresh
  per-call random key and compare the fixed-size MACs in constant time,
  hiding both per-byte timing and the password length.

Add string_memcmp_constant_time helper in core, exposed via the plugin
API. Bump WEECHAT_PLUGIN_API_VERSION accordingly.
2026-06-06 13:01:52 +02:00
Sébastien Helleu 405707d544 relay: limit size of decompressed websocket frame to prevent memory exhaustion (GHSA-v2v4-45wm-5cr3)
An authenticated relay client using the permessage-deflate websocket
extension could send a small compressed frame that decompresses to an
unbounded amount of data, exhausting all memory and crashing WeeChat.

The output buffer in relay_websocket_inflate is now capped to
WEBSOCKET_INFLATE_MAX_SIZE: frames decompressing beyond this limit are
rejected and the connection is closed.
2026-06-06 12:58:20 +02:00
Sébastien Helleu 2a272a7543 core: set max curl version for symbols
Set max curl version for these symbols:

- CURLPROTO_RTMP: 8.20.0
- CURLPROTO_RTMPT: 8.20.0
- CURLPROTO_RTMPE: 8.20.0
- CURLPROTO_RTMPTE: 8.20.0
- CURLPROTO_RTMPS: 8.20.0
- CURLPROTO_RTMPTS: 8.20.0
- CURLAUTH_DIGEST_IE: 8.21.0
- CURLOPT_KRBLEVEL: 8.17.0
2026-06-06 12:47:07 +02:00
Sébastien Helleu d4b15ea432 ci: force version 3.39.16 of schemathesis
Version 4.0.0 of schemathesis brings major breaking changes, the API tests with
this version will be changed on main branch only.
2025-06-22 09:36:06 +02:00
Sébastien Helleu 3a954405d7 core: set max version for Curl symbol CURLOPT_SSL_FALSESTART 2025-06-21 20:34:13 +02:00
Sébastien Helleu 42ae480f0a tests: add test with a float number using a lot of decimals in calculation of expression
This test validates the fix made in commit
5b4820ab06 and will prevent regression with such
numbers.
2025-06-07 17:01:11 +02:00
Sébastien Helleu f4fe63c312 core: update ChangeLog (issue #2251) 2025-05-25 10:00:24 +02:00
Sébastien Helleu 68b017935a core: fix build on FreeBSD (issue #2251)
Check if the resolv library is found before checking if it has res_init.
2025-05-25 09:58:19 +02:00
Albert Lee 97ceefd183 core: avoid dynamic format strings for Clang -Werror=format-security 2025-05-25 09:58:17 +02:00
Albert Lee 7a757d94c0 gui: use NCURSES_CFLAGS if available 2025-05-25 09:58:08 +02:00
Albert Lee f07d439cec python: use built-in CMake FindPython module from CMake 3.12 or higher 2025-05-25 09:57:59 +02:00
Albert Lee 3f670d31fe core: always define _XPG4_2 and __EXTENSIONS__ on Solaris/illumos 2025-05-25 09:56:21 +02:00
Albert Lee 558087325d core: check if res_init requires linking with libresolv 2025-05-25 09:56:19 +02:00
Albert Lee 3766d52bd3 core: improve support for non-macro htonll and htobe64 2025-05-25 09:56:17 +02:00
Albert Lee 2df0b3e2c3 core: use same msgfmt invocation to perform checks and create weechat.mo
On Illumos, msgfmt aborts when `--output-file=/dev/null` is used.
2025-05-25 09:56:15 +02:00
Albert Lee c1115c04d5 lua: use LUA_CFLAGS from pkg-config 2025-05-25 09:56:12 +02:00
Albert Lee e6d850daa0 core: include pthread.h for pthread types 2025-05-25 09:56:10 +02:00
Sébastien Helleu a0ffb9e5dd core, plugins: replace "%p" by "%lx" in calls to sscanf 2025-05-18 22:29:39 +02:00
Sébastien Helleu 95a940294e Revert "core, plugins: replace "%lx" by "%p" in calls to sscanf"
This reverts commit e64ab3c675.

This was causing incorrect conversion of strings "0x..." to pointers on systems
like Solaris/illumos.

And as a side effect, buffers were sometimes empty in weechat relay clients
like glowing-bear.
2025-05-18 22:29:39 +02:00
Sébastien Helleu d49c6515e4 relay/api: use specifier %@ for times formatted by util_strftimeval 2025-05-18 22:23:14 +02:00
Sébastien Helleu 2f375b652b core: add support of specifier %@ for UTC time in function util_strftimeval 2025-05-18 22:23:04 +02:00
Sébastien Helleu 8a024dddad Version 4.6.4-dev 2025-05-11 11:25:48 +02:00
Sébastien Helleu 951c030082 Version 4.6.3 2025-05-11 11:22:11 +02:00
Sébastien Helleu 5def4f72fe core: add API function util_version_number in upgrade guidelines 2025-05-11 10:00:27 +02:00
Sébastien Helleu 3db2f71112 core: fix buffer overflow in function eval_string_range_chars 2025-05-10 21:38:26 +02:00
Sébastien Helleu 09917a807b core: fix buffer overflow in function eval_string_base_encode 2025-05-10 21:31:22 +02:00
Sébastien Helleu 334f88ae2c core: fix buffer overflow in function eval_syntax_highlight_colorize 2025-05-10 21:30:33 +02:00
Sébastien Helleu 2e14645691 core: fix buffer overflow in function util_parse_time 2025-05-08 19:18:59 +02:00
Sébastien Helleu 2c0bbdf9b9 core: fix integer overflow in function util_version_number 2025-05-08 19:18:59 +02:00
Sébastien Helleu 5839df90e7 core: fix memory leak in function util_parse_delay 2025-05-08 18:39:03 +02:00
Sébastien Helleu 6082453002 core: fix integer overflow in base32 encoding/decoding 2025-05-05 21:39:00 +02:00
Sébastien Helleu d0568dce79 core: fix integer overflow with decimal numbers in calculation of expression 2025-05-05 21:38:28 +02:00
Sébastien Helleu 00a873dda0 ci: replace TCL 8.7 by 8.6 in FreeBSD CI 2025-04-21 08:47:37 +02:00
Sébastien Helleu 18e2badfbd Version 4.6.3-dev 2025-04-18 20:43:53 +02:00
Sébastien Helleu 120b048efb Version 4.6.2 2025-04-18 20:39:02 +02:00
Sébastien Helleu 600e438b90 debian: update changelog 2025-04-18 20:03:35 +02:00
Sébastien Helleu bf3a8628ae debian: bump Standards-Version to 4.7.2 2025-04-18 20:01:08 +02:00
Sébastien Helleu 1478ecd77d core: fix write of weechat.log to stdout with weechat-headless --stdout (issue #2247) 2025-04-15 08:16:06 +02:00
Sébastien Helleu 5c9d9bc8fc core: add refresh of window title on buffer switch, when option weechat.look.window_title is set 2025-04-11 19:32:43 +02:00
Sébastien Helleu ff00323363 Version 4.6.2-dev 2025-04-09 13:37:27 +02:00
Sébastien Helleu 1d2e5ce700 Version 4.6.1 2025-04-09 13:33:19 +02:00
Sébastien Helleu 2eebe241ab core: consider all keys are safe in cursor context (issue #2244) 2025-04-04 18:55:46 +02:00
Sébastien Helleu e93cebf02c core: update ChangeLog (issue #2243) 2025-04-02 23:05:16 +02:00
Alvar Penning c3db4946b2 perl: fix build when multiplicity is not available
Building WeeChat 4.6.0 on OpenBSD failed with the following error.

> /usr/ports/pobj/weechat-4.6.0/weechat-4.6.0/src/plugins/perl/weechat-perl.c:356:13: error: expected ')'
>             function) < 0)
>             ^
> /usr/ports/pobj/weechat-4.6.0/weechat-4.6.0/src/plugins/perl/weechat-perl.c:352:9: note: to match this '('
>     if (weechat_asprintf (
>         ^
> /usr/ports/pobj/weechat-4.6.0/weechat-4.6.0/src/plugins/perl/../weechat-plugin.h:1312:31: note: expanded from macro 'weechat_asprintf'
>     (weechat_plugin->asprintf)(__result, __fmt, ##__argz)

On further inspection, the line in question was recently altered in
099e11d7b8, where a comma was forgotten in the
else branch of the MULTIPLICITY ifdef.

After adding the comma, WeeChat builds as usual.
2025-04-02 23:05:14 +02:00
Sébastien Helleu 86d4da2fd1 irc: display nick changes and quit messages when option irc.look.ignore_tag_messages is enabled (closes #2241) 2025-03-28 12:11:29 +01:00
Sébastien Helleu e39ef93903 Version 4.6.1-dev 2025-03-28 12:10:53 +01:00
83 changed files with 912 additions and 287 deletions
+2 -2
View File
@@ -92,7 +92,7 @@ env:
ruby
rubygem-asciidoctor
sudo
tcl87
tcl86
zstd
jobs:
@@ -163,7 +163,7 @@ jobs:
env:
RELAY_PASSWORD: test
run: |
pipx install schemathesis
pipx install schemathesis==3.39.16
weechat-headless \
--dir /tmp/weechat-test-api \
--run-command '/set relay.network.password "${{ env.RELAY_PASSWORD }}"' \
+51
View File
@@ -1,5 +1,56 @@
# WeeChat ChangeLog
## Version 4.6.4 (under dev)
### Added
- core: add support of specifier `%@` for UTC time in function util_strftimeval
### Fixed
- core: fix buffer overflow in connection to SOCKS5 proxy ([#2325](https://github.com/weechat/weechat/issues/2325))
- api: fix infinite loop in function string_replace when the search string is empty
- irc: limit size of data received from the server to prevent memory exhaustion
- irc: fix out-of-bounds read on incoming DCC command with a quoted filename ending the message ([#2322](https://github.com/weechat/weechat/issues/2322))
- relay: limit size of received websocket frame and HTTP body to prevent memory exhaustion
- relay: fix timing attack on password authentication ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc), [CVE-2026-53525](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-53525))
- api, relay: fix timing attack on TOTP validation ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc), [CVE-2026-53525](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-53525))
- relay: limit size of decompressed websocket frame with permessage-deflate to prevent memory exhaustion ([GHSA-v2v4-45wm-5cr3](https://github.com/weechat/weechat/security/advisories/GHSA-v2v4-45wm-5cr3), [CVE-2026-53524](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-53524))
- relay/weechat: fix empty buffers in client when WeeChat is running on Solaris/illumos
- relay: limit size of partial message received while reading an HTTP request to prevent memory exhaustion
- relay: fix out-of-bounds read in dump of data ([#2324](https://github.com/weechat/weechat/issues/2324))
- xfer: replace directory separator in remote nick by underscore in download filename to prevent writing the file outside the download directory ([#2321](https://github.com/weechat/weechat/issues/2321))
- xfer: fix out-of-bounds read when receiving empty line in DCC chat ([#2323](https://github.com/weechat/weechat/issues/2323))
- build: fix build on Solaris/illumos (issue #2251)
## Version 4.6.3 (2025-05-11)
### Fixed
- core: fix integer overflow with decimal numbers in calculation of expression
- core: fix integer overflow in base32 encoding/decoding
- core: fix integer overflow in function util_version_number
- core: fix buffer overflow in function util_parse_time
- core: fix buffer overflow in function eval_syntax_highlight_colorize
- core: fix buffer overflow in function eval_string_base_encode
- core: fix buffer overflow in function eval_string_range_chars
- core: fix memory leak in function util_parse_delay
## Version 4.6.2 (2025-04-18)
### Fixed
- core: fix write of weechat.log to stdout with `weechat-headless --stdout` ([#2247](https://github.com/weechat/weechat/issues/2247))
- core: add refresh of window title on buffer switch, when option weechat.look.window_title is set
## Version 4.6.1 (2025-04-09)
### Fixed
- core: consider all keys are safe in cursor context ([#2244](https://github.com/weechat/weechat/issues/2244))
- irc: display nick changes and quit messages when option irc.look.ignore_tag_messages is enabled ([#2241](https://github.com/weechat/weechat/issues/2241))
- perl: fix build when multiplicity is not available ([#2243](https://github.com/weechat/weechat/issues/2243))
## Version 4.6.0 (2025-03-23)
### Changed
+21
View File
@@ -198,6 +198,7 @@ include(FindPkgConfig)
include(CheckIncludeFiles)
include(CheckFunctionExists)
include(CheckSymbolExists)
include(CheckLibraryExists)
check_include_files("langinfo.h" HAVE_LANGINFO_CODESET)
check_include_files("sys/resource.h" HAVE_SYS_RESOURCE_H)
@@ -208,13 +209,33 @@ check_symbol_exists("malloc_trim" "malloc.h" HAVE_MALLOC_TRIM)
check_function_exists(mallinfo HAVE_MALLINFO)
check_function_exists(mallinfo2 HAVE_MALLINFO2)
check_symbol_exists("htonll" "sys/types.h;netinet/in.h;inttypes.h" HAVE_HTONLL)
check_symbol_exists("eat_newline_glitch" "term.h" HAVE_EAT_NEWLINE_GLITCH)
# Check if res_init requires libresolv
check_function_exists(res_init, LIBC_HAS_RES_INIT)
if(NOT LIBC_HAS_RES_INIT)
find_library(RESOLV_LIBRARY resolv)
if(RESOLV_LIBRARY)
check_library_exists("${RESOLV_LIBRARY}" res_init "" LIBRESOLV_HAS_RES_INIT)
if(LIBRESOLV_HAS_RES_INIT)
list(APPEND EXTRA_LIBS ${RESOLV_LIBRARY})
endif()
endif()
endif()
# Check for Large File Support
if(ENABLE_LARGEFILE)
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -D_LARGE_FILES)
endif()
# _XPG4_2 is needed for macros like CMSG_SPACE
# __EXTENSIONS__ is needed for constants like NI_MAXHOST and for struct timeval
if(CMAKE_HOST_SOLARIS)
add_definitions(-D_XPG4_2 -D__EXTENSIONS__)
endif()
# Check for libgcrypt
pkg_check_modules(LIBGCRYPT REQUIRED libgcrypt)
include_directories(${LIBGCRYPT_INCLUDE_DIRS})
+8
View File
@@ -7,6 +7,14 @@ When upgrading from version X to Y, please read and apply all instructions from
For a list of all changes in each version, please see [CHANGELOG.md](CHANGELOG.md).
## Version 4.6.3
### API function util_version_number
An integer overflow has been fixed in the function
[util_version_number](https://weechat.org/doc/weechat/plugin/#_util_version_number)
which now returns a version up to "127.255.255.255" (0x7FFFFFFF).
## Version 4.6.0
### Relay remote commands
-34
View File
@@ -1,34 +0,0 @@
#
# Copyright (C) 2003-2025 Sébastien Helleu <flashcode@flashtux.org>
# Copyright (C) 2009 Julien Louis <ptitlouis@sysif.net>
#
# This file is part of WeeChat, the extensible chat client.
#
# WeeChat 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 3 of the License, or
# (at your option) any later version.
#
# WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
#
# - Find Python
# This module finds if Python is installed and determines where the include files
# and libraries are. It also determines what the name of the library is. This
# code sets the following variables:
#
# PYTHON_EXECUTABLE = full path to the python binary
# PYTHON_INCLUDE_DIRS = path to where python.h can be found
# PYTHON_LIBRARIES = path to where libpython.so* can be found
# PYTHON_LDFLAGS = python compiler options for linking
pkg_check_modules(PYTHON python3-embed IMPORTED_TARGET GLOBAL)
if(NOT PYTHON_FOUND)
pkg_check_modules(PYTHON python3 IMPORTED_TARGET GLOBAL)
endif()
+1
View File
@@ -43,6 +43,7 @@
#cmakedefine HAVE_MALLINFO2
#cmakedefine HAVE_MALLOC_H
#cmakedefine HAVE_MALLOC_TRIM
#cmakedefine HAVE_HTONLL
#cmakedefine HAVE_EAT_NEWLINE_GLITCH
#cmakedefine HAVE_ASPELL_VERSION_STRING
#cmakedefine HAVE_ENCHANT_GET_VERSION
+1 -1
View File
@@ -24,7 +24,7 @@ Build-Depends:
libzstd-dev,
zlib1g-dev,
libcjson-dev
Standards-Version: 4.7.0
Standards-Version: 4.7.2
Homepage: https://weechat.org/
Vcs-Git: https://salsa.debian.org/kolter/weechat.git
Vcs-Browser: https://salsa.debian.org/kolter/weechat
+6
View File
@@ -1,3 +1,9 @@
weechat (4.6.1-1) unstable; urgency=medium
* New upstream release (Closes: #1102450, #1098090)
-- Emmanuel Bouthenot <kolter@debian.org> Wed, 16 Apr 2025 20:31:07 +0000
weechat (4.5.1-1) unstable; urgency=medium
* New upstream release
+1 -1
View File
@@ -24,7 +24,7 @@ Build-Depends:
libzstd-dev,
zlib1g-dev,
libcjson-dev
Standards-Version: 4.7.0
Standards-Version: 4.7.2
Homepage: https://weechat.org/
Vcs-Git: https://salsa.debian.org/kolter/weechat.git
Vcs-Browser: https://salsa.debian.org/kolter/weechat
+7 -5
View File
@@ -4762,7 +4762,7 @@ This function is not available in scripting API.
==== util_strftimeval
_WeeChat ≥ 4.2.0, updated in 4.3.0._
_WeeChat ≥ 4.2.0, updated in 4.3.0, 4.6.4._
Format date and time like function `strftime` in C library, using `struct timeval`
as input, and supporting extra specifiers.
@@ -4779,6 +4779,8 @@ Arguments:
* _string_: buffer where the formatted string is stored
* _max_: string size
* _format_: format, the same as _strftime_ function, with these extra specifiers:
** `%@`: return the date expressed in Coordinated Universal Time (UTC)
instead of date relative to the user's specified timezone _(WeeChat ≥ 4.7.0)_
** `%.N` where `N` is between 1 and 6: zero-padded microseconds on N digits
(for example `%.3` for milliseconds)
** `%f`: alias of `%.6`
@@ -4795,8 +4797,8 @@ C example:
char time[256];
struct timeval tv;
gettimeofday (&tv, NULL);
weechat_util_strftimeval (time, sizeof (time), "%FT%T.%f", &tv);
/* result: 2023-12-26T18:10:04.460509 */
weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv);
/* result: 2023-12-26T18:10:04.460509Z */
----
[NOTE]
@@ -15528,8 +15530,8 @@ void weechat_window_set_title (const char *title);
Arguments:
* _title_: new title for terminal (NULL to reset title); string is evaluated,
so variables like `${info:version}` can be used
* _title_: new title for terminal; string is evaluated, so variables like
`${info:version}` can be used
(see <<_string_eval_expression,string_eval_expression>>)
C example:
+8 -6
View File
@@ -4841,7 +4841,7 @@ Cette fonction n'est pas disponible dans l'API script.
==== util_strftimeval
_WeeChat ≥ 4.2.0, mis à jour dans la 4.3.0._
_WeeChat ≥ 4.2.0, mis à jour dans la 4.3.0, 4.6.4._
Formatter la date et l'heure comme la fonction `strftime` de la bibliothèque C,
en utilisant un `struct timeval` en entrée et en supportant des caractères de
@@ -4860,6 +4860,8 @@ Paramètres :
* _max_ : taille de la chaîne
* _format_ : format, le même que celui de la fonction _strftime_, avec des
caractères de conversion supplémentaires :
** `%@`: retourner la date exprimée en Temps Universel Coordonné (UTC)
au lieu de la date relative au fuseau horaire de l'utilisateur _(WeeChat ≥ 4.7.0)_
** `%.N` où `N` est entre 1 and 6: microsecondes remplies avec des zéros sur
N chiffres (par exemple `%.3` pour les millisecondes)
** `%f` : alias de `%.6`
@@ -4876,8 +4878,8 @@ Exemple en C :
char time[256];
struct timeval tv;
gettimeofday (&tv, NULL);
weechat_util_strftimeval (time, sizeof (time), "%FT%T.%f", &tv);
/* résultat : 2023-12-26T18:10:04.460509 */
weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv);
/* résultat : 2023-12-26T18:10:04.460509Z */
----
[NOTE]
@@ -15869,9 +15871,9 @@ void weechat_window_set_title (const char *title);
Paramètres :
* _title_ : nouveau titre pour le terminal (NULL pour réinitialiser le titre) ;
la chaîne est évaluée, donc les variables comme `${info:version}` peuvent
être utilisées (voir <<_string_eval_expression,string_eval_expression>>)
* _title_ : nouveau titre pour le terminal ; la chaîne est évaluée, donc les variables
comme `${info:version}` peuvent être utilisées
(voir <<_string_eval_expression,string_eval_expression>>)
Exemple en C :
+7 -5
View File
@@ -4985,7 +4985,7 @@ Questa funzione non è disponibile nelle API per lo scripting.
// TRANSLATION MISSING
==== util_strftimeval
_WeeChat ≥ 4.2.0, updated in 4.3.0._
_WeeChat ≥ 4.2.0, updated in 4.3.0, 4.6.4._
Format date and time like function `strftime` in C library, using `struct timeval`
as input, and supporting extra specifiers.
@@ -5002,6 +5002,8 @@ Arguments:
* _string_: buffer where the formatted string is stored
* _max_: string size
* _format_: format, the same as _strftime_ function, with these extra specifiers:
** `%@`: return the date expressed in Coordinated Universal Time (UTC)
instead of date relative to the user's specified timezone _(WeeChat ≥ 4.7.0)_
** `%.N` where `N` is between 1 and 6: zero-padded microseconds on N digits
(for example `%.3` for milliseconds)
** `%f`: alias of `%.6`
@@ -5018,8 +5020,8 @@ C example:
char time[256];
struct timeval tv;
gettimeofday (&tv, NULL);
weechat_util_strftimeval (time, sizeof (time), "%FT%T.%f", &tv);
/* result: 2023-12-26T18:10:04.460509 */
weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv);
/* result: 2023-12-26T18:10:04.460509Z */
----
[NOTE]
@@ -16302,8 +16304,8 @@ void weechat_window_set_title (const char *title);
Argomenti:
// TRANSLATION MISSING
* _title_: nuovo titolo per il terminale (NULL per resettarlo);
string is evaluated, so variables like `${info:version}` can be used
* _title_: nuovo titolo per il terminale; string is evaluated, so variables
like `${info:version}` can be used
(see <<_string_eval_expression,string_eval_expression>>)
Esempio in C:
+7 -5
View File
@@ -4898,7 +4898,7 @@ weechat_printf (NULL, "date: %s",
// TRANSLATION MISSING
==== util_strftimeval
_WeeChat ≥ 4.2.0, updated in 4.3.0._
_WeeChat ≥ 4.2.0, updated in 4.3.0, 4.6.4._
Format date and time like function `strftime` in C library, using `struct timeval`
as input, and supporting extra specifiers.
@@ -4915,6 +4915,8 @@ Arguments:
* _string_: buffer where the formatted string is stored
* _max_: string size
* _format_: format, the same as _strftime_ function, with these extra specifiers:
** `%@`: return the date expressed in Coordinated Universal Time (UTC)
instead of date relative to the user's specified timezone _(WeeChat ≥ 4.7.0)_
** `%.N` where `N` is between 1 and 6: zero-padded microseconds on N digits
(for example `%.3` for milliseconds)
** `%f`: alias of `%.6`
@@ -4931,8 +4933,8 @@ C example:
char time[256];
struct timeval tv;
gettimeofday (&tv, NULL);
weechat_util_strftimeval (time, sizeof (time), "%FT%T.%f", &tv);
/* result: 2023-12-26T18:10:04.460509 */
weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv);
/* result: 2023-12-26T18:10:04.460509Z */
----
[NOTE]
@@ -15797,8 +15799,8 @@ void weechat_window_set_title (const char *title);
引数:
* _title_: 端末の新しいタイトル (タイトルをリセットする場合は NULL);
この文字列は評価されるため、文字列内に `${info:version}` などの変数を含めることが可能です
* _title_: 端末の新しいタイトル; この文字列は評価されるため、文字列内に
`${info:version}` などの変数を含めることが可能です
(<<_string_eval_expression,string_eval_expression>> を参照)
C 言語での使用例:
+9 -4
View File
@@ -4624,7 +4624,7 @@ weechat_printf (NULL, "date: %s",
==== util_strftimeval
_WeeChat ≥ 4.2.0, ажурирано у 4.3.0._
_WeeChat ≥ 4.2.0, ажурирано у 4.3.0, 4.6.4._
Форматира датум и време као функција `strftime` из C библиотеке, користећи `struct timeval`
као улаз уз подршку за додатне спецификаторе.
@@ -4641,6 +4641,9 @@ int weechat_util_strftimeval (char *string, int max, const char *format, struct
* _string_: бафер у који се смешта форматирани стринг
* _max_: величина стринга
* _format_: формат, исто као за _strftime_ функцију, са следећим додатним спецификаторима:
// TRANSLATION MISSING
** `%@`: return the date expressed in Coordinated Universal Time (UTC)
instead of date relative to the user's specified timezone _(WeeChat ≥ 4.7.0)_
** `%.N` где је `N` између 1 и 6: микросекунде допуњене нулама на N цифара
(на пример `%.3` за милисекунде)
** `%f`: алијас за `%.6`
@@ -4657,8 +4660,8 @@ C пример:
char time[256];
struct timeval tv;
gettimeofday (&tv, NULL);
weechat_util_strftimeval (time, sizeof (time), "%FT%T.%f", &tv);
/* резултат: 2023-12-26T18:10:04.460509 */
weechat_util_strftimeval (time, sizeof (time), "%@%FT%T.%fZ", &tv);
/* резултат: 2023-12-26T18:10:04.460509Z */
----
[NOTE]
@@ -15104,7 +15107,9 @@ void weechat_window_set_title (const char *title);
Аргументи:
* _title_: нови наслов за терминал (NULL ако желите да ресетујете наслов); стринг се израчунава, тако да је могуће коришћење променљивих као што је `${info:version}` (погледајте <<_string_eval_expression,string_eval_expression>>)
* _title_: нови наслов за терминал; стринг се израчунава, тако да је могуће
коришћење променљивих као што је `${info:version}`
(погледајте <<_string_eval_expression,string_eval_expression>>)
C пример:
+1 -2
View File
@@ -79,8 +79,7 @@ foreach(pofile ${PO_FILES})
add_custom_command(
OUTPUT "${mofile}"
COMMAND "${MSGMERGE_EXECUTABLE}" ARGS --quiet -o "${CMAKE_CURRENT_BINARY_DIR}/${pofile}" "${CMAKE_CURRENT_SOURCE_DIR}/${pofile}" ${POT_FILE_PATH}
COMMAND "${MSGFMT_EXECUTABLE}" ARGS -o "${mofile}" "${CMAKE_CURRENT_BINARY_DIR}/${pofile}"
COMMAND "${MSGFMT_EXECUTABLE}" ARGS -c --statistics --verbose --output-file=/dev/null "${CMAKE_CURRENT_BINARY_DIR}/${pofile}"
COMMAND "${MSGFMT_EXECUTABLE}" ARGS -c --statistics --verbose -o "${mofile}" "${CMAKE_CURRENT_BINARY_DIR}/${pofile}"
DEPENDS "${POT_FILE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/${pofile}"
COMMENT "Compiling ${polang}.po"
)
+2 -2
View File
@@ -336,9 +336,9 @@ calc_expression (const char *expr)
struct t_arraylist *list_values, *list_ops;
const char *ptr_expr, *ptr_expr2;
char str_result[64], *ptr_operator, *operator;
int index_op, decimals;
int index_op;
enum t_calc_symbol last_symbol;
double value, factor, *ptr_value;
double value, factor, decimals, *ptr_value;
list_values = NULL;
list_ops = NULL;
+1 -5
View File
@@ -498,12 +498,8 @@ config_change_window_title (const void *pointer, void *data,
(void) data;
(void) option;
if (gui_init_ok
|| (CONFIG_STRING(config_look_window_title)
&& CONFIG_STRING(config_look_window_title)[0]))
{
if (gui_init_ok)
gui_window_set_title (CONFIG_STRING(config_look_window_title));
}
}
/*
+17 -10
View File
@@ -34,10 +34,18 @@
/* Bring in htobe64 */
#ifdef __ANDROID__
#define _BSD_SOURCE
#define BE_INT64 htobe64
#include <endian.h>
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define htobe64 OSSwapHostToBigInt64
#define BE_INT64 OSSwapHostToBigInt64
#elif defined(HAVE_HTONLL)
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#define BE_INT64 htonll
#else
#define BE_INT64 htobe64
#endif
#include "weechat.h"
@@ -47,10 +55,6 @@
#include "core-string.h"
#include "../plugins/plugin.h"
#ifdef htonll
#define htobe64 htonll
#endif
char *weecrypto_hash_algo_string[] = {
"crc32",
"md5",
@@ -533,7 +537,7 @@ weecrypto_totp_generate_internal (const char *secret, int length_secret,
int rc, offset, length;
unsigned long bin_code;
moving_factor_swapped = htobe64 (moving_factor);
moving_factor_swapped = BE_INT64 (moving_factor);
rc = weecrypto_hmac (secret, length_secret,
&moving_factor_swapped, sizeof (moving_factor_swapped),
GCRY_MD_SHA1,
@@ -658,15 +662,18 @@ weecrypto_totp_validate (const char *secret_base32, time_t totp_time,
otp_ok = 0;
/*
* Compare in constant time and never break early: a non-constant
* compare and an early exit on match would let an observer measure
* how many digits of the expected OTP they got right and which
* time-window offset matched.
*/
for (i = moving_factor - window; i <= moving_factor + window; i++)
{
rc = weecrypto_totp_generate_internal (secret, length_secret,
i, digits, str_otp);
if (rc && (strcmp (str_otp, otp) == 0))
{
if (rc && (string_memcmp_constant_time (str_otp, otp, digits) == 0))
otp_ok = 1;
break;
}
}
free (secret);
+16 -4
View File
@@ -300,6 +300,9 @@ eval_string_range_chars (const char *range)
string = NULL;
result = NULL;
if (!range || !range[0])
goto end;
for (i = 0; eval_range_chars[i][0]; i++)
{
if (strcmp (range, eval_range_chars[i][0]) == 0)
@@ -309,11 +312,15 @@ eval_string_range_chars (const char *range)
char1 = utf8_char_int (range);
/* next char must be '-' */
if (!range[0])
goto end;
ptr_char = utf8_next_char (range);
if (!ptr_char || !ptr_char[0] || (ptr_char[0] != '-'))
goto end;
/* next char is the char2 */
if (!range[0])
goto end;
ptr_char = utf8_next_char (ptr_char);
if (!ptr_char || !ptr_char[0])
goto end;
@@ -894,7 +901,7 @@ eval_string_base_encode (const char *text)
ptr_string++;
length = strlen (ptr_string);
result = malloc ((length * 4) + 1);
result = malloc ((length * 4) + 8 + 1);
if (!result)
goto end;
@@ -1144,6 +1151,7 @@ char *
eval_hdata_count (const char *text, struct t_eval_context *eval_context)
{
struct t_hdata *hdata;
unsigned long ptr_value;
void *pointer;
char *pos1, *pos2, *value, *hdata_name, *pointer_name, str_count[64];
int rc, count;
@@ -1174,9 +1182,10 @@ eval_hdata_count (const char *text, struct t_eval_context *eval_context)
if (strncmp (pointer_name, "0x", 2) == 0)
{
rc = sscanf (pointer_name, "%p", &pointer);
rc = sscanf (pointer_name, "%lx", &ptr_value);
if ((rc != EOF) && (rc != 0))
{
pointer = (void *)ptr_value;
if (!hdata_check_pointer (hdata, NULL, pointer))
goto end;
}
@@ -1413,6 +1422,7 @@ eval_string_hdata (const char *text, struct t_eval_context *eval_context)
void *pointer;
struct t_hdata *hdata;
int rc;
unsigned long ptr;
value = NULL;
hdata_name = NULL;
@@ -1464,9 +1474,10 @@ eval_string_hdata (const char *text, struct t_eval_context *eval_context)
{
if (strncmp (pointer_name, "0x", 2) == 0)
{
rc = sscanf (pointer_name, "%p", &pointer);
rc = sscanf (pointer_name, "%lx", &ptr);
if ((rc != EOF) && (rc != 0))
{
pointer = (void *)ptr;
if (!hdata_check_pointer (hdata, NULL, pointer))
goto end;
}
@@ -1572,7 +1583,8 @@ eval_syntax_highlight_colorize (const char *value)
else if (ptr_value[0] == '-')
color--;
}
ptr_value++;
if (ptr_value[0])
ptr_value++;
if (config_num_eval_syntax_colors > 0)
{
string_dyn_concat (
+3 -3
View File
@@ -1244,10 +1244,10 @@ hdata_set (struct t_hdata *hdata, void *pointer, const char *name,
const char *value)
{
struct t_hdata_var *var;
void *ptr;
char **ptr_string, *error;
long number;
long long number_longlong;
unsigned long ptr;
int rc;
if (!hdata->update_pending)
@@ -1307,10 +1307,10 @@ hdata_set (struct t_hdata *hdata, void *pointer, const char *name,
case WEECHAT_HDATA_POINTER:
if (value)
{
rc = sscanf (value, "%p", &ptr);
rc = sscanf (value, "%lx", &ptr);
if ((rc != EOF) && (rc != 0))
{
*((void **)(pointer + var->offset)) = ptr;
*((void **)(pointer + var->offset)) = (void *)ptr;
return 1;
}
}
+12 -11
View File
@@ -70,21 +70,22 @@ log_open (const char *filename, const char *mode)
{
weechat_log_file = stdout;
}
else if (filename)
{
weechat_log_filename = strdup (filename);
}
else
{
string_asprintf (&weechat_log_filename,
"%s/%s", weechat_state_dir, WEECHAT_LOG_NAME);
if (filename)
{
weechat_log_filename = strdup (filename);
}
else
{
string_asprintf (&weechat_log_filename,
"%s/%s", weechat_state_dir, WEECHAT_LOG_NAME);
}
if (!weechat_log_filename)
return 0;
weechat_log_file = fopen (weechat_log_filename, mode);
}
if (!weechat_log_filename)
return 0;
weechat_log_file = fopen (weechat_log_filename, mode);
if (!weechat_log_file)
{
if (weechat_log_filename)
+19 -8
View File
@@ -26,13 +26,6 @@
#include "config.h"
#endif
/* _XPG4_2 is needed on SunOS for macros like CMSG_SPACE */
/* __EXTENSIONS__ is needed on SunOS for constants like NI_MAXHOST */
#ifdef __sun
#define _XPG4_2
#define __EXTENSIONS__
#endif
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
@@ -585,7 +578,13 @@ network_pass_socks5proxy (struct t_proxy *proxy, int sock, const char *address,
int port)
{
struct t_network_socks5 socks5;
unsigned char buffer[288];
/*
* buffer must be large enough for the username/password authentication
* request, which is the longest message sent/received here; according to
* RFC 1929 it is: version (1) + username length (1) + username (max 255)
* + password length (1) + password (max 255)
*/
unsigned char buffer[2 + 255 + 1 + 255];
int username_len, password_len, addr_len, addr_buffer_len;
unsigned char *addr_buffer;
char *username, *password;
@@ -634,6 +633,18 @@ network_pass_socks5proxy (struct t_proxy *proxy, int sock, const char *address,
username_len = strlen (username);
password_len = strlen (password);
/*
* username and password length are each stored on a single byte
* (RFC 1929), so they cannot exceed 255 bytes: reject longer values,
* otherwise the memcpy calls below would overflow the buffer
*/
if ((username_len > 255) || (password_len > 255))
{
free (username);
free (password);
return 0;
}
/* make username/password buffer */
buffer[0] = 1;
buffer[1] = (unsigned char) username_len;
+44 -2
View File
@@ -916,6 +916,43 @@ string_strcmp_ignore_chars (const char *string1, const char *string2,
string_charcasecmp (string1, string2);
}
/*
* Compares two memory areas of the same size in constant time.
*
* Use to compare secrets (e.g. password hashes, MACs) without leaking
* information through the comparison's running time. The loop always
* walks the full "size" bytes and uses only bitwise operations on the
* data, so the execution time depends on "size" alone, not on the
* position of the first differing byte.
*
* If either pointer is NULL, the areas are considered different (the
* NULL check itself is not constant time but does not look at any
* secret content).
*
* Returns:
* 0: areas are equal
* 1: areas differ
*/
int
string_memcmp_constant_time (const void *area1, const void *area2, size_t size)
{
const unsigned char *p1, *p2;
unsigned char diff;
size_t i;
if (!area1 || !area2)
return (area1 == area2) ? 0 : 1;
p1 = (const unsigned char *)area1;
p2 = (const unsigned char *)area2;
diff = 0;
for (i = 0; i < size; i++)
diff |= p1[i] ^ p2[i];
return (diff == 0) ? 0 : 1;
}
/*
* Searches for a string in another string (locale and case independent).
*
@@ -1922,6 +1959,9 @@ string_replace (const char *string, const char *search, const char *replace)
if (!string || !search || !replace)
return NULL;
if (!search[0])
return strdup (string);
length1 = strlen (search);
length2 = strlen (replace);
@@ -3570,7 +3610,8 @@ int
string_base32_encode (const char *from, int length, char *to)
{
unsigned char base32_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
int count, value, next, bits_left, pad, index;
unsigned int value;
int count, next, bits_left, pad, index;
int length_padding[8] = { 0, 0, 6, 0, 4, 3, 0, 2 };
if (!from || !to)
@@ -3648,7 +3689,8 @@ int
string_base32_decode (const char *from, char *to)
{
const char *ptr_from;
int value, bits_left, count;
int bits_left, count;
unsigned int value;
unsigned char c;
if (!from || !to)
+2
View File
@@ -67,6 +67,8 @@ extern int string_strcmp_ignore_chars (const char *string1,
const char *string2,
const char *chars_ignored,
int case_sensitive);
extern int string_memcmp_constant_time (const void *area1, const void *area2,
size_t size);
extern const char *string_strcasestr (const char *string, const char *search);
extern int string_match (const char *string, const char *mask,
int case_sensitive);
+8
View File
@@ -88,12 +88,14 @@ struct t_url_constant url_protocols[] =
URL_DEF_CONST(PROTO, SMTP),
URL_DEF_CONST(PROTO, SMTPS),
URL_DEF_CONST(PROTO, RTSP),
#if LIBCURL_VERSION_NUM < 0x081400 /* < 8.20.0 */
URL_DEF_CONST(PROTO, RTMP),
URL_DEF_CONST(PROTO, RTMPT),
URL_DEF_CONST(PROTO, RTMPE),
URL_DEF_CONST(PROTO, RTMPTE),
URL_DEF_CONST(PROTO, RTMPS),
URL_DEF_CONST(PROTO, RTMPTS),
#endif
URL_DEF_CONST(PROTO, GOPHER),
URL_DEF_CONST(PROTO, SMB),
URL_DEF_CONST(PROTO, SMBS),
@@ -122,7 +124,9 @@ struct t_url_constant url_auth[] =
URL_DEF_CONST(AUTH, NTLM),
URL_DEF_CONST(AUTH, ANY),
URL_DEF_CONST(AUTH, ANYSAFE),
#if LIBCURL_VERSION_NUM < 0x081500 /* < 8.21.0 */
URL_DEF_CONST(AUTH, DIGEST_IE),
#endif
URL_DEF_CONST(AUTH, ONLY),
#if LIBCURL_VERSION_NUM < 0x080800 /* < 8.8.0 */
URL_DEF_CONST(AUTH, NTLM_WB),
@@ -651,7 +655,9 @@ struct t_url_option url_options[] =
URL_DEF_OPTION(SSLENGINE_DEFAULT, LONG, NULL),
URL_DEF_OPTION(CAPATH, STRING, NULL),
URL_DEF_OPTION(SSL_SESSIONID_CACHE, LONG, NULL),
#if LIBCURL_VERSION_NUM < 0x081100 /* < 8.17.0 */
URL_DEF_OPTION(KRBLEVEL, STRING, NULL),
#endif
URL_DEF_OPTION(KEYPASSWD, STRING, NULL),
URL_DEF_OPTION(ISSUERCERT, STRING, NULL),
URL_DEF_OPTION(CRLFILE, STRING, NULL),
@@ -664,7 +670,9 @@ struct t_url_option url_options[] =
#endif
URL_DEF_OPTION(PINNEDPUBLICKEY, STRING, NULL),
URL_DEF_OPTION(SSL_VERIFYSTATUS, LONG, NULL),
#if LIBCURL_VERSION_NUM < 0x080F00 /* < 8.15.0 */
URL_DEF_OPTION(SSL_FALSESTART, LONG, NULL),
#endif
#if LIBCURL_VERSION_NUM >= 0x073400 /* 7.52.0 */
URL_DEF_OPTION(PROXY_CAINFO, STRING, NULL),
URL_DEF_OPTION(PROXY_CAPATH, STRING, NULL),
+24 -10
View File
@@ -166,6 +166,8 @@ util_get_time_string (const time_t *date)
/*
* Formats date and time like strftime (but with timeval structure as input)
* and adds extra specifiers:
* - "%@": return the date expressed in Coordinated Universal Time (UTC)
* instead of date relative to the user's specified timezone
* - "%.1" to "%.6": first N digits of microseconds, zero-padded
* - "%f": alias of "%.6" (microseconds, zero-padded to 6 digits)
* - "%!": timestamp as integer, in seconds (value of tv->tv_sec)
@@ -176,14 +178,15 @@ util_strftimeval (char *string, int max, const char *format, struct timeval *tv)
{
char **format2, str_temp[32];
const char *ptr_format;
struct tm *local_time;
int length, bytes;
struct tm *date_time;
int length, bytes, local_time;
long usec;
if (!string || (max <= 0) || !format || !tv)
return 0;
string[0] = '\0';
local_time = 1;
if (!format[0])
return 0;
@@ -206,6 +209,11 @@ util_strftimeval (char *string, int max, const char *format, struct timeval *tv)
string_dyn_concat (format2, "%%", -1);
ptr_format += 2;
}
else if ((ptr_format[0] == '%') && (ptr_format[1] == '@'))
{
local_time = 0;
ptr_format += 2;
}
else if ((ptr_format[0] == '%') && (ptr_format[1] == '.'))
{
if ((ptr_format[2] >= '1') && (ptr_format[2] <= '6'))
@@ -242,14 +250,17 @@ util_strftimeval (char *string, int max, const char *format, struct timeval *tv)
}
}
local_time = localtime (&(tv->tv_sec));
if (!local_time)
if (local_time)
date_time = localtime (&(tv->tv_sec));
else
date_time = gmtime (&(tv->tv_sec));
if (!date_time)
{
string_dyn_free (format2, 1);
return 0;
}
bytes = strftime (string, max, *format2, local_time);
bytes = strftime (string, max, *format2, date_time);
string_dyn_free (format2, 1);
@@ -285,7 +296,8 @@ util_strftimeval (char *string, int max, const char *format, struct timeval *tv)
int
util_parse_time (const char *datetime, struct timeval *tv)
{
char *string, *pos, *pos2, str_usec[16], *error, str_date[128];
char *string, *pos, *pos2, str_usec[16], *error;
char str_date[128], str_date2[256];
struct tm tm_date, tm_date_gm, tm_date_local, *local_time;
time_t time_now, time_gm, time_local;
long long value;
@@ -445,10 +457,10 @@ util_parse_time (const char *datetime, struct timeval *tv)
local_time = localtime (&time_now);
strftime (str_date, sizeof (str_date),
"%Y-%m-%dT", local_time);
strcat (str_date, string);
snprintf (str_date2, sizeof (str_date2), "%s%s", str_date, string);
/* initialize structure, because strptime does not do it */
memset (&tm_date, 0, sizeof (struct tm));
pos = strptime (str_date, "%Y-%m-%dT%H:%M:%S", &tm_date);
pos = strptime (str_date2, "%Y-%m-%dT%H:%M:%S", &tm_date);
if (pos)
{
if (use_local_time)
@@ -571,7 +583,6 @@ util_parse_delay (const char *string_delay, unsigned long long default_factor,
if ((pos > string_delay) && pos[0])
{
str_number = string_strndup (string_delay, pos - string_delay);
if (strcmp (pos, "us") == 0)
factor = 1ULL;
else if (strcmp (pos, "ms") == 0)
@@ -584,6 +595,7 @@ util_parse_delay (const char *string_delay, unsigned long long default_factor,
factor = 1000ULL * 1000ULL * 60ULL * 60ULL;
else
return 0;
str_number = string_strndup (string_delay, pos - string_delay);
}
else
{
@@ -670,7 +682,9 @@ util_version_number (const char *version)
{
if (number < 0)
number = 0;
else if (number > 0xFF)
else if ((i == 0) && (number > 0x7F))
number = 0x7F;
else if ((i > 0) && (number > 0xFF))
number = 0xFF;
version_int[i] = number;
}
+2
View File
@@ -20,6 +20,8 @@
#ifndef WEECHAT_HOOK_URL_H
#define WEECHAT_HOOK_URL_H
#include <pthread.h>
struct t_weechat_plugin;
struct t_infolist_item;
struct t_hashtable;
-5
View File
@@ -51,11 +51,6 @@ if(ENABLE_ZSTD)
list(APPEND EXTRA_LIBS ${LIBZSTD_LDFLAGS})
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# link with resolv lib on macOS
list(APPEND EXTRA_LIBS "resolv")
endif()
if(ENABLE_NCURSES)
subdirs(normal)
endif()
+1 -13
View File
@@ -231,12 +231,7 @@ gui_main_init (void)
gui_term_cols, gui_term_lines, 100, 100))
{
gui_current_window = gui_windows;
if (CONFIG_STRING(config_look_window_title)
&& CONFIG_STRING(config_look_window_title)[0])
{
gui_window_set_title (CONFIG_STRING(config_look_window_title));
}
gui_window_set_title (CONFIG_STRING(config_look_window_title));
}
/* switch to buffer */
@@ -526,13 +521,6 @@ gui_main_end (int clean_exit)
/* delete global history */
gui_history_global_free ();
/* reset title */
if (CONFIG_STRING(config_look_window_title)
&& CONFIG_STRING(config_look_window_title)[0])
{
gui_window_set_title (NULL);
}
/* end color */
gui_color_end ();
+8 -8
View File
@@ -2479,13 +2479,11 @@ gui_window_refresh_screen (int full_refresh)
refresh ();
gui_window_read_terminal_size ();
refresh ();
gui_window_set_title (
(CONFIG_STRING(config_look_window_title)
&& CONFIG_STRING(config_look_window_title)[0]) ?
CONFIG_STRING(config_look_window_title) : NULL);
}
gui_window_refresh_windows ();
gui_window_set_title (CONFIG_STRING(config_look_window_title));
}
/*
@@ -2573,15 +2571,17 @@ gui_window_set_title (const char *title)
{
char *new_title, *envterm, *envshell, *shell, *shellname;
envterm = getenv ("TERM");
if (!envterm)
if (!title || !title[0])
return;
new_title = (title && title[0]) ?
eval_expression (title, NULL, NULL, NULL) : NULL;
new_title = eval_expression (title, NULL, NULL, NULL);
if (!new_title)
return;
envterm = getenv ("TERM");
if (!envterm)
return;
if (strcmp (envterm, "sun-cmd") == 0)
{
printf ("\033]l%s\033\\", new_title);
+3 -6
View File
@@ -47,23 +47,20 @@ daemonize (void)
pid_t pid;
int fd, i;
printf (_("Running WeeChat in background..."));
printf (" ");
printf ("%s ", _("Running WeeChat in background..."));
pid = fork ();
if (pid < 0)
{
printf (_("fork error"));
printf ("\n");
printf ("%s\n", _("fork error"));
exit (EXIT_FAILURE);
}
if (pid > 0)
{
/* parent process */
printf (_("OK"));
printf ("\n");
printf ("%s\n", _("OK"));
exit (EXIT_SUCCESS);
}
+1
View File
@@ -31,6 +31,7 @@ set(LIB_GUI_CURSES_SRC
find_package(Ncurses)
if(NCURSES_FOUND)
add_definitions(${NCURSES_CFLAGS})
check_include_files(ncursesw/ncurses.h NCURSESW_HEADERS)
if(NCURSESW_HEADERS)
add_definitions(-DHAVE_NCURSESW_CURSES_H)
+5 -2
View File
@@ -2148,6 +2148,7 @@ gui_bar_item_focus_buffer_nicklist_cb (const void *pointer,
struct t_gui_nick_group *ptr_group;
struct t_gui_nick *ptr_nick;
int i, rc, bar_item_line;
unsigned long value;
const char *str_window, *str_buffer, *str_bar_item_line;
struct t_gui_window *window;
struct t_gui_buffer *buffer;
@@ -2165,9 +2166,10 @@ gui_bar_item_focus_buffer_nicklist_cb (const void *pointer,
str_window = hashtable_get (info, "_window");
if (str_window && str_window[0])
{
rc = sscanf (str_window, "%p", &window);
rc = sscanf (str_window, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return NULL;
window = (struct t_gui_window *)value;
}
else
{
@@ -2182,9 +2184,10 @@ gui_bar_item_focus_buffer_nicklist_cb (const void *pointer,
str_buffer = hashtable_get (info, "_buffer");
if (str_buffer && str_buffer[0])
{
rc = sscanf (str_buffer, "%p", &buffer);
rc = sscanf (str_buffer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return NULL;
buffer = (struct t_gui_buffer *)value;
}
if (!buffer)
return NULL;
+3 -1
View File
@@ -1396,6 +1396,7 @@ gui_chat_hsignal_quote_line_cb (const void *pointer, void *data,
{
const char *ptr_date, *ptr_date_usec, *line, *prefix, *ptr_prefix, *message;
long long number;
unsigned long value;
struct timeval tv;
struct t_gui_line *ptr_line;
int is_nick, rc;
@@ -1440,9 +1441,10 @@ gui_chat_hsignal_quote_line_cb (const void *pointer, void *data,
line = hashtable_get (hashtable, "_chat_line");
if (line && line[0])
{
rc = sscanf (line, "%p", &ptr_line);
rc = sscanf (line, "%lx", &value);
if ((rc != EOF) && (rc != 0))
{
ptr_line = (struct t_gui_line *)value;
if (gui_line_search_tag_starting_with (ptr_line, "prefix_nick"))
is_nick = 1;
}
+4 -3
View File
@@ -356,6 +356,7 @@ gui_history_hdata_history_update_cb (void *data,
struct t_gui_history *ptr_history;
struct t_gui_buffer *ptr_buffer;
const char *text, *buffer;
unsigned long value;
int rc;
/* make C compiler happy */
@@ -384,9 +385,9 @@ gui_history_hdata_history_update_cb (void *data,
buffer = hashtable_get (hashtable, "buffer");
if (buffer)
{
rc = sscanf (buffer, "%p", &ptr_buffer);
if ((rc == EOF) || (rc == 0))
ptr_buffer = NULL;
rc = sscanf (buffer, "%lx", &value);
if ((rc != EOF) && (rc != 0))
ptr_buffer = (struct t_gui_buffer *)value;
}
}
if (ptr_buffer)
+14 -13
View File
@@ -1213,12 +1213,12 @@ gui_key_set_score (struct t_gui_key *key)
}
/*
* Checks if a key is safe or not: a safe key begins always with the "meta" or
* "ctrl" code (except "@" allowed in cursor/mouse contexts).
* Checks if a key is safe or not: a safe key should begin with the "meta" or
* "ctrl" code (there are exceptions).
*
* Returns:
* 1: key is safe
* 0: key is NOT safe
* 1: key is safe for the given context
* 0: key is NOT safe for the given context
*/
int
@@ -1229,13 +1229,13 @@ gui_key_is_safe (int context, const char *key)
if (!key || !key[0])
return 0;
/* "@" is allowed at beginning for cursor/mouse contexts */
if ((key[0] == '@')
&& ((context == GUI_KEY_CONTEXT_CURSOR)
|| (context == GUI_KEY_CONTEXT_MOUSE)))
{
/* all keys are safe in cursor mode */
if (context == GUI_KEY_CONTEXT_CURSOR)
return 1;
/* "@" is allowed at beginning for mouse context */
if ((key[0] == '@') && (context == GUI_KEY_CONTEXT_MOUSE))
return 1;
}
if (strncmp (key, "comma", 5) == 0)
return 0;
@@ -2042,6 +2042,7 @@ gui_key_focus_command (const char *key, int context,
{
struct t_gui_key *ptr_key;
int matching, debug, rc;
unsigned long value;
char *command, **commands, **ptr_command;
const char *str_buffer;
struct t_hashtable *hashtable;
@@ -2099,9 +2100,9 @@ gui_key_focus_command (const char *key, int context,
str_buffer = hashtable_get (hashtable, "_buffer");
if (str_buffer && str_buffer[0])
{
rc = sscanf (str_buffer, "%p", &ptr_buffer);
if ((rc == EOF) || (rc == 0))
ptr_buffer = gui_current_window->buffer;
rc = sscanf (str_buffer, "%lx", &value);
if ((rc != EOF) && (rc != 0))
ptr_buffer = (struct t_gui_buffer *)value;
}
if (!ptr_buffer)
continue;
+3 -1
View File
@@ -1671,6 +1671,7 @@ gui_line_hook_update (struct t_gui_line *line,
{
const char *ptr_value, *ptr_value2;
struct t_gui_buffer *ptr_buffer;
unsigned long value_pointer;
long value;
char *error, *new_message, *pos_newline;
int rc, tags_updated, notify_level_updated, highlight_updated;
@@ -1704,7 +1705,8 @@ gui_line_hook_update (struct t_gui_line *line,
{
if ((ptr_value2[0] == '0') && (ptr_value2[1] == 'x'))
{
rc = sscanf (ptr_value2, "%p", &ptr_buffer);
rc = sscanf (ptr_value2 + 2, "%lx", &value_pointer);
ptr_buffer = (struct t_gui_buffer *)value_pointer;
if ((rc != EOF) && (rc >= 1)
&& gui_chat_buffer_valid (ptr_buffer, line->data->buffer->type))
{
+6 -2
View File
@@ -122,8 +122,12 @@ else()
endif()
if(ENABLE_SCRIPTS AND ENABLE_PYTHON)
find_package(Python)
if(PYTHON_FOUND)
if(CMAKE_VERSION VERSION_LESS "3.18.0")
find_package(Python 3.0 COMPONENTS Development)
else()
find_package(Python 3.0 COMPONENTS Development.Embed)
endif()
if(Python_FOUND)
add_subdirectory(python)
else()
message(SEND_ERROR "Python not found")
+3 -1
View File
@@ -333,6 +333,7 @@ buflist_hsignal_cb (const void *pointer, void *data, const char *signal,
struct t_gui_buffer *ptr_buffer;
char *error, str_command[1024];
long number, number2;
unsigned long value;
int rc, current_buffer_number;
/* make C compiler happy */
@@ -352,9 +353,10 @@ buflist_hsignal_cb (const void *pointer, void *data, const char *signal,
return WEECHAT_RC_OK;
}
rc = sscanf (ptr_pointer, "%p", &ptr_buffer);
rc = sscanf (ptr_pointer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return WEECHAT_RC_OK;
ptr_buffer = (struct t_gui_buffer *)value;
error = NULL;
number = strtol (ptr_number, &error, 10);
+7 -2
View File
@@ -41,6 +41,7 @@ fset_mouse_focus_cb (const void *pointer, void *data, struct t_hashtable *info)
{
const char *buffer;
int rc, format_number;
unsigned long value;
struct t_gui_buffer *ptr_buffer;
long y, option_index;
char *error, str_value[128];
@@ -57,10 +58,12 @@ fset_mouse_focus_cb (const void *pointer, void *data, struct t_hashtable *info)
if (!buffer)
return info;
rc = sscanf (buffer, "%p", &ptr_buffer);
rc = sscanf (buffer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return info;
ptr_buffer = (struct t_gui_buffer *)value;
if (!ptr_buffer || (ptr_buffer != fset_buffer))
return info;
@@ -184,6 +187,7 @@ fset_mouse_hsignal_cb (const void *pointer, void *data, const char *signal,
const char *ptr_key, *ptr_fset_option_pointer;
char str_command[1024];
struct t_fset_option *ptr_fset_option;
unsigned long value;
int rc, distance, num_options, min_y, max_y, i;
int chat_line_x, chat_line_x2, y, y2, chat_line_y, chat_line_y2;
int option_index, option_index2, index1, index2;
@@ -202,9 +206,10 @@ fset_mouse_hsignal_cb (const void *pointer, void *data, const char *signal,
if (!ptr_key || !ptr_fset_option_pointer)
return WEECHAT_RC_OK;
rc = sscanf (ptr_fset_option_pointer, "%p", &ptr_fset_option);
rc = sscanf (ptr_fset_option_pointer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return WEECHAT_RC_OK;
ptr_fset_option = (struct t_fset_option *)value;
if (!ptr_fset_option)
return WEECHAT_RC_OK;
+4 -1
View File
@@ -624,6 +624,7 @@ struct t_hashtable *
irc_bar_item_focus_buffer_nicklist (const void *pointer, void *data,
struct t_hashtable *info)
{
unsigned long value;
int rc;
struct t_gui_buffer *buffer;
struct t_irc_nick *ptr_nick;
@@ -634,10 +635,12 @@ irc_bar_item_focus_buffer_nicklist (const void *pointer, void *data,
if (!str_buffer || !str_buffer[0])
return NULL;
rc = sscanf (str_buffer, "%p", &buffer);
rc = sscanf (str_buffer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return NULL;
buffer = (struct t_gui_buffer *)value;
IRC_BUFFER_GET_SERVER_CHANNEL(buffer);
/* make C compiler happy */
+3 -3
View File
@@ -855,7 +855,7 @@ irc_ctcp_recv_dcc (struct t_irc_protocol_ctxt *ctxt, const char *arguments)
* double-quote
*/
pos = strrchr (pos_file, '"');
if (!pos || (pos == pos_file))
if (!pos || (pos == pos_file) || !pos[1])
{
weechat_printf (
ctxt->server->buffer,
@@ -1030,7 +1030,7 @@ irc_ctcp_recv_dcc (struct t_irc_protocol_ctxt *ctxt, const char *arguments)
* double-quote
*/
pos = strrchr (pos_file, '"');
if (!pos || (pos == pos_file))
if (!pos || (pos == pos_file) || !pos[1])
{
weechat_printf (
ctxt->server->buffer,
@@ -1174,7 +1174,7 @@ irc_ctcp_recv_dcc (struct t_irc_protocol_ctxt *ctxt, const char *arguments)
* double-quote
*/
pos = strrchr (pos_file, '"');
if (!pos || (pos == pos_file))
if (!pos || (pos == pos_file) || !pos[1])
{
weechat_printf (
ctxt->server->buffer,
+3 -1
View File
@@ -1311,6 +1311,7 @@ irc_list_mouse_hsignal_cb (const void *pointer, void *data, const char *signal,
{
const char *ptr_key, *ptr_chat_line_y, *ptr_buffer_pointer;
struct t_gui_buffer *ptr_buffer;
unsigned long value;
char str_command[1024];
int rc;
@@ -1326,9 +1327,10 @@ irc_list_mouse_hsignal_cb (const void *pointer, void *data, const char *signal,
if (!ptr_key || !ptr_buffer_pointer || !ptr_chat_line_y)
return WEECHAT_RC_OK;
rc = sscanf (ptr_buffer_pointer, "%p", &ptr_buffer);
rc = sscanf (ptr_buffer_pointer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return WEECHAT_RC_OK;
ptr_buffer = (struct t_gui_buffer *)value;
if (!ptr_buffer)
return WEECHAT_RC_OK;
+20 -12
View File
@@ -2393,8 +2393,7 @@ IRC_PROTOCOL_CALLBACK(nick)
}
else
{
if (!irc_ignore_check (ctxt->server, ptr_channel->name,
ctxt->nick, ctxt->host))
if (!ctxt->ignore_remove)
{
ptr_nick_speaking = ((weechat_config_boolean (irc_config_look_smart_filter))
&& (weechat_config_boolean (irc_config_look_smart_filter_nick))) ?
@@ -3401,7 +3400,7 @@ IRC_PROTOCOL_CALLBACK(quit)
if (ptr_nick
|| (irc_server_strcasecmp (ctxt->server, ptr_channel->name, ctxt->nick) == 0))
{
if (!irc_ignore_check (ctxt->server, ptr_channel->name, ctxt->nick, ctxt->host))
if (!ctxt->ignore_remove)
{
/* display quit message */
ptr_nick_speaking = NULL;
@@ -4144,16 +4143,25 @@ IRC_PROTOCOL_CALLBACK(005)
if (ctxt->server->isupport)
{
length_isupport = strlen (ctxt->server->isupport);
isupport2 = realloc (ctxt->server->isupport,
length_isupport + /* existing */
1 + /* space */
length + /* new */
1);
if (isupport2)
/*
* limit the size of the accumulated ISUPPORT data: once the
* maximum is reached, ignore the extra data (protection against a
* server flooding "005" messages, which would consume all the
* memory)
*/
if (length_isupport + 1 + length < IRC_SERVER_ISUPPORT_MAX_LENGTH)
{
ctxt->server->isupport = isupport2;
strcat (ctxt->server->isupport, " ");
strcat (ctxt->server->isupport, str_info);
isupport2 = realloc (ctxt->server->isupport,
length_isupport + /* existing */
1 + /* space */
length + /* new */
1);
if (isupport2)
{
ctxt->server->isupport = isupport2;
strcat (ctxt->server->isupport, " ");
strcat (ctxt->server->isupport, str_info);
}
}
}
else
+8
View File
@@ -3409,6 +3409,14 @@ irc_server_msgq_add_unterminated (struct t_irc_server *server,
if (server->unterminated_message)
{
/*
* limit the size of the unterminated message: once the maximum is
* reached, ignore the extra data (protection against a server sending
* a very long line without end-of-line, which would consume all the
* memory)
*/
if (strlen (server->unterminated_message) >= IRC_SERVER_RECV_MSG_MAX_LENGTH)
return;
unterminated_message2 =
realloc (server->unterminated_message,
(strlen (server->unterminated_message) +
+9
View File
@@ -142,6 +142,15 @@ enum t_irc_server_option
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_BYTES 4096
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_LINES 24
/*
* maximum length of an unterminated message (a received line without
* end-of-line) and of the accumulated "005" (ISUPPORT) data; these limits
* protect against a server sending a huge amount of data without end-of-line
* (or a flood of "005" messages), which would consume all the memory
*/
#define IRC_SERVER_RECV_MSG_MAX_LENGTH (64 * 1024)
#define IRC_SERVER_ISUPPORT_MAX_LENGTH (64 * 1024)
/* casemapping (string comparisons for nicks/channels) */
enum t_irc_server_casemapping
{
+7 -10
View File
@@ -38,6 +38,7 @@ logger_info_log_file_cb (const void *pointer, void *data,
const char *arguments)
{
int rc;
unsigned long value;
struct t_gui_buffer *buffer;
struct t_logger_buffer *logger_buffer;
@@ -52,20 +53,16 @@ logger_info_log_file_cb (const void *pointer, void *data,
buffer = NULL;
if (strncmp (arguments, "0x", 2) == 0)
{
rc = sscanf (arguments, "%p", &buffer);
if ((rc != EOF) && (rc != 0) && buffer)
rc = sscanf (arguments, "%lx", &value);
if ((rc != EOF) && (rc != 0) && value)
{
if (!weechat_hdata_check_pointer (weechat_hdata_get ("buffer"),
NULL,
buffer))
if (weechat_hdata_check_pointer (weechat_hdata_get ("buffer"),
NULL,
(struct t_gui_buffer *)value))
{
buffer = NULL;
buffer = (struct t_gui_buffer *)value;
}
}
else
{
buffer = NULL;
}
}
else
{
+1
View File
@@ -25,6 +25,7 @@ add_library(lua MODULE
set_target_properties(lua PROPERTIES PREFIX "")
if(LUA_FOUND)
add_definitions(${LUA_CFLAGS})
include_directories(${LUA_INCLUDE_DIRS})
target_link_libraries(lua ${LUA_LDFLAGS} weechat_plugins_scripts coverage_config)
endif()
+1 -1
View File
@@ -352,7 +352,7 @@ weechat_perl_exec (struct t_plugin_script *script,
if (weechat_asprintf (
&func,
"%s::%s",
(char *) ((script->interpreter) ? script->interpreter : perl_main)
(char *) ((script->interpreter) ? script->interpreter : perl_main),
function) < 0)
{
return NULL;
+3 -3
View File
@@ -405,7 +405,7 @@ plugin_script_str2ptr (struct t_weechat_plugin *weechat_plugin,
const char *script_name, const char *function_name,
const char *str_pointer)
{
void *pointer;
unsigned long value;
int rc;
struct t_gui_buffer *ptr_buffer;
@@ -415,9 +415,9 @@ plugin_script_str2ptr (struct t_weechat_plugin *weechat_plugin,
if ((str_pointer[0] != '0') || (str_pointer[1] != 'x'))
goto invalid;
rc = sscanf (str_pointer, "%p", &pointer);
rc = sscanf (str_pointer + 2, "%lx", &value);
if ((rc != EOF) && (rc >= 1))
return pointer;
return (void *)value;
invalid:
if ((weechat_plugin->debug >= 1) && script_name && function_name)
+1
View File
@@ -623,6 +623,7 @@ plugin_load (const char *filename, int init_plugin, int argc, char **argv)
new_plugin->strncasecmp = &string_strncasecmp;
new_plugin->strncasecmp_range = &string_strncasecmp_range;
new_plugin->strcmp_ignore_chars = &string_strcmp_ignore_chars;
new_plugin->string_memcmp_constant_time = &string_memcmp_constant_time;
new_plugin->strcasestr = &string_strcasestr;
new_plugin->strlen_screen = &gui_chat_strlen_screen;
new_plugin->string_match = &string_match;
+4 -2
View File
@@ -23,8 +23,10 @@ add_library(python MODULE
)
set_target_properties(python PROPERTIES PREFIX "")
if(PYTHON_FOUND)
target_link_libraries(python PkgConfig::PYTHON weechat_plugins_scripts coverage_config)
if(Python_FOUND)
include_directories(${Python_INCLUDE_DIRS})
add_definitions(${Python_DEFINITIONS})
target_link_libraries(python ${Python_LIBRARIES} weechat_plugins_scripts coverage_config)
endif()
install(TARGETS python LIBRARY DESTINATION "${WEECHAT_LIBDIR}/plugins")
+2 -10
View File
@@ -57,15 +57,11 @@
#define MSG_ADD_HDATA_TIME_USEC(__json_name, \
__var_name, __var_name_usec) \
time_value = weechat_hdata_time (hdata, pointer, __var_name); \
local_time = localtime (&time_value); \
time_value -= local_time->tm_gmtoff; \
local_time = localtime (&time_value); \
tv.tv_sec = mktime (local_time); \
tv.tv_sec = weechat_hdata_time (hdata, pointer, __var_name); \
tv.tv_usec = weechat_hdata_integer (hdata, pointer, \
__var_name_usec); \
weechat_util_strftimeval (str_time, sizeof (str_time), \
"%FT%T.%fZ", &tv); \
"%@%FT%T.%fZ", &tv); \
MSG_ADD_STR_BUF(__json_name, str_time);
#define MSG_ADD_HDATA_STR(__json_name, __var_name) \
@@ -487,9 +483,7 @@ relay_api_msg_line_data_to_json (struct t_gui_line_data *line_data,
const char *ptr_string;
char *string, str_time[256], str_var[64];
int i, tags_count;
time_t time_value;
struct timeval tv;
struct tm *local_time;
hdata = relay_hdata_line_data;
pointer = line_data;
@@ -792,9 +786,7 @@ relay_api_msg_hotlist_to_json (struct t_gui_hotlist *hotlist)
struct t_gui_hotlist *pointer;
struct t_gui_buffer *buffer;
cJSON *json, *json_count;
time_t time_value;
struct timeval tv;
struct tm *local_time;
char str_time[256], str_key[32];
int i, array_size;
long long buffer_id;
+2 -1
View File
@@ -31,6 +31,7 @@
#include "../../weechat-plugin.h"
#include "../relay.h"
#include "relay-irc.h"
#include "../relay-auth.h"
#include "../relay-buffer.h"
#include "../relay-client.h"
#include "../relay-config.h"
@@ -1699,7 +1700,7 @@ relay_irc_recv (struct t_relay_client *client, const char *data)
NULL, NULL, NULL);
if (password)
{
if (strcmp (password, pos_password) == 0)
if (relay_auth_password_equals (password, pos_password))
{
RELAY_IRC_DATA(client, password_ok) = 1;
weechat_hook_signal_send ("relay_client_auth_ok",
+93 -10
View File
@@ -100,6 +100,66 @@ relay_auth_generate_nonce (int size)
return nonce_hexa;
}
/*
* Compare two passwords for equality in constant time.
*
* HMAC both sides with a fresh random key, then compare the fixed-size
* MACs. This hides both the per-byte comparison and the password length
* from a timing-side-channel observer.
*
* Both messages are prefixed with a zero byte so empty passwords still
* produce a valid HMAC (the underlying crypto API rejects zero-length
* messages); the prefix is identical on both sides so equal inputs
* still yield equal MACs.
*
* Return:
* 1: passwords are equal
* 0: passwords are not equal (or an error occurred)
*/
int
relay_auth_password_equals (const char *password1, const char *password2)
{
unsigned char key[32];
char hmac1[64], hmac2[64];
char *buf1, *buf2;
int buf1_size, buf2_size, hmac1_size, hmac2_size, rc;
if (!password1 || !password2)
return 0;
rc = 0;
buf1_size = strlen (password1) + 1;
buf2_size = strlen (password2) + 1;
buf1 = malloc (buf1_size);
buf2 = malloc (buf2_size);
if (buf1 && buf2)
{
buf1[0] = 0;
memcpy (buf1 + 1, password1, buf1_size - 1);
buf2[0] = 0;
memcpy (buf2 + 1, password2, buf2_size - 1);
gcry_create_nonce (key, sizeof (key));
if (weechat_crypto_hmac (key, sizeof (key),
buf1, buf1_size,
"sha256",
hmac1, &hmac1_size)
&& weechat_crypto_hmac (key, sizeof (key),
buf2, buf2_size,
"sha256",
hmac2, &hmac2_size)
&& (hmac1_size == hmac2_size)
&& (weechat_string_memcmp_constant_time (
hmac1, hmac2, hmac1_size) == 0))
{
rc = 1;
}
}
free (buf1);
free (buf2);
return rc;
}
/*
* Checks if password received as plain text is valid.
*
@@ -125,7 +185,7 @@ relay_auth_check_password_plain (struct t_relay_client *client,
return -1;
}
return (strcmp (password, relay_password) == 0) ? 0 : -2;
return relay_auth_password_equals (password, relay_password) ? 0 : -2;
}
/*
@@ -345,8 +405,9 @@ relay_auth_check_hash_sha (const char *hash_algo,
const char *hash_sha,
const char *relay_password)
{
char *salt_password, hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
int rc, length, hash_size;
char *salt_password, *hash_sha_upper, hash[512 / 8];
char hash_hexa[((512 / 8) * 2) + 1];
int rc, length, hash_size, hash_hexa_len;
rc = 0;
@@ -364,10 +425,23 @@ relay_auth_check_hash_sha (const char *hash_algo,
hash_algo,
hash, &hash_size))
{
weechat_string_base_encode ("16", hash, hash_size,
hash_hexa);
if (weechat_strcasecmp (hash_hexa, hash_sha) == 0)
hash_hexa_len = weechat_string_base_encode ("16", hash, hash_size,
hash_hexa);
/*
* Compare in constant time to defeat timing attacks: the
* client-supplied hash is normalized to uppercase to match
* the output of base16 encoding, then compared byte-for-byte
* with no early exit.
*/
hash_sha_upper = weechat_string_toupper (hash_sha);
if (hash_sha_upper
&& ((int)strlen (hash_sha_upper) == hash_hexa_len)
&& (weechat_string_memcmp_constant_time (
hash_hexa, hash_sha_upper, hash_hexa_len) == 0))
{
rc = 1;
}
free (hash_sha_upper);
}
free (salt_password);
}
@@ -391,8 +465,8 @@ relay_auth_check_hash_pbkdf2 (const char *hash_pbkdf2_algo,
const char *hash_pbkdf2,
const char *relay_password)
{
char hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
int rc, hash_size;
char *hash_pbkdf2_upper, hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
int rc, hash_size, hash_hexa_len;
rc = 0;
@@ -405,9 +479,18 @@ relay_auth_check_hash_pbkdf2 (const char *hash_pbkdf2_algo,
iterations,
hash, &hash_size))
{
weechat_string_base_encode ("16", hash, hash_size, hash_hexa);
if (weechat_strcasecmp (hash_hexa, hash_pbkdf2) == 0)
hash_hexa_len = weechat_string_base_encode ("16", hash, hash_size,
hash_hexa);
/* see relay_auth_check_hash_sha for rationale */
hash_pbkdf2_upper = weechat_string_toupper (hash_pbkdf2);
if (hash_pbkdf2_upper
&& ((int)strlen (hash_pbkdf2_upper) == hash_hexa_len)
&& (weechat_string_memcmp_constant_time (
hash_hexa, hash_pbkdf2_upper, hash_hexa_len) == 0))
{
rc = 1;
}
free (hash_pbkdf2_upper);
}
}
+2
View File
@@ -37,6 +37,8 @@ extern char *relay_auth_password_hash_algo_name[];
extern int relay_auth_password_hash_algo_search (const char *name);
extern char *relay_auth_generate_nonce (int size);
extern int relay_auth_password_equals (const char *password1,
const char *password2);
extern int relay_auth_check_password_plain (struct t_relay_client *client,
const char *password,
const char *relay_password);
+22 -1
View File
@@ -487,6 +487,19 @@ relay_http_add_to_body (struct t_relay_http_request *request,
if (!partial_message || !*partial_message)
return;
/*
* reject the body if its announced length is too big: this prevents a
* client from forcing an unbounded allocation by announcing a huge
* "Content-Length"
*/
if (request->content_length > RELAY_HTTP_BODY_MAX_LENGTH)
{
free (*partial_message);
*partial_message = NULL;
request->status = RELAY_HTTP_END;
return;
}
num_bytes_missing = request->content_length
- request->body_size;
if (num_bytes_missing <= 0)
@@ -940,6 +953,14 @@ relay_http_recv (struct t_relay_client *client, const char *data)
if (client->partial_message)
{
/*
* limit the size of the partial message: once the maximum is reached,
* ignore the extra data (protection against a client sending a huge
* amount of data without any end-of-line and dribbling it, which would
* consume all the memory)
*/
if (strlen (client->partial_message) >= RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH)
return;
new_partial = realloc (client->partial_message,
strlen (client->partial_message) +
strlen (data) + 1);
@@ -1639,7 +1660,7 @@ relay_http_print_log_request (struct t_relay_http_request *request)
weechat_log_printf (" path_items. . . . . . . : %p", request->path_items);
if (request->path_items)
{
for (i = 0; request->path_items[0]; i++)
for (i = 0; request->path_items[i]; i++)
{
weechat_log_printf (" '%s'", request->path_items[i]);
}
+16
View File
@@ -53,6 +53,22 @@ enum t_relay_client_http_status
#define RELAY_HTTP_ERROR_NOT_FOUND "Resource not found"
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
/*
* maximum length of an HTTP request body: used as an upper bound on the
* "Content-Length" accepted from a client, to prevent a client from forcing
* an unbounded allocation by announcing a huge body
*/
#define RELAY_HTTP_BODY_MAX_LENGTH (8 * 1024 * 1024)
/*
* maximum length of the partial message accumulated while reading an HTTP
* request: once this limit is reached, the extra data is ignored; this
* protects against a client sending a huge amount of data without any
* end-of-line (an unterminated method or header line), which would consume
* all the memory
*/
#define RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH (8 * 1024 * 1024)
struct t_relay_http_request
{
enum t_relay_client_http_status status; /* HTTP status */
+29 -5
View File
@@ -530,7 +530,7 @@ relay_websocket_inflate (const void *data, size_t size, z_stream *strm,
int rc;
unsigned char append_bytes[4] = { 0x00, 0x00, 0xFF, 0xFF };
Bytef *data2, *dest, *dest2;
uLongf size2, dest_size;
uLongf size2, dest_size, new_size;
if (!data || (size == 0) || !strm || !size_decompressed)
return NULL;
@@ -547,8 +547,13 @@ relay_websocket_inflate (const void *data, size_t size, z_stream *strm,
memcpy (data2, data, size);
memcpy (data2 + size, append_bytes, sizeof (append_bytes));
/* estimate the decompressed size, by default 10 * size */
dest_size = 10 * size2;
/*
* estimate the decompressed size, by default 10 * size, capped to the
* maximum allowed size (also prevents an integer overflow on the
* multiplication)
*/
dest_size = (size2 > WEBSOCKET_INFLATE_MAX_SIZE / 10) ?
WEBSOCKET_INFLATE_MAX_SIZE : 10 * size2;
dest = malloc (dest_size);
if (!dest)
goto error;
@@ -577,8 +582,19 @@ relay_websocket_inflate (const void *data, size_t size, z_stream *strm,
&& (strm->avail_in > 0)))
{
/* output buffer is not large enough */
strm->avail_out += dest_size;
dest_size *= 2;
if (dest_size >= WEBSOCKET_INFLATE_MAX_SIZE)
{
/*
* decompressed data is too large: reject the frame
* (protection against a "deflate bomb")
*/
goto error;
}
/* double the buffer, capped to the maximum allowed size */
new_size = (dest_size > WEBSOCKET_INFLATE_MAX_SIZE / 2) ?
WEBSOCKET_INFLATE_MAX_SIZE : dest_size * 2;
strm->avail_out += (uInt)(new_size - dest_size);
dest_size = new_size;
dest2 = realloc (dest, dest_size);
if (!dest2)
goto error;
@@ -685,6 +701,14 @@ relay_websocket_decode_frame (const unsigned char *buffer,
index_buffer += length_frame_size;
}
/*
* reject the frame if its announced length is too big: this prevents
* a client from forcing an unbounded allocation (and unbounded
* accumulation of partial frames) by announcing a huge frame
*/
if (length_frame > WEBSOCKET_FRAME_MAX_LENGTH)
return 0;
if (masked_frame)
{
/* read mask (4 bytes) */
+15
View File
@@ -39,6 +39,21 @@
#define WEBSOCKET_SUB_PROTOCOL_API_WEECHAT "api.weechat"
/*
* maximum length of a websocket frame received from a client (or a remote
* WeeChat): used as an upper bound on the announced frame payload length, to
* prevent a client from forcing an unbounded allocation by announcing a huge
* frame and dribbling its payload
*/
#define WEBSOCKET_FRAME_MAX_LENGTH (8 * 1024 * 1024)
/*
* maximum size of a decompressed websocket frame (with "permessage-deflate"):
* used as an upper bound when inflating, to prevent a small compressed frame
* from decompressing to an unbounded amount of data ("deflate bomb")
*/
#define WEBSOCKET_INFLATE_MAX_SIZE (8 * 1024 * 1024)
struct t_relay_client;
struct t_relay_http_request;
+4 -1
View File
@@ -266,6 +266,7 @@ relay_modifier_input_text_display_cb (const void *pointer,
{
struct t_gui_buffer *ptr_buffer;
struct t_relay_remote *ptr_remote;
unsigned long value;
const char *ptr_input, *ptr_text_local, *ptr_text_remote;
char *text, *new_input;
int rc, input_get_any_user_data;
@@ -281,10 +282,12 @@ relay_modifier_input_text_display_cb (const void *pointer,
if (!relay_remotes)
return NULL;
rc = sscanf (modifier_data, "%p", &ptr_buffer);
rc = sscanf (modifier_data, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return NULL;
ptr_buffer = (struct t_gui_buffer *)value;
if (weechat_buffer_get_pointer (ptr_buffer, "plugin") != weechat_plugin)
return NULL;
@@ -588,6 +588,7 @@ relay_weechat_msg_add_hdata (struct t_relay_weechat_msg *msg,
char *path_returned;
const char *hdata_name, *array_size;
void *pointer, **path_pointers;
unsigned long value;
int rc, num_keys, num_path, i, type, pos_count, count, rc_sscanf;
uint32_t count32;
@@ -628,9 +629,10 @@ relay_weechat_msg_add_hdata (struct t_relay_weechat_msg *msg,
pos[0] = '\0';
if (strncmp (list_path[0], "0x", 2) == 0)
{
rc_sscanf = sscanf (list_path[0], "%p", &pointer);
rc_sscanf = sscanf (list_path[0], "%lx", &value);
if ((rc_sscanf != EOF) && (rc_sscanf != 0))
{
pointer = (void *)value;
if (!weechat_hdata_check_pointer (ptr_hdata_head, NULL, pointer))
{
if (weechat_relay_plugin->debug >= 1)
@@ -644,10 +646,6 @@ relay_weechat_msg_add_hdata (struct t_relay_weechat_msg *msg,
goto end;
}
}
else
{
pointer = NULL;
}
}
else
pointer = weechat_hdata_get_list (ptr_hdata_head, list_path[0]);
@@ -49,14 +49,17 @@ struct t_gui_buffer *
relay_weechat_protocol_get_buffer (const char *arg)
{
struct t_gui_buffer *ptr_buffer;
unsigned long value;
int rc;
ptr_buffer = NULL;
if (strncmp (arg, "0x", 2) == 0)
{
rc = sscanf (arg, "%p", &ptr_buffer);
if ((rc != EOF) && (rc != 0) && ptr_buffer)
rc = sscanf (arg, "%lx", &value);
if ((rc != EOF) && (rc != 0))
ptr_buffer = (struct t_gui_buffer *)value;
if (ptr_buffer)
{
if (!weechat_hdata_check_pointer (
relay_hdata_buffer,
@@ -67,10 +70,6 @@ relay_weechat_protocol_get_buffer (const char *arg)
ptr_buffer = NULL;
}
}
else
{
ptr_buffer = NULL;
}
}
else
ptr_buffer = weechat_buffer_search ("==", arg);
@@ -527,7 +526,7 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(info)
RELAY_WEECHAT_PROTOCOL_CALLBACK(infolist)
{
struct t_relay_weechat_msg *msg;
void *pointer;
unsigned long value;
char *args;
int rc;
@@ -536,17 +535,17 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(infolist)
msg = relay_weechat_msg_new (id);
if (msg)
{
pointer = NULL;
value = 0;
args = NULL;
if (argc > 1)
{
rc = sscanf (argv[1], "%p", &pointer);
rc = sscanf (argv[1], "%lx", &value);
if ((rc == EOF) || (rc == 0))
pointer = NULL;
value = 0;
if (argc > 2)
args = argv_eol[2];
}
relay_weechat_msg_add_infolist (msg, argv[0], pointer, args);
relay_weechat_msg_add_infolist (msg, argv[0], (void *)value, args);
relay_weechat_msg_send (client, msg);
relay_weechat_msg_free (msg);
}
+4 -1
View File
@@ -39,6 +39,7 @@ script_mouse_focus_chat_cb (const void *pointer, void *data,
{
const char *buffer;
int rc;
unsigned long value;
struct t_gui_buffer *ptr_buffer;
long x;
char *error, str_date[64];
@@ -56,10 +57,12 @@ script_mouse_focus_chat_cb (const void *pointer, void *data,
if (!buffer)
return info;
rc = sscanf (buffer, "%p", &ptr_buffer);
rc = sscanf (buffer, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return info;
ptr_buffer = (struct t_gui_buffer *)value;
if (!ptr_buffer || (ptr_buffer != script_buffer))
return info;
+4 -2
View File
@@ -37,6 +37,7 @@ spell_info_info_spell_dict_cb (const void *pointer, void *data,
const char *arguments)
{
int rc;
unsigned long value;
struct t_gui_buffer *buffer;
const char *buffer_full_name, *ptr_dict;
@@ -53,9 +54,10 @@ spell_info_info_spell_dict_cb (const void *pointer, void *data,
buffer_full_name = NULL;
if (strncmp (arguments, "0x", 2) == 0)
{
rc = sscanf (arguments, "%p", &buffer);
if ((rc != EOF) && (rc != 0) && buffer)
rc = sscanf (arguments, "%lx", &value);
if ((rc != EOF) && (rc != 0) && value)
{
buffer = (struct t_gui_buffer *)value;
if (weechat_hdata_check_pointer (weechat_hdata_get ("buffer"),
NULL, buffer))
{
+4 -1
View File
@@ -713,6 +713,7 @@ spell_modifier_cb (const void *pointer, void *data,
const char *modifier,
const char *modifier_data, const char *string)
{
unsigned long value;
struct t_gui_buffer *buffer;
struct t_spell_speller_buffer *ptr_speller_buffer;
char **result, *ptr_string, *ptr_string_orig, *pos_space;
@@ -735,10 +736,12 @@ spell_modifier_cb (const void *pointer, void *data,
if (!string)
return NULL;
rc = sscanf (modifier_data, "%p", &buffer);
rc = sscanf (modifier_data, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return NULL;
buffer = (struct t_gui_buffer *)value;
/* check text during search only if option is enabled */
if (weechat_buffer_get_integer (buffer, "text_search")
&& !weechat_config_boolean (spell_config_check_during_search))
+11 -11
View File
@@ -811,9 +811,9 @@ trigger_callback_modifier_cb (const void *pointer, void *data,
const char *ptr_string;
char *string_modified, *pos, *buffer_pointer;
char *str_tags, **tags, *prefix, *string_no_color;
unsigned long value;
int num_tags, rc;
void *ptr_irc_server, *ptr_irc_channel;
struct t_gui_buffer *ptr_buffer;
TRIGGER_CALLBACK_CB_INIT(NULL);
@@ -926,10 +926,10 @@ trigger_callback_modifier_cb (const void *pointer, void *data,
pos - modifier_data);
if (buffer_pointer)
{
rc = sscanf (buffer_pointer, "%p", &ptr_buffer);
rc = sscanf (buffer_pointer, "%lx", &value);
if ((rc != EOF) && (rc != 0))
{
ctx.buffer = ptr_buffer;
ctx.buffer = (struct t_gui_buffer *)value;
weechat_hashtable_set (
ctx.extra_vars,
"tg_plugin",
@@ -997,7 +997,7 @@ trigger_callback_line_cb (const void *pointer, void *data,
{
struct t_hashtable *hashtable;
struct t_weelist_item *ptr_item;
void *ptr;
unsigned long value;
const char *ptr_key, *ptr_value;
char **tags, *str_tags, *string_no_color;
int rc, num_tags;
@@ -1021,10 +1021,10 @@ trigger_callback_line_cb (const void *pointer, void *data,
ptr_value = weechat_hashtable_get (line, "buffer");
if (!ptr_value || (ptr_value[0] != '0') || (ptr_value[1] != 'x'))
goto end;
rc = sscanf (ptr_value, "%p", &ptr);
rc = sscanf (ptr_value + 2, "%lx", &value);
if ((rc == EOF) || (rc < 1))
goto end;
ctx.buffer = ptr;
ctx.buffer = (void *)value;
weechat_hashtable_set (ctx.pointers, "buffer", ctx.buffer);
ptr_value = weechat_hashtable_get (line, "tags");
@@ -1361,7 +1361,7 @@ trigger_callback_focus_cb (const void *pointer, void *data,
struct t_hashtable *info)
{
const char *ptr_value;
void *ptr;
unsigned long value;
int rc;
TRIGGER_CALLBACK_CB_INIT(info);
@@ -1375,16 +1375,16 @@ trigger_callback_focus_cb (const void *pointer, void *data,
ptr_value = weechat_hashtable_get (info, "_window");
if (ptr_value && ptr_value[0] && (strncmp (ptr_value, "0x", 2) == 0))
{
rc = sscanf (ptr_value, "%p", &ptr);
rc = sscanf (ptr_value + 2, "%lx", &value);
if ((rc != EOF) && (rc >= 1))
weechat_hashtable_set (ctx.pointers, "window", ptr);
weechat_hashtable_set (ctx.pointers, "window", (void *)value);
}
ptr_value = weechat_hashtable_get (info, "_buffer");
if (ptr_value && ptr_value[0] && (strncmp (ptr_value, "0x", 2) == 0))
{
rc = sscanf (ptr_value, "%p", &ptr);
rc = sscanf (ptr_value + 2, "%lx", &value);
if ((rc != EOF) && (rc >= 1))
weechat_hashtable_set (ctx.pointers, "buffer", ptr);
weechat_hashtable_set (ctx.pointers, "buffer", (void *)value);
}
/* execute the trigger (conditions, regex, command) */
+6 -2
View File
@@ -181,6 +181,7 @@ typing_input_text_for_buffer_modifier_cb (const void *pointer,
const char *string)
{
int rc, text_search;
unsigned long value;
const char *ptr_input_for_buffer;
struct t_gui_buffer *ptr_buffer;
struct t_typing_status *ptr_typing_status;
@@ -191,9 +192,10 @@ typing_input_text_for_buffer_modifier_cb (const void *pointer,
(void) modifier;
(void) string;
rc = sscanf (modifier_data, "%p", &ptr_buffer);
rc = sscanf (modifier_data, "%lx", &value);
if ((rc == EOF) || (rc == 0))
return NULL;
ptr_buffer = (struct t_gui_buffer *)value;
/* ignore any change in input if the user is searching text in the buffer */
text_search = weechat_buffer_get_integer (ptr_buffer, "text_search");
@@ -380,6 +382,7 @@ typing_typing_set_nick_signal_cb (const void *pointer, void *data,
{
char **items;
int num_items, rc, state, updated;
unsigned long value;
struct t_gui_buffer *ptr_buffer;
struct t_typing_status *ptr_typing_status;
@@ -394,9 +397,10 @@ typing_typing_set_nick_signal_cb (const void *pointer, void *data,
if (!items || (num_items != 3))
goto end;
rc = sscanf (items[0], "%p", &ptr_buffer);
rc = sscanf (items[0], "%lx", &value);
if ((rc == EOF) || (rc == 0))
goto end;
ptr_buffer = (struct t_gui_buffer *)value;
if (!ptr_buffer)
goto end;
+6 -1
View File
@@ -74,7 +74,7 @@ struct t_weelist_item;
* please change the date with current one; for a second change at same
* date, increment the 01, otherwise please keep 01.
*/
#define WEECHAT_PLUGIN_API_VERSION "20250215-01"
#define WEECHAT_PLUGIN_API_VERSION "20260530-01"
/* macros for defining plugin infos */
#define WEECHAT_PLUGIN_NAME(__name) \
@@ -346,6 +346,8 @@ struct t_weechat_plugin
int max, int range);
int (*strcmp_ignore_chars) (const char *string1, const char *string2,
const char *chars_ignored, int case_sensitive);
int (*string_memcmp_constant_time) (const void *area1, const void *area2,
size_t size);
const char *(*strcasestr) (const char *string, const char *search);
int (*strlen_screen) (const char *string);
int (*string_match) (const char *string, const char *mask,
@@ -1342,6 +1344,9 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
(weechat_plugin->strcmp_ignore_chars)(__string1, __string2, \
__chars_ignored, \
__case_sensitive)
#define weechat_string_memcmp_constant_time(__area1, __area2, __size) \
(weechat_plugin->string_memcmp_constant_time)(__area1, __area2, \
__size)
#define weechat_strcasestr(__string, __search) \
(weechat_plugin->strcasestr)(__string, __search)
#define weechat_strlen_screen(__string) \
+1 -1
View File
@@ -160,7 +160,7 @@ xfer_chat_recv_cb (const void *pointer, void *data, int fd)
{
ctcp_action = 0;
length = strlen (ptr_buf);
if (ptr_buf[length - 1] == '\r')
if ((length > 0) && (ptr_buf[length - 1] == '\r'))
{
ptr_buf[length - 1] = '\0';
length--;
+11 -3
View File
@@ -249,7 +249,7 @@ xfer_file_find_suffix (struct t_xfer *xfer)
void
xfer_file_find_filename (struct t_xfer *xfer)
{
char *dir_separator, *path;
char *dir_separator, *path, *nick;
struct t_hashtable *options;
if (!XFER_IS_FILE(xfer->type))
@@ -285,12 +285,20 @@ xfer_file_find_filename (struct t_xfer *xfer)
{
strcat (xfer->local_filename, dir_separator);
}
free (dir_separator);
if (weechat_config_boolean (xfer_config_file_use_nick_in_filename))
{
strcat (xfer->local_filename, xfer->remote_nick);
/*
* the remote nick comes from the server and can contain a directory
* separator: replace it so the nick cannot make the file be written
* outside the download directory
*/
nick = (dir_separator) ?
weechat_string_replace (xfer->remote_nick, dir_separator, "_") : NULL;
strcat (xfer->local_filename, (nick) ? nick : xfer->remote_nick);
free (nick);
strcat (xfer->local_filename, ".");
}
free (dir_separator);
strcat (xfer->local_filename, xfer->filename);
free (path);
+4 -1
View File
@@ -61,6 +61,7 @@ test_modifier_cb (const void *pointer, void *data,
char **items, *new_string;
const char *ptr_plugin, *ptr_tags, *ptr_msg;
int num_items, length, rc;
unsigned long value;
struct t_gui_buffer *ptr_buffer;
/* make C++ compiler happy */
@@ -81,10 +82,12 @@ test_modifier_cb (const void *pointer, void *data,
ptr_tags = (num_items >= 2) ? items[1] : NULL;
rc = sscanf (items[0], "%p", &ptr_buffer);
rc = sscanf (items[0], "%lx", &value);
if ((rc == EOF) || (rc == 0))
goto error;
ptr_buffer = (struct t_gui_buffer *)value;
ptr_plugin = gui_buffer_get_plugin_name (ptr_buffer);
if (!ptr_plugin)
goto error;
+1
View File
@@ -342,6 +342,7 @@ TEST(CoreCalc, Expression)
WEE_CHECK_CALC("0.0000000008", "1/1234567890");
WEE_CHECK_CALC("0.0000000001", "1/12345678901");
WEE_CHECK_CALC("0", "1/123456789012");
WEE_CHECK_CALC("1.2222222222", "1+0.22222222222222222222222222222222222");
/* expressions with parentheses */
WEE_CHECK_CALC("6", "((6))");
-1
View File
@@ -1035,7 +1035,6 @@ TEST(CoreEval, EvalExpression)
WEE_CHECK_EVAL("", "${buffer[].full_name}");
WEE_CHECK_EVAL("", "${buffer[0x0].full_name}");
WEE_CHECK_EVAL("", "${buffer[0x1].full_name}");
WEE_CHECK_EVAL("", "${buffer[0xZ].full_name}");
WEE_CHECK_EVAL("", "${buffer[unknown_list].full_name}");
WEE_CHECK_EVAL("", "${unknown_pointer}");
WEE_CHECK_EVAL("", "${my_null_pointer}");
+34
View File
@@ -798,6 +798,38 @@ TEST(CoreString, StringComparison)
LONGS_EQUAL(-2, string_strcmp_ignore_chars ("è", "ê", "", 1));
}
/*
* Tests functions:
* string_memcmp_constant_time
*/
TEST(CoreString, MemcmpConstantTime)
{
/* NULL handling */
LONGS_EQUAL(0, string_memcmp_constant_time (NULL, NULL, 0));
LONGS_EQUAL(0, string_memcmp_constant_time (NULL, NULL, 4));
LONGS_EQUAL(1, string_memcmp_constant_time (NULL, "abcd", 4));
LONGS_EQUAL(1, string_memcmp_constant_time ("abcd", NULL, 4));
/* zero-size compare always equal */
LONGS_EQUAL(0, string_memcmp_constant_time ("", "", 0));
LONGS_EQUAL(0, string_memcmp_constant_time ("abc", "xyz", 0));
/* equal areas */
LONGS_EQUAL(0, string_memcmp_constant_time ("abcd", "abcd", 4));
LONGS_EQUAL(0, string_memcmp_constant_time ("\x00\x01\x02\xff",
"\x00\x01\x02\xff", 4));
/* differing areas (first / middle / last byte) */
LONGS_EQUAL(1, string_memcmp_constant_time ("Xbcd", "abcd", 4));
LONGS_EQUAL(1, string_memcmp_constant_time ("aXcd", "abcd", 4));
LONGS_EQUAL(1, string_memcmp_constant_time ("abcX", "abcd", 4));
LONGS_EQUAL(1, string_memcmp_constant_time ("abcd", "abce", 4));
/* only compares "size" bytes, ignores trailing content */
LONGS_EQUAL(0, string_memcmp_constant_time ("abcd", "abcz", 3));
}
/*
* Tests functions:
* string_strcasestr
@@ -1420,6 +1452,8 @@ TEST(CoreString, Replace)
WEE_TEST_STR(NULL, string_replace ("string", NULL, "replace"));
WEE_TEST_STR(NULL, string_replace (NULL, "search", "replace"));
WEE_TEST_STR("test abc def", string_replace("test abc def", "", "xxx"));
WEE_TEST_STR("test abc def", string_replace("test abc def", "xyz", "xxx"));
WEE_TEST_STR("test xxx def", string_replace("test abc def", "abc", "xxx"));
WEE_TEST_STR("xxx test xxx def xxx",
+10
View File
@@ -185,6 +185,11 @@ TEST(CoreUtil, Strftimeval)
"%H:%M:%S", &tv));
STRCMP_EQUAL("10:29:09", str_time);
strcpy (str_time, "test");
LONGS_EQUAL(8, util_strftimeval (str_time, sizeof (str_time),
"%@%H:%M:%S", &tv));
STRCMP_EQUAL("10:29:09", str_time);
strcpy (str_time, "test");
LONGS_EQUAL(19, util_strftimeval (str_time, sizeof (str_time),
"%Y-%m-%d %H:%M:%S", &tv));
@@ -537,4 +542,9 @@ TEST(CoreUtil, VersionNumber)
LONGS_EQUAL(0x01010100, util_version_number ("1.1.1"));
LONGS_EQUAL(0x01010200, util_version_number ("1.1.2"));
LONGS_EQUAL(0x01020304, util_version_number ("1.2.3.4"));
LONGS_EQUAL(0x7EFFFFFF, util_version_number ("126.255.255.255"));
LONGS_EQUAL(0x7FFFFFFF, util_version_number ("127.255.255.255"));
LONGS_EQUAL(0x7FFFFFFF, util_version_number ("128.255.255.255"));
LONGS_EQUAL(0x7FFFFFFF, util_version_number ("255.255.255.255"));
LONGS_EQUAL(0x7FFFFFFF, util_version_number ("999999999.999999999.999999999.999999999"));;
}
+39 -1
View File
@@ -303,7 +303,7 @@ TEST_GROUP(IrcProtocolWithServer)
void server_recv (const char *command)
{
char str_command[4096];
char str_command[8192];
record_start ();
arraylist_clear (sent_messages);
@@ -3845,6 +3845,44 @@ TEST(IrcProtocolWithServer, 005_full)
STRCMP_EQUAL(IRC_MSG_005 " " IRC_MSG_005, ptr_server->isupport);
}
/*
* Tests functions:
* irc_protocol_cb_005 (accumulated ISUPPORT is bounded)
*/
TEST(IrcProtocolWithServer, 005_limit)
{
char str_msg[4096], str_value[3500];
size_t length1, length2;
int i;
SRV_INIT;
memset (str_value, 'X', sizeof (str_value) - 1);
str_value[sizeof (str_value) - 1] = '\0';
snprintf (str_msg, sizeof (str_msg),
":server 005 alice TEST=%s :are supported", str_value);
/* flood the server with "005" messages */
for (i = 0; i < 100; i++)
{
server_recv (str_msg);
}
CHECK(ptr_server->isupport);
length1 = strlen (ptr_server->isupport);
/* the accumulated ISUPPORT data must be bounded */
CHECK(length1 <= IRC_SERVER_ISUPPORT_MAX_LENGTH + sizeof (str_value));
/* receiving more "005" messages must not grow it any further */
for (i = 0; i < 100; i++)
{
server_recv (str_msg);
}
length2 = strlen (ptr_server->isupport);
LONGS_EQUAL(length1, length2);
}
/*
* Tests functions:
* irc_protocol_cb_005 (infos from server, multiple messages)
@@ -63,6 +63,49 @@ TEST(IrcServer, Valid)
irc_server_free (server);
}
/*
* Tests functions:
* irc_server_msgq_add_unterminated (via irc_server_msgq_add_buffer)
*
* Check that data received without any end-of-line does not grow the
* unterminated message buffer without limit.
*/
TEST(IrcServer, MsgqAddBufferLimit)
{
struct t_irc_server *server;
char chunk[4097];
int i;
size_t length1, length2;
server = irc_server_alloc ("server_msgq");
CHECK(server);
memset (chunk, 'a', sizeof (chunk) - 1);
chunk[sizeof (chunk) - 1] = '\0';
/* feed a lot of data with no end-of-line */
for (i = 0; i < 100; i++)
{
irc_server_msgq_add_buffer (server, chunk);
}
CHECK(server->unterminated_message);
length1 = strlen (server->unterminated_message);
/* the buffer must be bounded (not ~400 KB) */
CHECK(length1 <= IRC_SERVER_RECV_MSG_MAX_LENGTH + sizeof (chunk));
/* feeding more data must not grow the buffer any further */
for (i = 0; i < 100; i++)
{
irc_server_msgq_add_buffer (server, chunk);
}
length2 = strlen (server->unterminated_message);
LONGS_EQUAL(length1, length2);
irc_server_free (server);
}
/*
* Tests functions:
* irc_server_search
@@ -417,12 +417,12 @@ TEST(RelayApiMsg, LinesToJson)
gmtime_r (&(gui_buffers->own_lines->last_line->prev_line->data->date), &gm_time);
tv.tv_sec = mktime (&gm_time);
tv.tv_usec = gui_buffers->own_lines->last_line->prev_line->data->date_usec;
util_strftimeval (str_date, sizeof (str_date), "%FT%T.%fZ", &tv);
util_strftimeval (str_date, sizeof (str_date), "%@%FT%T.%fZ", &tv);
WEE_CHECK_OBJ_STR(str_date, json_line, "date");
gmtime_r (&(gui_buffers->own_lines->last_line->prev_line->data->date_printed), &gm_time);
tv.tv_sec = mktime (&gm_time);
tv.tv_usec = gui_buffers->own_lines->last_line->prev_line->data->date_usec_printed;
util_strftimeval (str_date, sizeof (str_date), "%FT%T.%fZ", &tv);
util_strftimeval (str_date, sizeof (str_date), "%@%FT%T.%fZ", &tv);
WEE_CHECK_OBJ_STR(str_date, json_line, "date_printed");
WEE_CHECK_OBJ_BOOL(0, json_line, "highlight");
WEE_CHECK_OBJ_STR("nick1", json_line, "prefix");
@@ -453,12 +453,12 @@ TEST(RelayApiMsg, LinesToJson)
gmtime_r (&(gui_buffers->own_lines->last_line->data->date), &gm_time);
tv.tv_sec = mktime (&gm_time);
tv.tv_usec = gui_buffers->own_lines->last_line->data->date_usec;
util_strftimeval (str_date, sizeof (str_date), "%FT%T.%fZ", &tv);
util_strftimeval (str_date, sizeof (str_date), "%@%FT%T.%fZ", &tv);
WEE_CHECK_OBJ_STR(str_date, json_line, "date");
gmtime_r (&(gui_buffers->own_lines->last_line->data->date_printed), &gm_time);
tv.tv_sec = mktime (&gm_time);
tv.tv_usec = gui_buffers->own_lines->last_line->data->date_usec_printed;
util_strftimeval (str_date, sizeof (str_date), "%FT%T.%fZ", &tv);
util_strftimeval (str_date, sizeof (str_date), "%@%FT%T.%fZ", &tv);
WEE_CHECK_OBJ_STR(str_date, json_line, "date_printed");
WEE_CHECK_OBJ_BOOL(0, json_line, "highlight");
WEE_CHECK_OBJ_STR("", json_line, "prefix");
@@ -624,7 +624,7 @@ TEST(RelayApiMsg, HotlistToJson)
gmtime_r (&time_value, &gm_time);
tv.tv_sec = mktime (&gm_time);
tv.tv_usec = hdata_integer (relay_hdata_hotlist, gui_hotlist, "time_usec");
util_strftimeval (str_date, sizeof (str_date), "%FT%T.%fZ", &tv);
util_strftimeval (str_date, sizeof (str_date), "%@%FT%T.%fZ", &tv);
WEE_CHECK_OBJ_STR(str_date, json, "date");
WEE_CHECK_OBJ_NUM(gui_buffers->id, json, "buffer_id");
json_count = cJSON_GetObjectItem (json, "count");
@@ -107,6 +107,31 @@ TEST(RelayAuth, GenerateNonce)
free (nonce);
}
/*
* Tests functions:
* relay_auth_password_equals
*/
TEST(RelayAuth, PasswordEquals)
{
/* invalid arguments */
LONGS_EQUAL(0, relay_auth_password_equals (NULL, NULL));
LONGS_EQUAL(0, relay_auth_password_equals ("abcd", NULL));
LONGS_EQUAL(0, relay_auth_password_equals (NULL, "abcd"));
/* different passwords */
LONGS_EQUAL(0, relay_auth_password_equals ("test", "password"));
LONGS_EQUAL(0, relay_auth_password_equals ("Password", "password"));
LONGS_EQUAL(0, relay_auth_password_equals ("", "password"));
LONGS_EQUAL(0, relay_auth_password_equals ("password", ""));
/* equal passwords */
LONGS_EQUAL(1, relay_auth_password_equals ("", ""));
LONGS_EQUAL(1, relay_auth_password_equals ("password", "password"));
LONGS_EQUAL(1, relay_auth_password_equals ("a really long password with spaces",
"a really long password with spaces"));
}
/*
* Tests functions:
* relay_auth_check_password_plain
@@ -159,6 +159,35 @@ TEST(RelayHttp, RequestAllocReinitFree)
relay_http_request_free (request);
}
/*
* Tests functions:
* relay_http_add_to_body (body too large is rejected)
*/
TEST(RelayHttp, AddToBodyLimit)
{
struct t_relay_http_request *request;
char *partial;
request = relay_http_request_alloc ();
CHECK(request);
/* announce a body larger than the maximum allowed */
request->status = RELAY_HTTP_BODY;
request->content_length = RELAY_HTTP_BODY_MAX_LENGTH + 1;
partial = strdup ("some body data");
relay_http_add_to_body (request, &partial);
/* the body must be rejected: nothing allocated, request ended */
POINTERS_EQUAL(NULL, request->body);
LONGS_EQUAL(0, request->body_size);
POINTERS_EQUAL(NULL, partial);
LONGS_EQUAL(RELAY_HTTP_END, request->status);
relay_http_request_free (request);
}
/*
* Tests functions:
* relay_http_url_decode
@@ -464,6 +464,41 @@ TEST(RelayWebsocket, Inflate)
free (payload_comp);
relay_websocket_deflate_free (ws_deflate);
/*
* protection against "deflate bomb": a small compressed frame that
* decompresses to more than WEBSOCKET_INFLATE_MAX_SIZE must be rejected
* (relay_websocket_inflate returns NULL)
*/
ws_deflate = relay_websocket_deflate_alloc ();
CHECK(ws_deflate);
ws_deflate->window_bits_deflate = 15;
ws_deflate->window_bits_inflate = 15;
ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_deflate));
CHECK(ws_deflate->strm_deflate);
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_deflate (ws_deflate));
ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof (*ws_deflate->strm_inflate));
CHECK(ws_deflate->strm_inflate);
LONGS_EQUAL(1, relay_websocket_deflate_init_stream_inflate (ws_deflate));
/* highly compressible payload that decompresses past the maximum size */
size_t bomb_size = WEBSOCKET_INFLATE_MAX_SIZE + (1024 * 1024);
char *bomb = (char *)calloc (1, bomb_size);
CHECK(bomb);
payload_comp = (char *)relay_websocket_deflate (bomb, bomb_size,
ws_deflate->strm_deflate, &size_comp);
CHECK(payload_comp);
CHECK(size_comp < bomb_size);
payload_decomp = (char *)relay_websocket_inflate (payload_comp, size_comp,
ws_deflate->strm_inflate, &size_decomp);
POINTERS_EQUAL(NULL, payload_decomp);
free (payload_comp);
free (bomb);
relay_websocket_deflate_free (ws_deflate);
}
/*
@@ -473,7 +508,44 @@ TEST(RelayWebsocket, Inflate)
TEST(RelayWebsocket, DecodeFrame)
{
/* TODO: write tests */
struct t_relay_websocket_frame *frames;
char *partial_ws_frame;
int num_frames, partial_ws_frame_size;
/* small unmasked binary frame with payload "hello" */
unsigned char frame_ok[7] = { 0x82, 0x05, 'h', 'e', 'l', 'l', 'o' };
/* masked frame announcing a 1 GB payload (64-bit length field) */
unsigned char frame_too_big[10] = {
0x82, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
};
/* a valid small frame is decoded */
frames = NULL;
num_frames = 0;
partial_ws_frame = NULL;
partial_ws_frame_size = 0;
LONGS_EQUAL(1, relay_websocket_decode_frame (
frame_ok, sizeof (frame_ok), 0, NULL,
&frames, &num_frames, &partial_ws_frame,
&partial_ws_frame_size));
LONGS_EQUAL(1, num_frames);
CHECK(frames);
LONGS_EQUAL(5, frames[0].payload_size);
MEMCMP_EQUAL("hello", frames[0].payload, 5);
free (frames[0].payload);
free (frames);
free (partial_ws_frame);
/* a frame announcing an oversized payload is rejected (return 0) */
frames = NULL;
num_frames = 0;
partial_ws_frame = NULL;
partial_ws_frame_size = 0;
LONGS_EQUAL(0, relay_websocket_decode_frame (
frame_too_big, sizeof (frame_too_big), 1, NULL,
&frames, &num_frames, &partial_ws_frame,
&partial_ws_frame_size));
free (frames);
free (partial_ws_frame);
}
/*
+2 -2
View File
@@ -39,8 +39,8 @@
# devel-number the devel version as hex number ("0x04010000" for "4.1.0-dev")
#
weechat_stable="4.6.0"
weechat_devel="4.6.0"
weechat_stable="4.6.3"
weechat_devel="4.6.4-dev"
stable_major=$(echo "${weechat_stable}" | cut -d"." -f1)
stable_minor=$(echo "${weechat_stable}" | cut -d"." -f2)