39 Commits

Author SHA1 Message Date
Steffen Jaeckel
541c22cb13 Allow configuring compression level
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-11-18 10:13:43 +01:00
Steffen Jaeckel
06f2ba19b4 Introduce generic xmpp_conn_set_*() API
Instead of having a multitude of setter API functions for configuration
options, provide generic ones for the different types we have.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-11-18 10:13:43 +01:00
ArtSin
5690c4ed89 Add long tests and _MIN/_MAX to test_snprintf 2024-10-23 20:15:57 +04:00
ArtSin
62953e9ecf Change int_nums to int in test_snprintf
All format specifiers in `int_fmt` are for `int`, not `long`, and all numbers
in `int_nums` fit into `int`.
2024-10-23 13:55:44 +04:00
Steffen Jaeckel
5142eea2eb SSL_get_peer_certificate() is deprecated since OpenSSL 3.0
Unfortunately OpenSSL didn't implement a warning for deprecated macros, so
this wasn't discovered until now.

Discovered in [0].

OpenSSL patch to improve the situation proposed in [1].

[0] https://github.com/strophe/libstrophe/discussions/244
[1] https://github.com/openssl/openssl/pull/24296

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-05-28 10:18:44 +02:00
Steffen Jaeckel
5dd9e4b0e0 Improve error messages
* be a bit more verbose on `getaddrinfo()` error
* fix missing space

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-05-23 16:07:32 +02:00
Steffen Jaeckel
4ec4f09b35 Fix xssl tests
Make sure to use the custom built TLS library.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-05-23 16:05:51 +02:00
Steffen Jaeckel
e24819a405 Run the xSSL Valgrind test in the same runner
Building the SSL library is too much overhead, let's do this only once
and re-build and run libstrophe with Valgrind enabled in the same runner.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-05-23 16:05:51 +02:00
Steffen Jaeckel
d0d1fa9835 Update xSSL CI jobs
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-05-23 16:05:51 +02:00
Steffen Jaeckel
da1229814c Add support for SCRAM-SHA-512-PLUS
Patch written by @matthias-hmb

This fixes #241

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-04-16 16:11:09 +02:00
Steffen Jaeckel
d82df1273c Add support for SSLKEYLOGFILE with OpenSSL
GnuTLS has support already built-in.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-04-10 17:22:14 +02:00
Steffen Jaeckel
9fef4b7d02 Restore old interface if TLS connection failed
This was reported as creating a segfault in [0]

[0] https://github.com/profanity-im/profanity/issues/1963

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-04-10 17:22:14 +02:00
Steffen Jaeckel
4359536a17 Allow to drop the first element of the send queue
In case we're in disconnected state, allow the user to drop the first
element of the send queue, even if it was already in progress
to be written.

Before this patch, the first element could not be retrieved at all, even
after a disconnect.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-04-10 11:59:36 +02:00
Steffen Jaeckel
03d43132bc Fix SM in case the user drops the first stanza
We have to reset the `r_sent` flag in case we drop the `<r>` stanza,
otherwise the SM `h` request mechanism stops working.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-04-09 16:47:00 +02:00
Steffen Jaeckel
4d59a9fe45 Release libstrophe-0.13.1
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-21 13:47:07 +01:00
Steffen Jaeckel
40f2452fb0 Fix SCRAM-*-PLUS SASL mechanisms with OpenSSL and TLS < v1.3
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-21 13:19:47 +01:00
Steffen Jaeckel
1cf09b1870 Only signal "stream negotiation success" once.
The code-path which checks whether the server requires an "xmpp-session"
was untested and therefore the connection-callback handler was triggered
twice with the state `XMPP_CONN_CONNECT`. This happened if the server
supports stream-management and requires a session.

Reported via https://github.com/profanity-im/profanity/issues/1954

Fixup of c7d410f38b

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-14 11:40:59 +01:00
Steffen Jaeckel
5edc480932 Fix sock_connect()
`rc` must be reset in order to make the `do-while` loop work in case
there's no `sockopt_cb` set.

Fixup of f3460460e9

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-14 11:40:38 +01:00
Steffen Jaeckel
641211ecae Minor improvements
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-12 17:47:24 +01:00
Steffen Jaeckel
d8fd6e6d14 Improve documentation
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-12 17:46:52 +01:00
Omar Polo
9410530507 Replace usage of EBADFD (not in POSIX) 2024-02-05 11:09:25 +01:00
Steffen Jaeckel
d6d71e97f8 Release libstrophe-0.13.0
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-02-01 09:34:32 +01:00
Steffen Jaeckel
3f03de031c Re-factor into separate compression module
Introduce a `conn_interface` to simplify the decision logic which API
we must call.

This also fixes some bugs of the previous commit.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-01-31 20:37:30 +01:00
Steffen Jaeckel
c7d410f38b First version of XEP-0138 support
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-01-30 14:23:26 +01:00
Steffen Jaeckel
fa960429b8 Improve Stream Management
* Delay the notification of the library user that the connection was
  successful, until SM is reported by the server as enabled.
* Clear the SM queue in case resumption failed.
* Improve some debug statements & comments.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-01-30 14:23:26 +01:00
Steffen Jaeckel
bfd0872aea Add support for SCRAM-*-PLUS SASL mechanisms
This fixes #133

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-27 23:50:16 +01:00
Steffen Jaeckel
c5b6026fc6 Use memset() in constructors
Instead of setting each element individually to 0 or NULL, use memset.

This also fixes the missing initialization of `conn->sm_disable`.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-08 15:23:49 +01:00
Steffen Jaeckel
7fbf507f58 Fix connected/connecting semantics
In case a connection is established, but the stream negotiation has not
completed yet, a user may think that they can start sending data,
but this is not the case.

All of the following quotes originate in RFC6120.

As of Ch. 8:

> After a client and a server (or two servers) have completed stream
> negotiation, either party can send XML stanzas.

As of Ch. 7.3.1:

> The parties to a stream MUST consider resource binding as
> mandatory-to-negotiate.

As of Ch. 6.3.1:

> The parties to a stream MUST consider SASL as mandatory-to-negotiate.

As of Ch. 4.3.5:

> The initiating entity MUST NOT attempt to send XML stanzas to entities
> other than itself (i.e., the client's connected resource or any other
> authenticated resource of the client's account) or the server to which
> it is connected until stream negotiation has been completed.
> Even if the initiating entity does attempt to do so, the receiving
> entity MUST NOT accept such stanzas and MUST close the stream with a
> <not-authorized/> stream error [...]

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-08 15:23:49 +01:00
Steffen Jaeckel
69f42360cf Officially deprecate xmpp_conn_disable_tls()
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-08 15:23:49 +01:00
Steffen Jaeckel
f40fcbe5d1 Introduce strophe_free_and_null()
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-01 01:40:45 +01:00
Steffen Jaeckel
13d0354176 Send less ACK requests
Only send an `r` stanza after we've received the reply to the previous one.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-01 01:40:45 +01:00
Steffen Jaeckel
53d8eb17b6 Improve macros used in tests
* Be more verbose in which argument is `should` and which is `is`.
* Fix the order in the `ENSURE_EQ()` macro.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-11-01 01:40:45 +01:00
Steffen Jaeckel
9735af515a Improve debug message
Before this change we couldn't differentiate between this instance
and the one further down in the code.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-10-26 22:23:28 +02:00
Steffen Jaeckel
c30bd0d9ab Fix typo
... also make it possible to pre-define `STROPHE_MESSAGE_BUFFER_SIZE` in
a custom build if someone doesn't want such a huge stack buffer.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-10-26 22:23:03 +02:00
Steffen Jaeckel
fdd717a246 Run CI against newer (libre|open)ssl
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-10-23 23:55:56 +02:00
Theo Buehler
7894d15929 Stop reaching into X509_ALGOR
While the struct is still public in all versions of OpenSSL and its
forks, this may well change in the future. Prepare for that case and
use the X509_ALGOR_get0() accessor which has been available with this
signature since OpenSSL 1.1.
2023-10-21 07:59:44 +02:00
Steffen Jaeckel
f49ccb3262 Fix wording of licensing terms
It has been pointed out that the wording of the license of this library is
not entirely clear.

The term "dual licensing" usually refers to a licence choice of two
licenses "LICENSE1 _or_ LICENSE2.
Instead the license of this library claimed "LICENSE1 _and_ LICENSE2".

After an internal discussion with @metajack and @pasis it was made clear
that the initial idea was to dual license the library in the usual way.

This was also made clear by jack on the ML in the past [0].
As of jack, these licensing terms originated from jquery, which also used
the 'and' version in the past and has since been corrected [1].

This patch changes the license terms to 'MIT or GPLv3' and also adds SPDX
headers [2].

[0] https://groups.google.com/g/libstrophe/c/JkFgr601JQc
[1] https://stackoverflow.com/q/2758409
[2] https://spdx.org

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-08-25 18:08:42 +02:00
Steffen Jaeckel
069787db51 Update certificate used in tests
Fedora patches OpenSSL and disables usage of the ECC curve we used
in the old certificate.
This patch changes the ECC curve to a supported one.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-08-09 15:51:50 +02:00
Steffen Jaeckel
9eba8e8738 Allow running tests when static library is disabled
We then only run a subset of the tests, but still better than failing to
build.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-08-09 13:34:18 +02:00
79 changed files with 2264 additions and 854 deletions

View File

@@ -24,6 +24,7 @@ jobs:
- { configure: '--disable-tls' } - { configure: '--disable-tls' }
- { configure: '--enable-cares' } - { configure: '--enable-cares' }
- { configure: '--disable-getrandom' } - { configure: '--disable-getrandom' }
- { configure: '--disable-static' }
name: Regular Tests name: Regular Tests
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -49,22 +50,31 @@ jobs:
strategy: strategy:
matrix: matrix:
xssl_versions: xssl_versions:
- { version: "master", continue: true, libressl: true } - { version: "master", continue: true, libressl: true }
- { version: "OPENBSD_7_1", continue: true, libressl: true } - { version: "OPENBSD_7_5", continue: true, libressl: true }
- { version: "v3.9.2", continue: true, libressl: true }
- { version: "OPENBSD_7_4", continue: true, libressl: true }
- { version: "v3.8.4", continue: true, libressl: true }
- { version: "OPENBSD_7_3", continue: true, libressl: true }
- { version: "OPENBSD_7_2", continue: true, libressl: true }
- { version: "OPENBSD_7_1", continue: true, libressl: true }
# https://github.com/libressl-portable/portable/issues/760 # https://github.com/libressl-portable/portable/issues/760
# - { version: "v3.5.2", continue: true, libressl: true } # - { version: "v3.5.2", continue: true, libressl: true }
- { version: "OPENBSD_7_0", continue: true, libressl: true } - { version: "OPENBSD_7_0", continue: true, libressl: true }
# OPENBSD_7_0 is basically the "fixed v3.4.3" # OPENBSD_7_0 is basically the "fixed v3.4.3"
# - { version: "v3.4.3", continue: true, libressl: true } # - { version: "v3.4.3", continue: true, libressl: true }
- { version: "v3.4.2", continue: true, libressl: true } - { version: "v3.4.2", continue: true, libressl: true }
- { version: "OPENBSD_6_9", continue: true, libressl: true } - { version: "OPENBSD_6_9", continue: true, libressl: true }
- { version: "v3.1.5", continue: true, libressl: true } - { version: "v3.1.5", continue: true, libressl: true }
- { version: "v2.1.10", continue: true, libressl: true } - { version: "v2.1.10", continue: true, libressl: true }
- { version: "openssl-3.0", continue: true, libressl: false } - { version: "openssl-3.0", continue: true, libressl: false }
- { version: "openssl-3.0.4", continue: false, libressl: false } - { version: "openssl-3.0.13", continue: false, libressl: false }
valgrind: - { version: "openssl-3.1", continue: true, libressl: false }
- { configure: '' , make: 'check' } - { version: "openssl-3.1.5", continue: false, libressl: false }
- { configure: '--enable-valgrind' , make: 'check-valgrind' } - { version: "openssl-3.2", continue: true, libressl: false }
- { version: "openssl-3.2.1", continue: false, libressl: false }
- { version: "openssl-3.3", continue: true, libressl: false }
- { version: "openssl-3.3.0", continue: false, libressl: false }
name: xSSL tests name: xSSL tests
continue-on-error: ${{ matrix.xssl_versions.continue }} continue-on-error: ${{ matrix.xssl_versions.continue }}
steps: steps:
@@ -82,11 +92,19 @@ jobs:
- name: Build the library - name: Build the library
run: | run: |
./bootstrap.sh ./bootstrap.sh
./configure ${{ matrix.valgrind.configure }} PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/xssl" PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" ./configure CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
make -j$(nproc) make -j$(nproc)
- name: Run tests - name: Run tests
run: | run: |
make -j$(nproc) ${{ matrix.valgrind.make }} LD_LIBRARY_PATH="${HOME}/xssl/lib" make -j$(nproc) check
- name: Build the library with Valgrind enabled
run: |
./bootstrap.sh
PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" ./configure --enable-valgrind CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
make -j$(nproc)
- name: Run tests with Valgrind enabled
run: |
LD_LIBRARY_PATH="${HOME}/xssl/lib" make -j$(nproc) check-valgrind
- name: Error logs - name: Error logs
if: ${{ failure() }} if: ${{ failure() }}
run: | run: |

View File

@@ -1,3 +1,19 @@
0.13.1
- Fix SCRAM-*-PLUS SASL mechanisms with OpenSSL and TLS < v1.3 (40f2452)
- Only signal "stream negotiation success" once (1cf09b1)
- Fix `sock_connect()` not looping over all DNS records returned if no `sockopt_cb` is set (5edc480)
- Replace usage of EBADFD, it's not in POSIX (#235)
0.13.0
- Fix connected/connecting signaling to user (#227)
- Fix wording of licensing terms (#225)
- Prepare for future changes in OpenSSL (#226)
- Improve Stream Management (#227) (#230)
- Add SCRAM-PLUS Variants (#228)
- Introduce XEP-0138 stream compression (#231)
- Deprecated the following API (#227):
- xmpp_conn_disable_tls() - replaced by a flag set by xmpp_conn_set_flags()
0.12.3 0.12.3
- Improve TCP-connection establishment (#221) - Improve TCP-connection establishment (#221)
- Handle case where the server doesn't provide the `bind` feature (#224) - Handle case where the server doesn't provide the `bind` feature (#224)
@@ -21,7 +37,7 @@
- Fix some build steps when builddir != srcdir (#208) - Fix some build steps when builddir != srcdir (#208)
- Allow the user to disable build of examples (#209) - Allow the user to disable build of examples (#209)
- CI builds against OpenSSL 3 (#206) - CI builds against OpenSSL 3 (#206)
- Change the call signature of the following API: - Change the call signature of the following API (#208):
- xmpp_conn_set_client_cert() - the PKCS#12 file has now to be passed via the `cert` - xmpp_conn_set_client_cert() - the PKCS#12 file has now to be passed via the `cert`
parameter. Originally it was via `key`. Currently both styles are supported, parameter. Originally it was via `key`. Currently both styles are supported,
but in a future release only passing via `cert` will be accepted. but in a future release only passing via `cert` will be accepted.

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.12 PROJECT_NUMBER = 0.13
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

View File

@@ -1,5 +1,5 @@
libstrophe XMPP client library libstrophe XMPP client library
Copyright (C) 2005-2009 Collecta, Inc. Copyright (C) 2005-2009 Collecta, Inc.
This program is dual licensed under the MIT and GPLv3 licenses. This program is dual licensed under the MIT or GPLv3 licenses.
Please the files MIT-LICENSE.txt and GPL-LICENSE.txt for details. Please the files MIT-LICENSE.txt and GPL-LICENSE.txt for details.

View File

@@ -10,6 +10,9 @@ COVERAGE_POST=@COVERAGE_POST@
PARSER_CFLAGS=@PARSER_CFLAGS@ PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@ PARSER_LIBS=@PARSER_LIBS@
ZLIB_CFLAGS=@ZLIB_CFLAGS@
ZLIB_LIBS=@ZLIB_LIBS@
if TLS_WITH_GNUTLS if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@ SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@ SSL_LIBS = @gnutls_LIBS@
@@ -32,8 +35,8 @@ STROPHE_LIBS = $(COVERAGE_PRE) libstrophe.la $(COVERAGE_POST) $(COVERAGE_LDFLAGS
## Main build targets ## Main build targets
lib_LTLIBRARIES = libstrophe.la lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS) libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS) $(ZLIB_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) -no-undefined libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) $(ZLIB_LIBS) -no-undefined
# Export only public API # Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@ libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@
@@ -82,6 +85,12 @@ if NEED_SNPRINTF
libstrophe_la_SOURCES += src/snprintf.c libstrophe_la_SOURCES += src/snprintf.c
endif endif
if DISABLE_COMPRESSION
libstrophe_la_SOURCES += src/compression_dummy.c
else
libstrophe_la_SOURCES += src/compression.c
endif
if DISABLE_TLS if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c libstrophe_la_SOURCES += src/tls_dummy.c
else else
@@ -175,23 +184,29 @@ endif
## Tests ## Tests
TESTS = \ STATIC_TESTS = \
tests/check_parser \ tests/check_parser \
tests/test_hash \
tests/test_jid \
tests/test_ctx \
tests/test_send_queue \
tests/test_string \
tests/test_resolver
TESTS = \
tests/test_sha1 \ tests/test_sha1 \
tests/test_sha256 \ tests/test_sha256 \
tests/test_sha512 \ tests/test_sha512 \
tests/test_md5 \ tests/test_md5 \
tests/test_rand \ tests/test_rand \
tests/test_scram \ tests/test_scram \
tests/test_ctx \
tests/test_base64 \ tests/test_base64 \
tests/test_hash \
tests/test_jid \
tests/test_send_queue \
tests/test_snprintf \ tests/test_snprintf \
tests/test_string \ tests/test_stanza
tests/test_stanza \
tests/test_resolver if !DISABLE_STATIC
TESTS += $(STATIC_TESTS)
endif
if !DISABLE_TLS if !DISABLE_TLS
TESTS += tests/test_xmppaddr TESTS += tests/test_xmppaddr

View File

@@ -5,7 +5,7 @@ libstrophe is a lightweight XMPP client library written in C. It has
minimal dependencies and is configurable for various environments. It minimal dependencies and is configurable for various environments. It
runs well on Linux, Unix and Windows based platforms. runs well on Linux, Unix and Windows based platforms.
libstrophe is dual licensed under MIT and GPLv3. libstrophe is dual licensed under MIT or GPLv3.
Build Instructions Build Instructions
------------------ ------------------
@@ -88,7 +88,7 @@ or if you have everything configured properly:
Then open `docs/html/index.html`. Then open `docs/html/index.html`.
An online version of the documentation of the latest release is available on http://strophe.im/libstrophe/ An online version of the documentation of the latest release is available on https://strophe.im/libstrophe/
Releases Releases
-------- --------

View File

@@ -1,6 +1,6 @@
m4_define([v_maj], [0]) m4_define([v_maj], [0])
m4_define([v_min], [12]) m4_define([v_min], [13])
m4_define([v_patch], [3]) m4_define([v_patch], [1])
m4_define([project_version], [v_maj.v_min.v_patch]) m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min)) m4_define([lt_cur], m4_eval(v_maj + v_min))
@@ -51,6 +51,8 @@ AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])]) [AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([getrandom], AC_ARG_ENABLE([getrandom],
[AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])]) [AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])])
AC_ARG_ENABLE([zlib],
[AS_HELP_STRING([--disable-zlib], [disable compression support])])
AC_ARG_ENABLE([fuzzing], AC_ARG_ENABLE([fuzzing],
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])], [AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
@@ -247,6 +249,18 @@ fi
fi fi
if test "x$enable_zlib" != xno; then
PKG_CHECK_MODULES([zlib], [zlib >= 1.2.0],
[
PC_REQUIRES="zlib ${PC_REQUIRES}"
ZLIB_CFLAGS=$zlib_CFLAGS
ZLIB_LIBS=$zlib_LIBS
AC_DEFINE([HAVE_ZLIB])
],
[AC_MSG_ERROR([zlib not found])])
# TODO: if pkg-config doesn't find, check the library manually
fi
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR], m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir], [AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir],
@@ -255,7 +269,9 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])]) AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2]) AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AM_CONDITIONAL([DISABLE_COMPRESSION], [test x$enable_zlib = xno])
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno]) AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
AM_CONDITIONAL([DISABLE_STATIC], [test x$enable_static = xno])
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno]) AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes]) AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
AM_CONDITIONAL([TLS_WITH_SCHANNEL], [test x$with_schannel = xyes]) AM_CONDITIONAL([TLS_WITH_SCHANNEL], [test x$with_schannel = xyes])
@@ -289,5 +305,7 @@ AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS) AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS) AC_SUBST(RESOLV_LIBS)
AC_SUBST(WARNING_FLAGS) AC_SUBST(WARNING_FLAGS)
AC_SUBST(ZLIB_CFLAGS)
AC_SUBST(ZLIB_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc]) AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT AC_OUTPUT

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* active.c /* active.c
** libstrophe XMPP client library -- basic usage example ** libstrophe XMPP client library -- basic usage example
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* This example demonstrates basic handler functions by printing out /* This example demonstrates basic handler functions by printing out
@@ -114,8 +115,8 @@ int main(int argc, char **argv)
*/ */
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]); xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]);
xmpp_conn_set_pass(conn, argv[2]); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]);
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* basic.c /* basic.c
** libstrophe XMPP client library -- basic usage example ** libstrophe XMPP client library -- basic usage example
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdio.h> #include <stdio.h>
@@ -115,9 +116,9 @@ int main(int argc, char **argv)
/* setup authentication information */ /* setup authentication information */
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
if (password) if (password)
xmpp_conn_set_pass(conn, password); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* bot.c /* bot.c
** libstrophe XMPP client library -- basic usage example ** libstrophe XMPP client library -- basic usage example
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* simple bot example /* simple bot example
@@ -76,13 +77,19 @@ int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
return 1; return 1;
} }
static int _quit_handler(xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
xmpp_disconnect(conn);
return 0;
}
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *body, *reply; xmpp_stanza_t *body, *reply;
const char *type; const char *type;
char *intext, *replytext; char *intext, *replytext;
int quit = 0;
body = xmpp_stanza_get_child_by_name(stanza, "body"); body = xmpp_stanza_get_child_by_name(stanza, "body");
if (body == NULL) if (body == NULL)
@@ -102,11 +109,11 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (strcmp(intext, "quit") == 0) { if (strcmp(intext, "quit") == 0) {
replytext = strdup("bye!"); replytext = strdup("bye!");
quit = 1; xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
} else if (strcmp(intext, "reconnect") == 0) { } else if (strcmp(intext, "reconnect") == 0) {
replytext = strdup("alright, let's see what happens!"); replytext = strdup("alright, let's see what happens!");
reconnect = 1; reconnect = 1;
quit = 1; xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
} else { } else {
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1); replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext); strcpy(replytext, intext);
@@ -119,9 +126,6 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_release(reply); xmpp_stanza_release(reply);
free(replytext); free(replytext);
if (quit)
xmpp_disconnect(conn);
return 1; return 1;
} }
@@ -213,7 +217,10 @@ static void usage(int exit_code)
" --legacy-ssl Use old style SSL.\n" " --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n" " --legacy-auth Allow legacy authentication.\n"
"Note: --disable-tls conflicts with --mandatory-tls or " "Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n"); "--legacy-ssl\n"
" --zlib Enable compression via zlib.\n"
" --dont-reset When using zlib, don't do a full-flush "
"after compression.\n");
exit(exit_code); exit(exit_code);
} }
@@ -243,6 +250,10 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL; flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0) else if (strcmp(argv[i], "--legacy-auth") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH; flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--zlib") == 0)
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
else if (strcmp(argv[i], "--dont-reset") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc)) else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i]; jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc)) else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
@@ -282,20 +293,24 @@ create_connection:
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* ask for a password if key is protected */ /* ask for a password if key is protected */
xmpp_conn_set_password_callback(conn, password_callback, NULL); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
password_callback);
/* try at max 3 times in case the user enters the password wrong */ /* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_password_retries(conn, 3); xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3);
/* setup authentication information */ /* setup authentication information */
if (key) if (key) {
xmpp_conn_set_client_cert(conn, cert, key); xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
}
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
if (password) if (password)
xmpp_conn_set_pass(conn, password); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
/* enable TCP keepalive, using canned callback function */ /* enable TCP keepalive, using canned callback function */
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
xmpp_sockopt_cb_keepalive);
/* set Stream-Mangement state if available */ /* set Stream-Mangement state if available */
if (sm_state) { if (sm_state) {

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* complex.c /* complex.c
** libstrophe XMPP client library -- more complex usage example ** libstrophe XMPP client library -- more complex usage example
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdio.h> #include <stdio.h>
@@ -238,6 +239,9 @@ static void usage(int exit_code)
" --enable-certfail Enable certfail handler.\n" " --enable-certfail Enable certfail handler.\n"
" --legacy-ssl Use old style SSL.\n" " --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n" " --legacy-auth Allow legacy authentication.\n"
" --zlib Enable compression via zlib.\n"
" --dont-reset When using zlib, don't do a full-flush "
"after compression.\n"
" --verbose Increase the verbosity level.\n" " --verbose Increase the verbosity level.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n" " --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or " "Note: --disable-tls conflicts with --mandatory-tls or "
@@ -272,6 +276,10 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL; flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0) else if (strcmp(argv[i], "--legacy-auth") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH; flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--zlib") == 0)
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
else if (strcmp(argv[i], "--dont-reset") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_RESET;
else if (strcmp(argv[i], "--verbose") == 0) else if (strcmp(argv[i], "--verbose") == 0)
verbosity++; verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0) else if (strcmp(argv[i], "--tcp-keepalive") == 0)
@@ -323,27 +331,31 @@ int main(int argc, char **argv)
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */ /* configure TCP keepalive (optional) */
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_sockopt_callback(conn, sockopt_cb); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
sockopt_cb);
/* ask for a password if key is protected */ /* ask for a password if key is protected */
xmpp_conn_set_password_callback(conn, password_callback, NULL); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
password_callback);
/* try at max 3 times in case the user enters the password wrong */ /* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_password_retries(conn, 3); xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3);
/* setup authentication information */ /* setup authentication information */
if (key) { if (key) {
xmpp_conn_set_client_cert(conn, cert, key); xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
} }
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
if (password) if (password)
xmpp_conn_set_pass(conn, password); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password);
if (certfail) if (certfail)
xmpp_conn_set_certfail_handler(conn, certfail_handler); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER,
certfail_handler);
if (capath) if (capath)
xmpp_conn_set_capath(conn, capath); xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, capath);
if (cafile) if (cafile)
xmpp_conn_set_cafile(conn, cafile); xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, cafile);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* component.c /* component.c
** libstrophe XMPP client library -- external component (XEP-0114) example ** libstrophe XMPP client library -- external component (XEP-0114) example
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* This example demonstrates simple connection to a server /* This example demonstrates simple connection to a server
@@ -79,8 +80,8 @@ int main(int argc, char **argv)
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
/* initiate connection */ /* initiate connection */
xmpp_connect_component(conn, host, port, conn_handler, ctx); xmpp_connect_component(conn, host, port, conn_handler, ctx);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* perf.c /* perf.c
* strophe XMPP client library -- performance measure * strophe XMPP client library -- performance measure
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* register.c /* register.c
* strophe XMPP client library -- In-band registration (XEP-0077) * strophe XMPP client library -- In-band registration (XEP-0077)
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* /*
@@ -341,7 +342,7 @@ int main(int argc, char **argv)
/* jid can be a jid or domain for "raw" connection */ /* jid can be a jid or domain for "raw" connection */
domain = xmpp_jid_domain(ctx, jid); domain = xmpp_jid_domain(ctx, jid);
xmpp_conn_set_jid(conn, domain); xmpp_conn_set_string(conn, XMPP_SETTING_JID, domain);
xmpp_free(ctx, domain); xmpp_free(ctx, domain);
/* private data */ /* private data */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* roster.c /* roster.c
** libstrophe XMPP client library -- handler example ** libstrophe XMPP client library -- handler example
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* This example demonstrates basic handler functions by printing out /* This example demonstrates basic handler functions by printing out
@@ -117,8 +118,8 @@ int main(int argc, char **argv)
*/ */
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, argv[1]); xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]);
xmpp_conn_set_pass(conn, argv[2]); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]);
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* vcard.c /* vcard.c
* strophe XMPP client library -- vCard example * strophe XMPP client library -- vCard example
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>
@@ -268,8 +269,8 @@ int main(int argc, char **argv)
log = xmpp_get_default_logger(XMPP_LEVEL_INFO); log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
vcard.ctx = ctx; vcard.ctx = ctx;
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard); xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
xmpp_run(ctx); xmpp_run(ctx);

View File

@@ -5,7 +5,7 @@ includedir=@includedir@
Name: libstrophe Name: libstrophe
Description: A simple, lightweight C library for writing XMPP clients Description: A simple, lightweight C library for writing XMPP clients
URL: http://strophe.im/libstrophe/ URL: https://strophe.im/libstrophe/
Version: @VERSION@ Version: @VERSION@
Requires: Requires:
Requires.private: @PC_REQUIRES@ Requires.private: @PC_REQUIRES@

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* auth.c /* auth.c
** strophe XMPP client library -- auth functions and handlers ** strophe XMPP client library -- auth functions and handlers
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -61,6 +62,7 @@
static void _auth(xmpp_conn_t *conn); static void _auth(xmpp_conn_t *conn);
static void _auth_legacy(xmpp_conn_t *conn); static void _auth_legacy(xmpp_conn_t *conn);
static void _handle_open_compress(xmpp_conn_t *conn);
static void _handle_open_sasl(xmpp_conn_t *conn); static void _handle_open_sasl(xmpp_conn_t *conn);
static void _handle_open_tls(xmpp_conn_t *conn); static void _handle_open_tls(xmpp_conn_t *conn);
@@ -71,6 +73,9 @@ static int _handle_component_hs_response(xmpp_conn_t *conn,
static int static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata); _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_features_compress(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata);
static int static int
_handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata); _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_digestmd5_challenge(xmpp_conn_t *conn, static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
@@ -82,7 +87,8 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
static int _handle_scram_challenge(xmpp_conn_t *conn, static int _handle_scram_challenge(xmpp_conn_t *conn,
xmpp_stanza_t *stanza, xmpp_stanza_t *stanza,
void *userdata); void *userdata);
static char *_make_scram_init_msg(xmpp_conn_t *conn); struct scram_user_data;
static int _make_scram_init_msg(struct scram_user_data *scram);
static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata); static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata);
static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata); static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata);
@@ -205,12 +211,54 @@ static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
return 0; return 0;
} }
typedef void (*text_handler)(xmpp_conn_t *conn, const char *text);
static void _foreach_child(xmpp_conn_t *conn,
xmpp_stanza_t *parent,
const char *name,
text_handler hndl)
{
xmpp_stanza_t *children;
for (children = xmpp_stanza_get_children(parent); children;
children = xmpp_stanza_get_next(children)) {
const char *child_name = xmpp_stanza_get_name(children);
if (child_name && strcmp(child_name, name) == 0) {
char *text = xmpp_stanza_get_text(children);
if (text == NULL)
continue;
hndl(conn, text);
strophe_free(conn->ctx, text);
}
}
}
static void _handle_sasl_children(xmpp_conn_t *conn, const char *text)
{
if (strcasecmp(text, "PLAIN") == 0) {
conn->sasl_support |= SASL_MASK_PLAIN;
} else if (strcasecmp(text, "EXTERNAL") == 0 &&
(conn->tls_client_cert || conn->tls_client_key)) {
conn->sasl_support |= SASL_MASK_EXTERNAL;
} else if (strcasecmp(text, "DIGEST-MD5") == 0) {
conn->sasl_support |= SASL_MASK_DIGESTMD5;
} else if (strcasecmp(text, "ANONYMOUS") == 0) {
conn->sasl_support |= SASL_MASK_ANONYMOUS;
} else {
size_t n;
for (n = 0; n < scram_algs_num; ++n) {
if (strcasecmp(text, scram_algs[n]->scram_name) == 0) {
conn->sasl_support |= scram_algs[n]->mask;
break;
}
}
}
}
static int static int
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t *child, *mech; xmpp_stanza_t *child;
const char *ns;
char *text;
UNUSED(userdata); UNUSED(userdata);
@@ -220,10 +268,9 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* check for TLS */ /* check for TLS */
if (!conn->secured) { if (!conn->secured) {
if (!conn->tls_disabled) { if (!conn->tls_disabled) {
child = xmpp_stanza_get_child_by_name(stanza, "starttls"); if (xmpp_stanza_get_child_by_name_and_ns(stanza, "starttls",
if (child) { XMPP_NS_TLS)) {
ns = xmpp_stanza_get_ns(child); conn->tls_support = 1;
conn->tls_support = ns != NULL && strcmp(ns, XMPP_NS_TLS) == 0;
} }
} else { } else {
conn->tls_support = 0; conn->tls_support = 0;
@@ -231,36 +278,10 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
} }
/* check for SASL */ /* check for SASL */
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms"); child = xmpp_stanza_get_child_by_name_and_ns(stanza, "mechanisms",
ns = child ? xmpp_stanza_get_ns(child) : NULL; XMPP_NS_SASL);
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) { if (child) {
for (mech = xmpp_stanza_get_children(child); mech; _foreach_child(conn, child, "mechanism", _handle_sasl_children);
mech = xmpp_stanza_get_next(mech)) {
if (xmpp_stanza_get_name(mech) &&
strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
text = xmpp_stanza_get_text(mech);
if (text == NULL)
continue;
if (strcasecmp(text, "PLAIN") == 0)
conn->sasl_support |= SASL_MASK_PLAIN;
else if (strcasecmp(text, "EXTERNAL") == 0 &&
(conn->tls_client_cert || conn->tls_client_key))
conn->sasl_support |= SASL_MASK_EXTERNAL;
else if (strcasecmp(text, "DIGEST-MD5") == 0)
conn->sasl_support |= SASL_MASK_DIGESTMD5;
else if (strcasecmp(text, "SCRAM-SHA-1") == 0)
conn->sasl_support |= SASL_MASK_SCRAMSHA1;
else if (strcasecmp(text, "SCRAM-SHA-256") == 0)
conn->sasl_support |= SASL_MASK_SCRAMSHA256;
else if (strcasecmp(text, "SCRAM-SHA-512") == 0)
conn->sasl_support |= SASL_MASK_SCRAMSHA512;
else if (strcasecmp(text, "ANONYMOUS") == 0)
conn->sasl_support |= SASL_MASK_ANONYMOUS;
strophe_free(conn->ctx, text);
}
}
} }
/* Disable PLAIN when other secure mechanisms are supported */ /* Disable PLAIN when other secure mechanisms are supported */
@@ -334,7 +355,9 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
(char *)userdata); (char *)userdata);
/* reset parser */ /* reset parser */
conn_prepare_reset(conn, _handle_open_sasl); conn_prepare_reset(conn, conn->compression.allowed
? _handle_open_compress
: _handle_open_sasl);
/* send stream tag */ /* send stream tag */
conn_open_stream(conn); conn_open_stream(conn);
@@ -438,7 +461,11 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
} }
struct scram_user_data { struct scram_user_data {
xmpp_conn_t *conn;
int sasl_plus;
char *scram_init; char *scram_init;
char *channel_binding;
const char *first_bare;
const struct hash_alg *alg; const struct hash_alg *alg;
}; };
@@ -470,8 +497,9 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
if (!challenge) if (!challenge)
goto err; goto err;
response = sasl_scram(conn->ctx, scram_ctx->alg, challenge, response =
scram_ctx->scram_init, conn->jid, conn->pass); sasl_scram(conn->ctx, scram_ctx->alg, scram_ctx->channel_binding,
challenge, scram_ctx->first_bare, conn->jid, conn->pass);
strophe_free(conn->ctx, challenge); strophe_free(conn->ctx, challenge);
if (!response) if (!response)
goto err; goto err;
@@ -505,7 +533,8 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
*/ */
rc = _handle_sasl_result(conn, stanza, rc = _handle_sasl_result(conn, stanza,
(void *)scram_ctx->alg->scram_name); (void *)scram_ctx->alg->scram_name);
strophe_free(conn->ctx, scram_ctx->scram_init); strophe_free_and_null(conn->ctx, scram_ctx->channel_binding);
strophe_free_and_null(conn->ctx, scram_ctx->scram_init);
strophe_free(conn->ctx, scram_ctx); strophe_free(conn->ctx, scram_ctx);
} }
@@ -516,33 +545,103 @@ err_release_auth:
err_free_response: err_free_response:
strophe_free(conn->ctx, response); strophe_free(conn->ctx, response);
err: err:
strophe_free(conn->ctx, scram_ctx->scram_init); strophe_free_and_null(conn->ctx, scram_ctx->channel_binding);
strophe_free_and_null(conn->ctx, scram_ctx->scram_init);
strophe_free(conn->ctx, scram_ctx); strophe_free(conn->ctx, scram_ctx);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0; return 0;
} }
static char *_make_scram_init_msg(xmpp_conn_t *conn) static int _make_scram_init_msg(struct scram_user_data *scram)
{ {
xmpp_conn_t *conn = scram->conn;
xmpp_ctx_t *ctx = conn->ctx; xmpp_ctx_t *ctx = conn->ctx;
size_t message_len; const void *binding_data;
char *node; const char *binding_type;
char *message; char *node, *message;
char nonce[32]; size_t message_len, binding_type_len = 0, binding_data_len;
int l, is_secured = xmpp_conn_is_secured(conn);
/* This buffer must be able to hold:
* "p=<10 bytes binding type>,,<36 bytes binding data>"
* + alignment */
char buf[56];
if (scram->sasl_plus) {
if (!is_secured) {
strophe_error(
ctx, "xmpp",
"SASL: Server requested a -PLUS variant to authenticate, "
"but the connection is not secured. This is an error on "
"the server side we can't do anything about.");
return -1;
}
if (tls_init_channel_binding(conn->tls, &binding_type,
&binding_type_len)) {
return -1;
}
/* directly account for the '=' char in 'p=<binding-type>' */
binding_type_len += 1;
}
node = xmpp_jid_node(ctx, conn->jid); node = xmpp_jid_node(ctx, conn->jid);
if (!node) { if (!node) {
return NULL; return -1;
} }
xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce)); /* 32 bytes nonce is enough */
message_len = strlen(node) + strlen(nonce) + 8 + 1; xmpp_rand_nonce(ctx->rand, buf, 33);
message_len = strlen(node) + strlen(buf) + 8 + binding_type_len + 1;
message = strophe_alloc(ctx, message_len); message = strophe_alloc(ctx, message_len);
if (message) { if (!message) {
strophe_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce); goto err_node;
} }
/* increase length to account for 'y,,', 'n,,' or 'p,,'.
* In the 'p' case the '=' sign has already been accounted for above.
*/
binding_type_len += 3;
if (scram->sasl_plus) {
l = strophe_snprintf(message, message_len, "p=%s,,n=%s,r=%s",
binding_type, node, buf);
} else {
l = strophe_snprintf(message, message_len, "%c,,n=%s,r=%s",
is_secured ? 'y' : 'n', node, buf);
}
if (l < 0 || (size_t)l >= message_len) {
goto err_msg;
}
if (binding_type_len > sizeof(buf)) {
goto err_msg;
}
/* Make `first_bare` point to the 'n' of 'n=<node>' of the
* client-first-message */
scram->first_bare = message + binding_type_len;
memcpy(buf, message, binding_type_len);
if (scram->sasl_plus) {
binding_data =
tls_get_channel_binding_data(conn->tls, &binding_data_len);
if (!binding_data) {
goto err_msg;
}
if (binding_data_len > sizeof(buf) - binding_type_len) {
strophe_error(ctx, "xmpp", "Channel binding data is too long (%zu)",
binding_data_len);
goto err_msg;
}
memcpy(&buf[binding_type_len], binding_data, binding_data_len);
binding_type_len += binding_data_len;
}
scram->channel_binding =
xmpp_base64_encode(ctx, (void *)buf, binding_type_len);
memset(buf, 0, binding_type_len);
strophe_free(ctx, node); strophe_free(ctx, node);
scram->scram_init = message;
return message; return 0;
err_msg:
strophe_free(ctx, message);
err_node:
strophe_free(ctx, node);
return -1;
} }
static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn) static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn)
@@ -635,7 +734,7 @@ static void _auth(xmpp_conn_t *conn)
return; return;
} }
if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) { if (anonjid && (conn->sasl_support & SASL_MASK_ANONYMOUS)) {
/* some crap here */ /* some crap here */
auth = _make_sasl_auth(conn, "ANONYMOUS"); auth = _make_sasl_auth(conn, "ANONYMOUS");
if (!auth) { if (!auth) {
@@ -701,22 +800,26 @@ static void _auth(xmpp_conn_t *conn)
"Password hasn't been set, and SASL ANONYMOUS unsupported."); "Password hasn't been set, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAM) { } else if (conn->sasl_support & SASL_MASK_SCRAM) {
size_t n;
scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx)); scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx));
if (conn->sasl_support & SASL_MASK_SCRAMSHA512) memset(scram_ctx, 0, sizeof(*scram_ctx));
scram_ctx->alg = &scram_sha512; for (n = 0; n < scram_algs_num; ++n) {
else if (conn->sasl_support & SASL_MASK_SCRAMSHA256) if (conn->sasl_support & scram_algs[n]->mask) {
scram_ctx->alg = &scram_sha256; scram_ctx->alg = scram_algs[n];
else if (conn->sasl_support & SASL_MASK_SCRAMSHA1) break;
scram_ctx->alg = &scram_sha1; }
}
auth = _make_sasl_auth(conn, scram_ctx->alg->scram_name); auth = _make_sasl_auth(conn, scram_ctx->alg->scram_name);
if (!auth) { if (!auth) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
return; return;
} }
/* don't free scram_init on success */ scram_ctx->conn = conn;
scram_ctx->scram_init = _make_scram_init_msg(conn); scram_ctx->sasl_plus =
if (!scram_ctx->scram_init) { scram_ctx->alg->mask & SASL_MASK_SCRAM_PLUS ? 1 : 0;
if (_make_scram_init_msg(scram_ctx)) {
strophe_free(conn->ctx, scram_ctx); strophe_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
disconnect_mem_error(conn); disconnect_mem_error(conn);
@@ -752,7 +855,7 @@ static void _auth(xmpp_conn_t *conn)
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
/* SASL SCRAM-SHA-1 was tried, unset flag */ /* SASL algorithm was tried, unset flag */
conn->sasl_support &= ~scram_ctx->alg->mask; conn->sasl_support &= ~scram_ctx->alg->mask;
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) { } else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
auth = _make_sasl_auth(conn, "DIGEST-MD5"); auth = _make_sasl_auth(conn, "DIGEST-MD5");
@@ -812,10 +915,10 @@ static void _auth(xmpp_conn_t *conn)
} }
} }
static void _auth_success(xmpp_conn_t *conn) static void _stream_negotiation_success(xmpp_conn_t *conn)
{ {
tls_clear_password_cache(conn); tls_clear_password_cache(conn);
conn->authenticated = 1; conn->stream_negotiation_completed = 1;
/* call connection handler */ /* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata); conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} }
@@ -865,6 +968,17 @@ static void _handle_open_sasl(xmpp_conn_t *conn)
NULL); NULL);
} }
/* called when stream:stream tag received after compression has been enabled */
static void _handle_open_compress(xmpp_conn_t *conn)
{
strophe_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
/* setup stream:features handlers */
handler_add(conn, _handle_features_compress, XMPP_NS_STREAMS, "features",
NULL, NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind) static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
{ {
xmpp_stanza_t *iq, *res, *text; xmpp_stanza_t *iq, *res, *text;
@@ -877,6 +991,7 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
/* send bind request */ /* send bind request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1"); iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
if (!iq) { if (!iq) {
xmpp_stanza_release(bind);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0; return 0;
} }
@@ -921,24 +1036,78 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
return 0; return 0;
} }
static int _handle_compress_result(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata)
{
const char *name = xmpp_stanza_get_name(stanza);
UNUSED(userdata);
if (!name)
return 0;
if (strcmp(name, "compressed") == 0) {
/* Stream compression enabled, we need to restart the stream */
strophe_debug(conn->ctx, "xmpp", "Stream compression enabled");
/* reset parser */
conn_prepare_reset(conn, _handle_open_sasl);
/* make compression effective */
compression_init(conn);
/* send stream tag */
conn_open_stream(conn);
}
return 0;
}
static int _handle_features_compress(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
const char *compress = "<compress xmlns='" XMPP_NS_COMPRESSION
"'><method>zlib</method></compress>";
xmpp_stanza_t *child;
/* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features);
/* check for compression */
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
XMPP_NS_FEATURE_COMPRESSION);
if (conn->compression.allowed && child) {
_foreach_child(conn, child, "method",
compression_handle_feature_children);
}
if (conn->compression.supported) {
send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL,
NULL, NULL);
} else {
return _handle_features_sasl(conn, stanza, userdata);
}
return 0;
}
static int static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t *bind, *session, *opt; xmpp_stanza_t *bind, *session;
xmpp_stanza_t *resume; xmpp_stanza_t *resume;
const char *ns;
char h[11]; char h[11];
UNUSED(userdata); UNUSED(userdata);
/* remove missing features handler */ /* Remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl); xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
/* check whether resource binding is required */ /* Check whether resource binding is required */
bind = xmpp_stanza_get_child_by_name(stanza, "bind"); bind = xmpp_stanza_get_child_by_name_and_ns(stanza, "bind", XMPP_NS_BIND);
if (bind) { if (bind) {
ns = xmpp_stanza_get_ns(bind); conn->bind_required = 1;
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
bind = xmpp_stanza_copy(bind); bind = xmpp_stanza_copy(bind);
if (!bind) { if (!bind) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
@@ -948,25 +1117,31 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
conn->bind_required = 0; conn->bind_required = 0;
} }
/* check whether session establishment is required */ /* Check whether session establishment is required.
session = xmpp_stanza_get_child_by_name(stanza, "session"); *
* The mechanism is deprecated, but we still support it.
*
* RFC3921 contains Ch. 3 "Session Establishment".
*
* RFC6121 removes this and explains in Ch. 1.4:
* "Interoperability Note: [...] Implementation and deployment experience
* has shown that this additional step is unnecessary. [...]" */
session = xmpp_stanza_get_child_by_name_and_ns(stanza, "session",
XMPP_NS_SESSION);
if (session) { if (session) {
ns = xmpp_stanza_get_ns(session); conn->session_required =
opt = xmpp_stanza_get_child_by_name(session, "optional"); xmpp_stanza_get_child_by_name(session, "optional") == NULL;
if (!opt)
conn->session_required =
ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
} }
/* Check stream-management support */
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) { if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
/* stream management supported */
conn->sm_state->sm_support = 1; conn->sm_state->sm_support = 1;
} }
/* we are expecting either <bind/> and <session/> since this is a /* We are expecting either <bind/> and optionally <session/> since this is a
XMPP style connection or we <resume/> the previous session */ XMPP style connection or we <resume/> the previous session */
/* check whether we can <resume/> the previous session */ /* Check whether we can <resume/> the previous session */
if (!conn->sm_disable && conn->sm_state->can_resume && if (!conn->sm_disable && conn->sm_state->can_resume &&
conn->sm_state->previd && conn->sm_state->bound_jid) { conn->sm_state->previd && conn->sm_state->bound_jid) {
resume = xmpp_stanza_new(conn->ctx); resume = xmpp_stanza_new(conn->ctx);
@@ -1013,11 +1188,57 @@ static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
return 0; return 0;
} }
static void _session_start(xmpp_conn_t *conn)
{
xmpp_stanza_t *session;
xmpp_stanza_t *iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
if (!iq) {
disconnect_mem_error(conn);
return;
}
session = xmpp_stanza_new(conn->ctx);
if (!session) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
/* setup response handlers */
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT, NULL);
xmpp_stanza_set_name(session, "session");
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
xmpp_stanza_add_child_ex(iq, session, 0);
/* send session establishment request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
}
static void _sm_enable(xmpp_conn_t *conn)
{
xmpp_stanza_t *enable = xmpp_stanza_new(conn->ctx);
if (!enable) {
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(enable, "enable");
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
if (!conn->sm_state->dont_request_resume)
xmpp_stanza_set_attribute(enable, "resume", "true");
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
conn->sm_state->sm_sent_nr = 0;
conn->sm_state->sm_enabled = 1;
}
static int static int
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
const char *type; const char *type;
xmpp_stanza_t *iq, *enable, *session, *binding, *jid_stanza; xmpp_stanza_t *binding, *jid_stanza;
UNUSED(userdata); UNUSED(userdata);
@@ -1042,50 +1263,18 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* establish a session if required */ /* establish a session if required */
if (conn->session_required) { if (conn->session_required) {
/* setup response handlers */ _session_start(conn);
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT,
NULL);
/* send session request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
if (!iq) {
disconnect_mem_error(conn);
return 0;
}
session = xmpp_stanza_new(conn->ctx);
if (!session) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(session, "session");
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
xmpp_stanza_add_child_ex(iq, session, 0);
/* send session establishment request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
} }
/* send enable directly after the bind request */
if (conn->sm_state->sm_support && !conn->sm_disable) { else if (conn->sm_state->sm_support && !conn->sm_disable) {
enable = xmpp_stanza_new(conn->ctx); _sm_enable(conn);
if (!enable) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(enable, "enable");
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
if (!conn->sm_state->dont_request_resume)
xmpp_stanza_set_attribute(enable, "resume", "true");
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
} }
/* if there's no xmpp session required and we didn't try to enable
if (!conn->session_required) { * stream-management, we're done here and the stream-negotiation was
_auth_success(conn); * successful
*/
else {
_stream_negotiation_success(conn);
} }
} else { } else {
strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply."); strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
@@ -1121,8 +1310,11 @@ _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (type && strcmp(type, "result") == 0) { } else if (type && strcmp(type, "result") == 0) {
strophe_debug(conn->ctx, "xmpp", "Session establishment successful."); strophe_debug(conn->ctx, "xmpp", "Session establishment successful.");
if (conn->sm_state->sm_support && !conn->sm_disable) {
_auth_success(conn); _sm_enable(conn);
} else {
_stream_negotiation_success(conn);
}
} else { } else {
strophe_error(conn->ctx, "xmpp", strophe_error(conn->ctx, "xmpp",
"Server sent malformed session reply."); "Server sent malformed session reply.");
@@ -1153,23 +1345,59 @@ static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
return 0; return 0;
} }
static int _get_h_attribute(xmpp_stanza_t *stanza, unsigned long *ul_h)
{
const char *h = xmpp_stanza_get_attribute(stanza, "h");
if (!h || string_to_ul(h, ul_h)) {
strophe_error(
stanza->ctx, "xmpp",
"SM error: failed parsing 'h', \"%s\" got converted to %llu.",
STR_MAYBE_NULL(h), *ul_h);
return -1;
}
return 0;
}
static void _sm_queue_cleanup(xmpp_conn_t *conn, unsigned long ul_h)
{
xmpp_send_queue_t *e;
while ((e = peek_queue_front(&conn->sm_state->sm_queue))) {
if (e->sm_h >= ul_h)
break;
e = pop_queue_front(&conn->sm_state->sm_queue);
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
}
}
static void _sm_queue_resend(xmpp_conn_t *conn)
{
xmpp_send_queue_t *e;
while ((e = pop_queue_front(&conn->sm_state->sm_queue))) {
/* Re-send what was already sent out and is still in the
* SM queue (i.e. it hasn't been ACK'ed by the server)
*/
strophe_debug_verbose(2, conn->ctx, "conn", "SM_Q_RESEND: %p, h=%lu", e,
e->sm_h);
send_raw(conn, e->data, e->len, e->owner, NULL);
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
}
}
static int _handle_sm(xmpp_conn_t *const conn, static int _handle_sm(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza, xmpp_stanza_t *const stanza,
void *const userdata) void *const userdata)
{ {
xmpp_stanza_t *failed_cause; xmpp_stanza_t *failed_cause, *bind = NULL;
const char *name, *id, *previd, *resume, *h, *cause; const char *name, *id, *previd, *resume, *cause;
xmpp_send_queue_t *e;
unsigned long ul_h = 0; unsigned long ul_h = 0;
UNUSED(userdata); UNUSED(userdata);
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
if (!name) if (!name)
goto LBL_ERR; goto err_sm;
if (strcmp(name, "enabled") == 0) { if (strcmp(name, "enabled") == 0) {
conn->sm_state->sm_enabled = 1;
conn->sm_state->sm_handled_nr = 0; conn->sm_state->sm_handled_nr = 0;
resume = xmpp_stanza_get_attribute(stanza, "resume"); resume = xmpp_stanza_get_attribute(stanza, "resume");
if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) { if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) {
@@ -1179,11 +1407,17 @@ static int _handle_sm(xmpp_conn_t *const conn,
"SM error: server said it can resume, but " "SM error: server said it can resume, but "
"didn't provide an ID."); "didn't provide an ID.");
name = NULL; name = NULL;
goto LBL_ERR; goto err_sm;
} }
conn->sm_state->can_resume = 1; conn->sm_state->can_resume = 1;
conn->sm_state->id = strophe_strdup(conn->ctx, id); conn->sm_state->id = strophe_strdup(conn->ctx, id);
} }
/* We maybe have stuff in the SM queue if we tried to resume, but the
* server doesn't remember all details of our session, but the `h` was
* still available.
*/
_sm_queue_resend(conn);
_stream_negotiation_success(conn);
} else if (strcmp(name, "resumed") == 0) { } else if (strcmp(name, "resumed") == 0) {
previd = xmpp_stanza_get_attribute(stanza, "previd"); previd = xmpp_stanza_get_attribute(stanza, "previd");
if (!previd || strcmp(previd, conn->sm_state->previd)) { if (!previd || strcmp(previd, conn->sm_state->previd)) {
@@ -1191,16 +1425,11 @@ static int _handle_sm(xmpp_conn_t *const conn,
"SM error: previd didn't match, ours is \"%s\".", "SM error: previd didn't match, ours is \"%s\".",
conn->sm_state->previd); conn->sm_state->previd);
name = NULL; name = NULL;
goto LBL_ERR; goto err_sm;
} }
h = xmpp_stanza_get_attribute(stanza, "h"); if (_get_h_attribute(stanza, &ul_h)) {
if (!h || string_to_ul(h, &ul_h)) {
strophe_error(conn->ctx, "xmpp",
"SM error: failed parsing 'h', it got converted "
"to %llu.",
ul_h);
name = NULL; name = NULL;
goto LBL_ERR; goto err_sm;
} }
conn->sm_state->sm_enabled = 1; conn->sm_state->sm_enabled = 1;
conn->sm_state->id = conn->sm_state->previd; conn->sm_state->id = conn->sm_state->previd;
@@ -1211,54 +1440,53 @@ static int _handle_sm(xmpp_conn_t *const conn,
conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h; conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h;
else else
conn->sm_state->sm_sent_nr = ul_h; conn->sm_state->sm_sent_nr = ul_h;
while ((e = pop_queue_front(&conn->sm_state->sm_queue))) { _sm_queue_cleanup(conn, ul_h);
if (e->sm_h >= ul_h) { _sm_queue_resend(conn);
/* Re-send what was already sent out and is still in the
* SM queue (i.e. it hasn't been ACK'ed by the server)
*/
send_raw(conn, e->data, e->len, e->owner, NULL);
}
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
}
strophe_debug(conn->ctx, "xmpp", "Session resumed successfully."); strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
_auth_success(conn); _stream_negotiation_success(conn);
} else if (strcmp(name, "failed") == 0) { } else if (strcmp(name, "failed") == 0) {
name = NULL; name = NULL;
conn->sm_state->sm_enabled = 0;
failed_cause = failed_cause =
xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF); xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF);
if (!failed_cause) if (!failed_cause)
goto LBL_ERR; goto err_sm;
cause = xmpp_stanza_get_name(failed_cause); cause = xmpp_stanza_get_name(failed_cause);
if (!cause) if (!cause)
goto LBL_ERR; goto err_sm;
if (!strcmp(cause, "item-not-found") || if (!strcmp(cause, "item-not-found")) {
!strcmp(cause, "feature-not-implemented")) {
if (conn->sm_state->resume) { if (conn->sm_state->resume) {
conn->sm_state->resume = 0; /* It's no error if there's no `h` attribute included
conn->sm_state->can_resume = 0; * but if there is, it gives a hint at what the server
/* remember that the server reports having support * already received.
* for resumption, but actually it doesn't ...
*/ */
conn->sm_state->dont_request_resume = if (!_get_h_attribute(stanza, &ul_h)) {
!strcmp(cause, "feature-not-implemented"); /* In cases there's no `h` included, drop all elements. */
strophe_free(conn->ctx, conn->sm_state->previd); ul_h = (unsigned long)-1;
conn->sm_state->previd = NULL; }
strophe_free(conn->ctx, conn->sm_state->bound_jid); _sm_queue_cleanup(conn, ul_h);
conn->sm_state->bound_jid = NULL;
_do_bind(conn, conn->sm_state->bind);
conn->sm_state->bind = NULL;
} }
} else if (!strcmp(cause, "feature-not-implemented")) {
conn->sm_state->resume = 0;
conn->sm_state->can_resume = 0;
/* remember that the server reports having support
* for resumption, but actually it doesn't ...
*/
conn->sm_state->dont_request_resume = 1;
} }
conn->sm_state->sm_handled_nr = 0; bind = conn->sm_state->bind;
conn->sm_state->bind = NULL;
reset_sm_state(conn->sm_state);
_do_bind(conn, bind);
} else { } else {
/* unknown stanza received */ /* unknown stanza received */
name = NULL; name = NULL;
} }
LBL_ERR: err_sm:
if (!name) { if (!name) {
char *err = "Couldn't convert stanza to text!"; char *err = "Couldn't convert stanza to text!";
char *buf; char *buf;
@@ -1277,7 +1505,8 @@ LBL_ERR:
buf); buf);
if (buf != err) if (buf != err)
strophe_free(conn->ctx, buf); strophe_free(conn->ctx, buf);
conn->sm_state->sm_enabled = 0; /* Don't disable for <failure> cases, they're no hard errors */
conn->sm_state->sm_enabled = bind != NULL;
} }
return 0; return 0;
} }
@@ -1310,7 +1539,7 @@ _handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* auth succeeded */ /* auth succeeded */
strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded."); strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
_auth_success(conn); _stream_negotiation_success(conn);
} else { } else {
strophe_error(conn->ctx, "xmpp", strophe_error(conn->ctx, "xmpp",
"Server sent us a legacy authentication " "Server sent us a legacy authentication "
@@ -1500,7 +1729,7 @@ int _handle_component_hs_response(xmpp_conn_t *conn,
xmpp_disconnect(conn); xmpp_disconnect(conn);
return XMPP_EINT; return XMPP_EINT;
} else { } else {
_auth_success(conn); _stream_negotiation_success(conn);
} }
/* We don't need this handler anymore, return 0 so it can be deleted /* We don't need this handler anymore, return 0 so it can be deleted
@@ -1522,8 +1751,8 @@ int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata)
void auth_handle_open_raw(xmpp_conn_t *conn) void auth_handle_open_raw(xmpp_conn_t *conn)
{ {
handler_reset_timed(conn, 0); handler_reset_timed(conn, 0);
/* user handlers are not called before authentication is completed. */ /* user handlers are not called before stream negotiation has completed. */
_auth_success(conn); _stream_negotiation_success(conn);
} }
void auth_handle_open_stub(xmpp_conn_t *conn) void auth_handle_open_stub(xmpp_conn_t *conn)

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* common.h /* common.h
** strophe XMPP client library -- internal common structures ** strophe XMPP client library -- internal common structures
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -92,6 +93,13 @@ void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s); char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s);
char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len); char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
void strophe_free(const xmpp_ctx_t *ctx, void *p); void strophe_free(const xmpp_ctx_t *ctx, void *p);
#define strophe_free_and_null(ctx, p) \
do { \
if (p) { \
strophe_free(ctx, (p)); \
(p) = NULL; \
} \
} while (0)
/* wrappers for xmpp_log at specific levels */ /* wrappers for xmpp_log at specific levels */
void strophe_error(const xmpp_ctx_t *ctx, void strophe_error(const xmpp_ctx_t *ctx,
@@ -119,6 +127,12 @@ void strophe_log_internal(const xmpp_ctx_t *ctx,
const char *fmt, const char *fmt,
va_list ap); va_list ap);
#if defined(__OpenBSD__)
#define STR_MAYBE_NULL(p) (p) ? (p) : "(null)"
#else
#define STR_MAYBE_NULL(p) (p)
#endif
/** connection **/ /** connection **/
/* opaque connection object */ /* opaque connection object */
@@ -159,9 +173,16 @@ struct _xmpp_send_queue_t {
#define SASL_MASK_SCRAMSHA256 (1 << 4) #define SASL_MASK_SCRAMSHA256 (1 << 4)
#define SASL_MASK_SCRAMSHA512 (1 << 5) #define SASL_MASK_SCRAMSHA512 (1 << 5)
#define SASL_MASK_EXTERNAL (1 << 6) #define SASL_MASK_EXTERNAL (1 << 6)
#define SASL_MASK_SCRAMSHA1_PLUS (1 << 7)
#define SASL_MASK_SCRAMSHA256_PLUS (1 << 8)
#define SASL_MASK_SCRAMSHA512_PLUS (1 << 9)
#define SASL_MASK_SCRAM \ #define SASL_MASK_SCRAM_PLUS \
(SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS | \
SASL_MASK_SCRAMSHA512_PLUS)
#define SASL_MASK_SCRAM_WEAK \
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512) (SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
#define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK)
enum { enum {
XMPP_PORT_CLIENT = 5222, XMPP_PORT_CLIENT = 5222,
@@ -180,14 +201,36 @@ struct _xmpp_sm_t {
int sm_support; int sm_support;
int sm_enabled; int sm_enabled;
int can_resume, resume, dont_request_resume; int can_resume, resume, dont_request_resume;
xmpp_queue_t sm_queue;
int r_sent;
uint32_t sm_handled_nr; uint32_t sm_handled_nr;
uint32_t sm_sent_nr; uint32_t sm_sent_nr;
xmpp_queue_t sm_queue;
char *id, *previd, *bound_jid; char *id, *previd, *bound_jid;
xmpp_stanza_t *bind; xmpp_stanza_t *bind;
}; };
struct conn_interface {
int (*read)(struct conn_interface *intf, void *buff, size_t len);
int (*write)(struct conn_interface *intf, const void *buff, size_t len);
int (*flush)(struct conn_interface *intf);
int (*pending)(struct conn_interface *intf);
int (*get_error)(struct conn_interface *intf);
int (*error_is_recoverable)(struct conn_interface *intf, int err);
xmpp_conn_t *conn;
};
int conn_interface_write(struct conn_interface *intf,
const void *buff,
size_t len);
int conn_int_nop(struct conn_interface *intf);
int compression_init(xmpp_conn_t *conn);
void compression_free(xmpp_conn_t *conn);
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text);
struct _xmpp_conn_t { struct _xmpp_conn_t {
struct conn_interface intf;
unsigned int ref; unsigned int ref;
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_type_t type; xmpp_conn_type_t type;
@@ -235,6 +278,12 @@ struct _xmpp_conn_t {
int sm_disable; int sm_disable;
xmpp_sm_state_t *sm_state; xmpp_sm_state_t *sm_state;
struct {
struct xmpp_compression *state;
int allowed, dont_reset, level;
int supported;
} compression;
char *lang; char *lang;
char *domain; char *domain;
char *jid; char *jid;
@@ -262,8 +311,9 @@ struct _xmpp_conn_t {
/* stream open handler */ /* stream open handler */
xmpp_open_handler open_handler; xmpp_open_handler open_handler;
/* user handlers only get called after authentication */ /* user handlers only get called after the stream negotiation has completed
int authenticated; */
int stream_negotiation_completed;
/* connection events handler */ /* connection events handler */
xmpp_conn_handler conn_handler; xmpp_conn_handler conn_handler;
@@ -327,6 +377,7 @@ void handler_add(xmpp_conn_t *conn,
void handler_system_delete_all(xmpp_conn_t *conn); void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */ /* utility functions */
void reset_sm_state(xmpp_sm_state_t *sm_state);
void disconnect_mem_error(xmpp_conn_t *conn); void disconnect_mem_error(xmpp_conn_t *conn);
/* auth functions */ /* auth functions */
@@ -337,6 +388,7 @@ void auth_handle_open_stub(xmpp_conn_t *conn);
/* queue functions */ /* queue functions */
void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item); void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item);
xmpp_send_queue_t *peek_queue_front(xmpp_queue_t *queue);
xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue); xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue);
char *queue_element_free(xmpp_ctx_t *ctx, xmpp_send_queue_t *e); char *queue_element_free(xmpp_ctx_t *ctx, xmpp_send_queue_t *e);

270
src/compression.c Normal file
View File

@@ -0,0 +1,270 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* compression.c
** strophe XMPP client library -- XEP-0138 Stream Compression
**
** Copyright (C) 2024 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT or GPLv3 licenses.
*/
/** @file
* XEP-0138 Stream Compression.
*/
#include <zlib.h>
#include <string.h>
#include <errno.h>
#include "common.h"
#ifndef STROPHE_COMPRESSION_BUFFER_SIZE
/** Max buffer size for compressed data (send & receive). */
#define STROPHE_COMPRESSION_BUFFER_SIZE 4096
#endif
struct zlib_compression {
void *buffer, *buffer_end;
z_stream stream;
};
struct xmpp_compression {
xmpp_conn_t *conn;
struct zlib_compression compression, decompression;
struct conn_interface next;
};
static int _conn_decompress(struct xmpp_compression *comp,
size_t c_len,
void *buff,
size_t len)
{
if (comp->decompression.stream.next_in == NULL) {
comp->decompression.stream.next_in = comp->decompression.buffer;
comp->decompression.buffer_end =
comp->decompression.stream.next_in + c_len;
comp->decompression.stream.avail_in = c_len;
} else if (c_len) {
strophe_error(comp->conn->ctx, "zlib",
"_conn_decompress() called with c_len=%zu", c_len);
}
comp->decompression.stream.next_out = buff;
comp->decompression.stream.avail_out = len;
int ret = inflate(&comp->decompression.stream, Z_SYNC_FLUSH);
switch (ret) {
case Z_STREAM_END:
case Z_OK:
if (comp->decompression.buffer_end ==
comp->decompression.stream.next_in)
comp->decompression.stream.next_in = NULL;
return comp->decompression.stream.next_out - (Bytef *)buff;
case Z_BUF_ERROR:
break;
default:
strophe_error(comp->conn->ctx, "zlib", "inflate error %d", ret);
comp->conn->error = ret;
conn_disconnect(comp->conn);
break;
}
return 0;
}
static int compression_read(struct conn_interface *intf, void *buff, size_t len)
{
xmpp_conn_t *conn = intf->conn;
struct xmpp_compression *comp = conn->compression.state;
void *dbuff = buff;
size_t dlen = len;
if (comp->decompression.stream.next_in != NULL) {
return _conn_decompress(comp, 0, buff, len);
}
dbuff = comp->decompression.buffer;
dlen = STROPHE_COMPRESSION_BUFFER_SIZE;
int ret = comp->next.read(intf, dbuff, dlen);
if (ret > 0) {
return _conn_decompress(comp, ret, buff, len);
}
return ret;
}
static int _try_compressed_write_to_network(xmpp_conn_t *conn, int force)
{
struct xmpp_compression *comp = conn->compression.state;
int ret = 0;
ptrdiff_t len =
comp->compression.stream.next_out - (Bytef *)comp->compression.buffer;
int buffer_full =
comp->compression.stream.next_out == comp->compression.buffer_end;
if ((buffer_full || force) && len > 0) {
ret = conn_interface_write(&comp->next, comp->compression.buffer, len);
if (ret < 0)
return ret;
comp->compression.stream.next_out = comp->compression.buffer;
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
}
return ret;
}
static int
_compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
{
int ret;
const void *buff_end = buff + len;
struct xmpp_compression *comp = conn->compression.state;
comp->compression.stream.next_in = (Bytef *)buff;
comp->compression.stream.avail_in = len;
do {
ret = _try_compressed_write_to_network(conn, 0);
if (ret < 0) {
return ret;
}
ret = deflate(&comp->compression.stream, flush);
if (ret == Z_STREAM_END) {
break;
}
if (flush && ret == Z_BUF_ERROR) {
break;
}
if (ret != Z_OK) {
strophe_error(conn->ctx, "zlib", "deflate error %d", ret);
conn->error = ret;
conn_disconnect(conn);
return ret;
}
ret = comp->compression.stream.next_in - (Bytef *)buff;
} while (comp->compression.stream.next_in < (Bytef *)buff_end);
if (flush) {
ret = _try_compressed_write_to_network(conn, 1);
if (ret < 0) {
return ret;
}
}
return ret;
}
static int
compression_write(struct conn_interface *intf, const void *buff, size_t len)
{
return _compression_write(intf->conn, buff, len, Z_NO_FLUSH);
}
static int compression_flush(struct conn_interface *intf)
{
xmpp_conn_t *conn = intf->conn;
struct xmpp_compression *comp = conn->compression.state;
return _compression_write(conn, comp->compression.buffer, 0,
conn->compression.dont_reset ? Z_SYNC_FLUSH
: Z_FULL_FLUSH);
}
static int compression_pending(struct conn_interface *intf)
{
xmpp_conn_t *conn = intf->conn;
struct xmpp_compression *comp = conn->compression.state;
return comp->decompression.stream.next_in != NULL ||
comp->next.pending(intf);
}
static int compression_get_error(struct conn_interface *intf)
{
struct conn_interface *next = &intf->conn->compression.state->next;
return next->get_error(next);
}
static int compression_is_recoverable(struct conn_interface *intf, int err)
{
struct conn_interface *next = &intf->conn->compression.state->next;
return next->error_is_recoverable(next, err);
}
static const struct conn_interface compression_intf = {
compression_read,
compression_write,
compression_flush,
compression_pending,
compression_get_error,
compression_is_recoverable,
NULL,
};
static void *_zlib_alloc(void *opaque, unsigned int items, unsigned int size)
{
size_t sz = items * size;
/* Poor man's multiplication overflow check */
if (sz < items || sz < size)
return NULL;
return strophe_alloc(opaque, sz);
}
static void _init_zlib_compression(xmpp_ctx_t *ctx, struct zlib_compression *s)
{
s->buffer = strophe_alloc(ctx, STROPHE_COMPRESSION_BUFFER_SIZE);
s->buffer_end = s->buffer + STROPHE_COMPRESSION_BUFFER_SIZE;
s->stream.opaque = ctx;
s->stream.zalloc = _zlib_alloc;
s->stream.zfree = (free_func)strophe_free;
}
int compression_init(xmpp_conn_t *conn)
{
if (!conn->compression.allowed || !conn->compression.supported)
return -1;
conn->compression.state =
strophe_alloc(conn->ctx, sizeof(*conn->compression.state));
struct xmpp_compression *comp = conn->compression.state;
memset(comp, 0, sizeof(*comp));
comp->conn = conn;
comp->next = conn->intf;
conn->intf = compression_intf;
conn->intf.conn = conn;
_init_zlib_compression(conn->ctx, &comp->compression);
comp->compression.stream.next_out = comp->compression.buffer;
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
int ret = deflateInit(&comp->compression.stream, conn->compression.level);
if (ret != Z_OK) {
strophe_free_and_null(conn->ctx, comp->compression.buffer);
conn->error = ret;
conn_disconnect(conn);
return ret;
}
_init_zlib_compression(conn->ctx, &comp->decompression);
ret = inflateInit(&comp->decompression.stream);
if (ret != Z_OK) {
strophe_free_and_null(conn->ctx, comp->decompression.buffer);
conn->error = ret;
conn_disconnect(conn);
return ret;
}
return 0;
}
void compression_free(xmpp_conn_t *conn)
{
struct xmpp_compression *comp = conn->compression.state;
if (!comp)
return;
if (comp->compression.buffer) {
deflateEnd(&comp->compression.stream);
strophe_free_and_null(conn->ctx, comp->compression.buffer);
}
if (comp->decompression.buffer) {
inflateEnd(&comp->decompression.stream);
strophe_free_and_null(conn->ctx, comp->decompression.buffer);
}
}
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text)
{
if (strcasecmp(text, "zlib") == 0) {
conn->compression.supported = 1;
}
}

36
src/compression_dummy.c Normal file
View File

@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* compression_dummy.c
** strophe XMPP client library -- Dummy Compression
**
** Copyright (C) 2024 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT or GPLv3 licenses.
*/
/** @file
* Dummy Compression.
*/
#include <strings.h>
#include <errno.h>
#include "common.h"
int compression_init(xmpp_conn_t *conn)
{
conn->compression.supported = 0;
return -1;
}
void compression_free(xmpp_conn_t *conn)
{
UNUSED(conn);
}
void compression_handle_feature_children(xmpp_conn_t *conn, const char *text)
{
UNUSED(text);
conn->compression.supported = 0;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* conn.c /* conn.c
** strophe XMPP client library -- connection object functions ** strophe XMPP client library -- connection object functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -77,6 +78,7 @@
#define KEEPALIVE_COUNT 3 #define KEEPALIVE_COUNT 3
#endif #endif
static int _is_connected(xmpp_conn_t *conn, xmpp_send_queue_owner_t owner);
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata); static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn); static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn);
static char *_conn_build_stream_tag(xmpp_conn_t *conn, static char *_conn_build_stream_tag(xmpp_conn_t *conn,
@@ -140,28 +142,19 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
conn = strophe_alloc(ctx, sizeof(xmpp_conn_t)); conn = strophe_alloc(ctx, sizeof(xmpp_conn_t));
if (conn != NULL) { if (conn != NULL) {
memset(conn, 0, sizeof(xmpp_conn_t));
conn->ctx = ctx; conn->ctx = ctx;
conn->type = XMPP_UNKNOWN; conn->type = XMPP_UNKNOWN;
conn->state = XMPP_STATE_DISCONNECTED; conn->state = XMPP_STATE_DISCONNECTED;
conn->xsock = NULL;
conn->sock = INVALID_SOCKET; conn->sock = INVALID_SOCKET;
conn->ka_timeout = KEEPALIVE_TIMEOUT; conn->ka_timeout = KEEPALIVE_TIMEOUT;
conn->ka_interval = KEEPALIVE_INTERVAL; conn->ka_interval = KEEPALIVE_INTERVAL;
conn->ka_count = KEEPALIVE_COUNT; conn->ka_count = KEEPALIVE_COUNT;
conn->tls = NULL;
conn->timeout_stamp = 0;
conn->error = 0;
conn->stream_error = NULL;
/* default send parameters */ /* default send parameters */
conn->blocking_send = 0;
conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX; conn->send_queue_max = DEFAULT_SEND_QUEUE_MAX;
conn->send_queue_len = 0;
conn->send_queue_user_len = 0;
conn->send_queue_head = NULL;
conn->send_queue_tail = NULL;
/* default timeouts */ /* default timeouts */
conn->connect_timeout = CONNECT_TIMEOUT; conn->connect_timeout = CONNECT_TIMEOUT;
@@ -171,49 +164,16 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
strophe_free(conn->ctx, conn); strophe_free(conn->ctx, conn);
return NULL; return NULL;
} }
conn->domain = NULL;
conn->jid = NULL;
conn->pass = NULL;
conn->stream_id = NULL;
conn->bound_jid = NULL;
conn->is_raw = 0;
conn->tls_support = 0;
conn->tls_disabled = 0;
conn->tls_mandatory = 0;
conn->tls_legacy_ssl = 0;
conn->tls_trust = 0;
conn->tls_failed = 0;
conn->tls_cafile = NULL;
conn->tls_capath = NULL;
conn->tls_client_cert = NULL;
conn->tls_client_key = NULL;
conn->sasl_support = 0;
conn->auth_legacy_enabled = 0;
conn->secured = 0;
conn->certfail_handler = NULL;
conn->password_callback = NULL;
conn->password_callback_userdata = NULL;
tls_clear_password_cache(conn); tls_clear_password_cache(conn);
conn->password_retries = 1; conn->password_retries = 1;
conn->bind_required = 0; conn->compression.level = -1;
conn->session_required = 0;
conn->sm_state = NULL;
conn->parser = conn->parser =
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end, parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
_handle_stream_stanza, conn); _handle_stream_stanza, conn);
conn->reset_parser = 0;
conn->authenticated = 0;
conn->conn_handler = NULL;
conn->userdata = NULL;
conn->timed_handlers = NULL;
/* we own (and will free) the hash values */ /* we own (and will free) the hash values */
conn->id_handlers = hash_new(conn->ctx, 32, NULL); conn->id_handlers = hash_new(conn->ctx, 32, NULL);
conn->handlers = NULL;
conn->sockopt_cb = NULL;
/* give the caller a reference to connection */ /* give the caller a reference to connection */
conn->ref = 1; conn->ref = 1;
@@ -259,32 +219,6 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn)
return conn; return conn;
} }
/** Register sockopt callback
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started.
*
* If the connection is already connected, this callback will be called
* immediately.
*
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn The Strophe connection object this callback is being registered
* for
* @param callback a xmpp_sockopt_callback callback function that will receive
* notifications of connection status
*
* @ingroup Connections
*/
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback)
{
conn->sockopt_cb = callback;
if (conn->state != XMPP_STATE_DISCONNECTED)
callback(conn, &conn->sock);
}
/** Release a Strophe connection object. /** Release a Strophe connection object.
* Decrement the reference count by one for a connection, freeing the * Decrement the reference count by one for a connection, freeing the
* connection object if the count reaches 0. * connection object if the count reaches 0.
@@ -408,6 +342,204 @@ int xmpp_conn_release(xmpp_conn_t *conn)
return released; return released;
} }
/** Configure a connection-related int setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_RETRIES
* Set the number of retry attempts to decrypt a private key file. \n
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* - \ref XMPP_SETTING_COMPRESSION_LEVEL
* Set the compression level. \n
* For zlib the valid range is `-1` to `9`.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_int(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
int value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_RETRIES:
if (value <= 0)
conn->password_retries = 1;
else
conn->password_retries = value;
break;
case XMPP_SETTING_COMPRESSION_LEVEL:
conn->compression.level = value;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Int setting %d", setting);
return;
}
}
/** Configure a connection-related string setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_JID
* Set the JID of the user that will be bound to the connection. \n
* This should not be used after a connection is created. \n
* If the supplied JID is missing the node, SASL ANONYMOUS authentication
* will be used.
*
* - \ref XMPP_SETTING_PASS
* Set the password used to authenticate the connection.
*
* - \ref XMPP_SETTING_CAFILE
* Set CAfile.
*
* - \ref XMPP_SETTING_CAPATH
* Set CApath.
*
* - \ref XMPP_SETTING_CLIENT_CERT
* Set the Client Certificate or PKCS#12 encoded file that will be bound to
* the connection. \n
* This should not be used after a connection is created. \n
* In case the PKCS#12 file is encrypted, a callback must be set via
* \ref xmpp_conn_set_functionpointer with the option
* \ref XMPP_SETTING_PASSWORD_CALLBACK so the TLS stack can retrieve the
* password.
*
* - \ref XMPP_SETTING_CLIENT_KEY
* Set the Private Key that will be bound to the connection. \n
* This should not be used after a connection is created. \n
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_functionpointer with the option
* \ref XMPP_SETTING_PASSWORD_CALLBACK so the TLS stack can retrieve the
* password.
*
*
*
* If any value was previously set, it will be discarded.
* The function will make a copy of the value given.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_string(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
const char *value)
{
char **target;
switch (setting) {
case XMPP_SETTING_JID:
target = &conn->jid;
break;
case XMPP_SETTING_PASS:
target = &conn->pass;
break;
case XMPP_SETTING_CAFILE:
target = &conn->tls_cafile;
break;
case XMPP_SETTING_CAPATH:
target = &conn->tls_capath;
break;
case XMPP_SETTING_CLIENT_CERT:
target = &conn->tls_client_cert;
break;
case XMPP_SETTING_CLIENT_KEY:
target = &conn->tls_client_key;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid String setting %d", setting);
return;
}
if (*target)
strophe_free(conn->ctx, *target);
*target = NULL;
if (value) {
*target = strophe_strdup(conn->ctx, value);
}
}
/** Configure a connection-related pointer setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_CALLBACK_USERDATA
* Set the userdata pointer that is pass when the password-retrieval
* callback is called. \ref XMPP_SETTING_PASSWORD_CALLBACK
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_pointer(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
void *value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_CALLBACK_USERDATA:
conn->password_callback_userdata = value;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Pointer setting %d", setting);
return;
}
}
/** Configure a connection-related functionpointer setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_CALLBACK
* Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file. The userdata pointer can be set
* via \ref xmpp_conn_set_pointer with the setting
* \ref XMPP_SETTING_PASSWORD_CALLBACK_USERDATA
*
* - \ref XMPP_SETTING_CERTFAIL_HANDLER
* Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* - \ref XMPP_SETTING_SOCKOPT_CALLBACK
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started. \n
* If the connection is already connected, this callback will be called
* immediately. \n
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_functionpointer_impl(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
xmpp_conn_pfn_t value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_CALLBACK:
conn->password_callback = (xmpp_password_callback)value;
break;
case XMPP_SETTING_CERTFAIL_HANDLER:
conn->certfail_handler = (xmpp_certfail_handler)value;
break;
case XMPP_SETTING_SOCKOPT_CALLBACK:
conn->sockopt_cb = (xmpp_sockopt_callback)value;
if (conn->state != XMPP_STATE_DISCONNECTED)
conn->sockopt_cb(conn, &conn->sock);
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Functionpointer setting %d",
setting);
return;
}
}
/** Get the JID which is or will be bound to the connection. /** Get the JID which is or will be bound to the connection.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -439,66 +571,6 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn)
return conn->bound_jid; return conn->bound_jid;
} }
/** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL
* ANONYMOUS authentication will be used.
*
* @param conn a Strophe connection object
* @param jid a full or bare JID
*
* @ingroup Connections
*/
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
if (conn->jid)
strophe_free(conn->ctx, conn->jid);
conn->jid = strophe_strdup(conn->ctx, jid);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup TLS
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
conn->certfail_handler = hndl;
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param path path to a certificate file
*
* @ingroup TLS
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_cafile)
strophe_free(conn->ctx, conn->tls_cafile);
conn->tls_cafile = strophe_strdup(conn->ctx, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param path path to a folder containing certificates
*
* @ingroup TLS
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_capath)
strophe_free(conn->ctx, conn->tls_capath);
conn->tls_capath = strophe_strdup(conn->ctx, path);
}
/** Retrieve the peer certificate /** Retrieve the peer certificate
* *
* The returned Certificate object must be free'd by calling * The returned Certificate object must be free'd by calling
@@ -515,41 +587,6 @@ xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
return tls_peer_cert(conn); return tls_peer_cert(conn);
} }
/** Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* @param conn a Strophe connection object
* @param cb The callback function that shall be called
* @param userdata An opaque data pointer that will be passed to the callback
*
* @ingroup TLS
*/
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata)
{
conn->password_callback = cb;
conn->password_callback_userdata = userdata;
}
/** Set the number of retry attempts to decrypt a private key file.
*
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* @param conn a Strophe connection object
* @param retries The number of retries that should be tried
*
* @ingroup TLS
*/
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries)
{
if (retries == 0)
conn->password_retries = 1;
else
conn->password_retries = retries;
}
/** Retrieve the path of the key file that shall be unlocked. /** Retrieve the path of the key file that shall be unlocked.
* *
* This makes usually sense to be called from the * This makes usually sense to be called from the
@@ -566,49 +603,6 @@ const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn)
return conn->tls_client_key; return conn->tls_client_key;
} }
/** Set the Client Certificate and Private Key or PKCS#12 encoded file that
* will be bound to the connection. If any of them was previously set, it
* will be discarded. This should not be used after a connection is created.
* The function will make a copy of the strings passed in.
*
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup TLS
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (conn->tls_client_cert)
strophe_free(conn->ctx, conn->tls_client_cert);
conn->tls_client_cert = NULL;
if (conn->tls_client_key)
strophe_free(conn->ctx, conn->tls_client_key);
conn->tls_client_key = NULL;
if (cert && key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
} else if (cert && !key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
} else if (!cert && key) {
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
conn->tls_client_cert = strophe_strdup(conn->ctx, key);
}
}
/** Get the number of xmppAddr entries in the client certificate. /** Get the number of xmppAddr entries in the client certificate.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -649,22 +643,6 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t *conn)
return conn->pass; return conn->pass;
} }
/** Set the password used to authenticate the connection.
* If any password was previously set, it will be discarded. The function
* will make a copy of the password string.
*
* @param conn a Strophe connection object
* @param pass the password
*
* @ingroup Connections
*/
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
if (conn->pass)
strophe_free(conn->ctx, conn->pass);
conn->pass = pass ? strophe_strdup(conn->ctx, pass) : NULL;
}
/** Get the strophe context that the connection is associated with. /** Get the strophe context that the connection is associated with.
* @param conn a Strophe connection object * @param conn a Strophe connection object
* *
@@ -798,7 +776,8 @@ int xmpp_connect_component(xmpp_conn_t *conn,
return XMPP_EINVOP; return XMPP_EINVOP;
/* XEP-0114 does not support TLS */ /* XEP-0114 does not support TLS */
xmpp_conn_disable_tls(conn); (void)xmpp_conn_set_flags(conn, xmpp_conn_get_flags(conn) |
XMPP_CONN_FLAG_DISABLE_TLS);
if (!conn->tls_disabled) { if (!conn->tls_disabled) {
strophe_error(conn->ctx, "conn", strophe_error(conn->ctx, "conn",
"Failed to disable TLS. " "Failed to disable TLS. "
@@ -862,9 +841,10 @@ void conn_established(xmpp_conn_t *conn)
if (conn->is_raw) { if (conn->is_raw) {
handler_reset_timed(conn, 0); handler_reset_timed(conn, 0);
/* we skip authentication for a "raw" connection, but the event loop /* we skip all the mandatory steps of the stream negotiation for a "raw"
ignores user's handlers when conn->authenticated is not set. */ connection, but the event loop ignores user's handlers when
conn->authenticated = 1; conn->stream_negotiation_completed is not set. */
conn->stream_negotiation_completed = 1;
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL, conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL,
conn->userdata); conn->userdata);
} else { } else {
@@ -958,6 +938,7 @@ void conn_disconnect(xmpp_conn_t *conn)
{ {
strophe_debug(conn->ctx, "xmpp", "Closing socket."); strophe_debug(conn->ctx, "xmpp", "Closing socket.");
conn->state = XMPP_STATE_DISCONNECTED; conn->state = XMPP_STATE_DISCONNECTED;
conn->stream_negotiation_completed = 0;
if (conn->tls) { if (conn->tls) {
tls_stop(conn->tls); tls_stop(conn->tls);
tls_free(conn->tls); tls_free(conn->tls);
@@ -1026,7 +1007,7 @@ void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...)
{ {
va_list ap; va_list ap;
if (conn->state != XMPP_STATE_CONNECTED) if (!_is_connected(conn, XMPP_QUEUE_USER))
return; return;
va_start(ap, fmt); va_start(ap, fmt);
@@ -1101,6 +1082,23 @@ void conn_open_stream(xmpp_conn_t *conn)
strophe_free(conn->ctx, from); strophe_free(conn->ctx, from);
} }
int conn_interface_write(struct conn_interface *intf,
const void *buff,
size_t len)
{
int ret = intf->write(intf, buff, len);
if (ret < 0 && !intf->error_is_recoverable(intf, intf->get_error(intf))) {
intf->conn->error = intf->get_error(intf);
}
return ret;
}
int conn_int_nop(struct conn_interface *intf)
{
UNUSED(intf);
return 0;
}
int conn_tls_start(xmpp_conn_t *conn) int conn_tls_start(xmpp_conn_t *conn)
{ {
int rc; int rc;
@@ -1114,14 +1112,18 @@ int conn_tls_start(xmpp_conn_t *conn)
} }
if (conn->tls != NULL) { if (conn->tls != NULL) {
struct conn_interface old_intf = conn->intf;
conn->intf = tls_intf;
conn->intf.conn = conn;
if (tls_start(conn->tls)) { if (tls_start(conn->tls)) {
conn->secured = 1; conn->secured = 1;
} else { } else {
rc = XMPP_EINT; rc = XMPP_EINT;
conn->error = tls_error(conn->tls); conn->error = tls_error(&conn->intf);
tls_free(conn->tls); tls_free(conn->tls);
conn->tls = NULL; conn->tls = NULL;
conn->tls_failed = 1; conn->tls_failed = 1;
conn->intf = old_intf;
} }
} }
if (rc != 0) { if (rc != 0) {
@@ -1145,11 +1147,15 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
{ {
long flags; long flags;
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled | flags =
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory | XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl | XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust | XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled; XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable |
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression.allowed |
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * conn->compression.dont_reset |
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
return flags; return flags;
} }
@@ -1163,12 +1169,14 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
* *
* Supported flags are: * Supported flags are:
* *
* - XMPP_CONN_FLAG_DISABLE_TLS * - \ref XMPP_CONN_FLAG_DISABLE_TLS
* - XMPP_CONN_FLAG_MANDATORY_TLS * - \ref XMPP_CONN_FLAG_MANDATORY_TLS
* - XMPP_CONN_FLAG_LEGACY_SSL * - \ref XMPP_CONN_FLAG_LEGACY_SSL
* - XMPP_CONN_FLAG_TRUST_TLS * - \ref XMPP_CONN_FLAG_TRUST_TLS
* - XMPP_CONN_FLAG_LEGACY_AUTH * - \ref XMPP_CONN_FLAG_LEGACY_AUTH
* - XMPP_CONN_FLAG_DISABLE_SM * - \ref XMPP_CONN_FLAG_DISABLE_SM
* - \ref XMPP_CONN_FLAG_ENABLE_COMPRESSION
* - \ref XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param flags ORed connection flags * @param flags ORed connection flags
@@ -1198,29 +1206,23 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags)
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0; conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0; conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0;
conn->sm_disable = (flags & XMPP_CONN_FLAG_DISABLE_SM) ? 1 : 0; conn->sm_disable = (flags & XMPP_CONN_FLAG_DISABLE_SM) ? 1 : 0;
conn->compression.allowed =
(flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0;
conn->compression.dont_reset =
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_RESET) ? 1 : 0;
flags &= ~(XMPP_CONN_FLAG_DISABLE_TLS | XMPP_CONN_FLAG_MANDATORY_TLS |
XMPP_CONN_FLAG_LEGACY_SSL | XMPP_CONN_FLAG_TRUST_TLS |
XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM |
XMPP_CONN_FLAG_ENABLE_COMPRESSION |
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET);
if (flags) {
strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags);
return XMPP_EINVOP;
}
return 0; return 0;
} }
/** Disable TLS for this connection, called by users of the library.
* Occasionally a server will be misconfigured to send the starttls
* feature, but will not support the handshake.
*
* @param conn a Strophe connection object
*
* @note this function is deprecated
* @see xmpp_conn_set_flags()
*
* @ingroup Connections
*/
void xmpp_conn_disable_tls(xmpp_conn_t *conn)
{
long flags = xmpp_conn_get_flags(conn);
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
(void)xmpp_conn_set_flags(conn, flags);
}
/** Return whether TLS session is established or not. /** Return whether TLS session is established or not.
* *
* @return TRUE if TLS session is established and FALSE otherwise * @return TRUE if TLS session is established and FALSE otherwise
@@ -1239,17 +1241,26 @@ int xmpp_conn_is_secured(xmpp_conn_t *conn)
*/ */
int xmpp_conn_is_connecting(xmpp_conn_t *conn) int xmpp_conn_is_connecting(xmpp_conn_t *conn)
{ {
return conn->state == XMPP_STATE_CONNECTING; return conn->state == XMPP_STATE_CONNECTING ||
(conn->state == XMPP_STATE_CONNECTED &&
conn->stream_negotiation_completed == 0);
}
static int _is_connected(xmpp_conn_t *conn, xmpp_send_queue_owner_t owner)
{
return conn->state == XMPP_STATE_CONNECTED &&
(owner != XMPP_QUEUE_USER ||
conn->stream_negotiation_completed == 1);
} }
/** /**
* @return TRUE if connection is in connected state and FALSE otherwise * @return TRUE if connection is established and FALSE otherwise
* *
* @ingroup Connections * @ingroup Connections
*/ */
int xmpp_conn_is_connected(xmpp_conn_t *conn) int xmpp_conn_is_connected(xmpp_conn_t *conn)
{ {
return conn->state == XMPP_STATE_CONNECTED; return _is_connected(conn, XMPP_QUEUE_USER);
} }
/** /**
@@ -1313,7 +1324,7 @@ static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
s->id = NULL; s->id = NULL;
} }
s->sm_enabled = s->sm_support = s->resume = 0; s->r_sent = s->sm_enabled = s->sm_support = s->resume = 0;
if (s->bind) { if (s->bind) {
xmpp_stanza_release(s->bind); xmpp_stanza_release(s->bind);
@@ -1333,8 +1344,11 @@ static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state) int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state)
{ {
/* We can only set the SM state when we're disconnected */ /* We can only set the SM state when we're disconnected */
if (conn->state != XMPP_STATE_DISCONNECTED) if (conn->state != XMPP_STATE_DISCONNECTED) {
strophe_error(conn->ctx, "conn",
"SM state can only be set the when we're disconnected");
return XMPP_EINVOP; return XMPP_EINVOP;
}
if (conn->sm_state) { if (conn->sm_state) {
strophe_error(conn->ctx, "conn", "SM state is already set!"); strophe_error(conn->ctx, "conn", "SM state is already set!");
@@ -1353,6 +1367,21 @@ int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state)
return XMPP_EOK; return XMPP_EOK;
} }
void reset_sm_state(xmpp_sm_state_t *sm_state)
{
xmpp_ctx_t *ctx = sm_state->ctx;
strophe_free_and_null(ctx, sm_state->id);
strophe_free_and_null(ctx, sm_state->previd);
strophe_free_and_null(ctx, sm_state->bound_jid);
if (sm_state->bind)
xmpp_stanza_release(sm_state->bind);
sm_state->bind = NULL;
sm_state->sm_handled_nr = 0;
sm_state->sm_sent_nr = 0;
sm_state->r_sent = 0;
}
/** c.f. \ref xmpp_conn_get_sm_state for usage documentation /** c.f. \ref xmpp_conn_get_sm_state for usage documentation
* *
* @param sm_state A Stream Management state returned from a call to * @param sm_state A Stream Management state returned from a call to
@@ -1362,8 +1391,8 @@ int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state)
*/ */
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state) void xmpp_free_sm_state(xmpp_sm_state_t *sm_state)
{ {
xmpp_ctx_t *ctx;
xmpp_send_queue_t *smq; xmpp_send_queue_t *smq;
xmpp_ctx_t *ctx;
if (!sm_state || !sm_state->ctx) if (!sm_state || !sm_state->ctx)
return; return;
@@ -1374,15 +1403,7 @@ void xmpp_free_sm_state(xmpp_sm_state_t *sm_state)
strophe_free(ctx, queue_element_free(ctx, smq)); strophe_free(ctx, queue_element_free(ctx, smq));
} }
if (sm_state->bind) reset_sm_state(sm_state);
xmpp_stanza_release(sm_state->bind);
if (sm_state->id)
strophe_free(ctx, sm_state->id);
if (sm_state->previd)
strophe_free(ctx, sm_state->previd);
if (sm_state->bound_jid)
strophe_free(ctx, sm_state->bound_jid);
memset(sm_state, 0, sizeof(*sm_state));
strophe_free(ctx, sm_state); strophe_free(ctx, sm_state);
} }
@@ -1436,6 +1457,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
xmpp_queue_element_t which) xmpp_queue_element_t which)
{ {
xmpp_send_queue_t *t; xmpp_send_queue_t *t;
int disconnected = conn->state == XMPP_STATE_DISCONNECTED;
/* Fast return paths */ /* Fast return paths */
/* empty queue */ /* empty queue */
@@ -1444,7 +1466,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
/* one element in queue */ /* one element in queue */
if (conn->send_queue_head == conn->send_queue_tail) { if (conn->send_queue_head == conn->send_queue_tail) {
/* head is already sent out partially */ /* head is already sent out partially */
if (conn->send_queue_head->wip) if (conn->send_queue_head->wip && !disconnected)
return NULL; return NULL;
/* the element is no USER element */ /* the element is no USER element */
if (conn->send_queue_head->owner != XMPP_QUEUE_USER) if (conn->send_queue_head->owner != XMPP_QUEUE_USER)
@@ -1468,7 +1490,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
return NULL; return NULL;
/* head is already sent out partially */ /* head is already sent out partially */
if (t == conn->send_queue_head && t->wip) if (t == conn->send_queue_head && t->wip && !disconnected)
t = t->next; t = t->next;
/* search forward to find the first USER element */ /* search forward to find the first USER element */
@@ -1482,8 +1504,11 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
/* In case there exists a SM stanza that is linked to the /* In case there exists a SM stanza that is linked to the
* one we're currently dropping, also delete that one. * one we're currently dropping, also delete that one.
*/ */
if (t->next && t->next->userdata == t) if (t->next && t->next->userdata == t) {
strophe_free(conn->ctx, _drop_send_queue_element(conn, t->next)); strophe_free(conn->ctx, _drop_send_queue_element(conn, t->next));
/* reset the flag, so we restart to send `<r>` stanzas */
conn->sm_state->r_sent = 0;
}
/* Finally drop the element */ /* Finally drop the element */
return _drop_send_queue_element(conn, t); return _drop_send_queue_element(conn, t);
} }
@@ -1746,10 +1771,12 @@ static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
while (conn->sm_state->sm_queue.head && while (conn->sm_state->sm_queue.head &&
conn->sm_state->sm_queue.head->sm_h < ul_h) { conn->sm_state->sm_queue.head->sm_h < ul_h) {
e = pop_queue_front(&conn->sm_state->sm_queue); e = pop_queue_front(&conn->sm_state->sm_queue);
strophe_debug_verbose(2, conn->ctx, "conn", "SM_Q_DROP: %p", e); strophe_debug_verbose(2, conn->ctx, "conn",
"SM_Q_DROP: %p, h=%lu", e, e->sm_h);
c = queue_element_free(conn->ctx, e); c = queue_element_free(conn->ctx, e);
strophe_free(conn->ctx, c); strophe_free(conn->ctx, c);
} }
conn->sm_state->r_sent = 0;
} }
} }
} }
@@ -1788,6 +1815,11 @@ static void _conn_reset(xmpp_conn_t *conn)
return; return;
} }
compression_free(conn);
conn->intf = sock_intf;
conn->intf.conn = conn;
/* free queued */ /* free queued */
sq = conn->send_queue_head; sq = conn->send_queue_head;
while (sq) { while (sq) {
@@ -1802,22 +1834,14 @@ static void _conn_reset(xmpp_conn_t *conn)
if (conn->stream_error) { if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza); xmpp_stanza_release(conn->stream_error->stanza);
if (conn->stream_error->text) strophe_free_and_null(ctx, conn->stream_error->text);
strophe_free(ctx, conn->stream_error->text); strophe_free_and_null(ctx, conn->stream_error);
strophe_free(ctx, conn->stream_error);
conn->stream_error = NULL;
} }
if (conn->domain) strophe_free_and_null(ctx, conn->domain);
strophe_free(ctx, conn->domain); strophe_free_and_null(ctx, conn->bound_jid);
if (conn->bound_jid) strophe_free_and_null(ctx, conn->stream_id);
strophe_free(ctx, conn->bound_jid); conn->stream_negotiation_completed = 0;
if (conn->stream_id)
strophe_free(ctx, conn->stream_id);
conn->domain = NULL;
conn->bound_jid = NULL;
conn->stream_id = NULL;
conn->authenticated = 0;
conn->secured = 0; conn->secured = 0;
conn->tls_failed = 0; conn->tls_failed = 0;
conn->error = 0; conn->error = 0;
@@ -1904,7 +1928,7 @@ static void _send_valist(xmpp_conn_t *conn,
char buf[1024]; /* small buffer for common case */ char buf[1024]; /* small buffer for common case */
char *bigbuf; char *bigbuf;
if (conn->state != XMPP_STATE_CONNECTED) if (!_is_connected(conn, owner))
return; return;
va_copy(apdup, ap); va_copy(apdup, ap);
@@ -1952,7 +1976,7 @@ void send_stanza(xmpp_conn_t *conn,
char *buf = NULL; char *buf = NULL;
size_t len; size_t len;
if (conn->state != XMPP_STATE_CONNECTED) if (!_is_connected(conn, owner))
goto out; goto out;
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) { if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
@@ -1979,6 +2003,11 @@ void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item)
} }
} }
xmpp_send_queue_t *peek_queue_front(xmpp_queue_t *queue)
{
return queue->head;
}
xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue) xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue)
{ {
xmpp_send_queue_t *ret = queue->head; xmpp_send_queue_t *ret = queue->head;
@@ -2034,8 +2063,10 @@ static int _send_raw(xmpp_conn_t *conn,
conn->send_queue_user_len++; conn->send_queue_user_len++;
strophe_debug_verbose(3, conn->ctx, "conn", "QUEUED: %s", data); strophe_debug_verbose(3, conn->ctx, "conn", "QUEUED: %s", data);
strophe_debug_verbose(1, conn->ctx, "conn", "Q_ADD: %p", item); strophe_debug_verbose(1, conn->ctx, "conn", "Q_ADD: %p", item);
if (!(owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled) { if (!(owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled &&
!conn->sm_state->r_sent) {
send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item); send_raw(conn, req_ack, strlen(req_ack), XMPP_QUEUE_SM_STROPHE, item);
conn->sm_state->r_sent = 1;
} }
return XMPP_EOK; return XMPP_EOK;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* crypto.c /* crypto.c
* strophe XMPP client library -- public interface for digests, encodings * strophe XMPP client library -- public interface for digests, encodings
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* ctx.c /* ctx.c
** strophe XMPP client library -- run-time context implementation ** strophe XMPP client library -- run-time context implementation
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -464,6 +465,8 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata); ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
if (ctx != NULL) { if (ctx != NULL) {
memset(ctx, 0, sizeof(xmpp_ctx_t));
if (mem != NULL) if (mem != NULL)
ctx->mem = mem; ctx->mem = mem;
else else
@@ -474,12 +477,9 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
else else
ctx->log = log; ctx->log = log;
ctx->connlist = NULL;
ctx->timed_handlers = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED; ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx); ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT; ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
ctx->verbosity = 0;
if (ctx->rand == NULL) { if (ctx->rand == NULL) {
strophe_free(ctx, ctx); strophe_free(ctx, ctx);
ctx = NULL; ctx = NULL;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* deprecated.c /* deprecated.c
** strophe XMPP client library -- File with deprecated API functions. ** strophe XMPP client library -- File with deprecated API functions.
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -18,6 +19,7 @@
*/ */
#include "common.h" #include "common.h"
#include <limits.h>
/** Allocate memory in a Strophe context. /** Allocate memory in a Strophe context.
* All Strophe functions will use this to allocate memory. * All Strophe functions will use this to allocate memory.
@@ -85,6 +87,10 @@ char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
return strophe_strndup(ctx, s, len); return strophe_strndup(ctx, s, len);
} }
/** Write to the log.
*
* @ingroup Deprecated
*/
void xmpp_log(const xmpp_ctx_t *ctx, void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level, xmpp_log_level_t level,
const char *area, const char *area,
@@ -216,6 +222,10 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
return strophe_strtok_r(s, delim, saveptr); return strophe_strtok_r(s, delim, saveptr);
} }
/** snprintf(3) implementation.
*
* @ingroup Deprecated
*/
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...) int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{ {
va_list ap; va_list ap;
@@ -227,11 +237,184 @@ int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
return ret; return ret;
} }
/** vsnprintf(3) implementation.
*
* @ingroup Deprecated
*/
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg) int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg)
{ {
return strophe_vsnprintf(str, count, fmt, arg); return strophe_vsnprintf(str, count, fmt, arg);
} }
/** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL
* ANONYMOUS authentication will be used.
*
* @param conn a Strophe connection object
* @param jid a full or bare JID
*
* @ingroup Deprecated
*/
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
}
/** Set the password used to authenticate the connection.
* If any password was previously set, it will be discarded. The function
* will make a copy of the password string.
*
* @param conn a Strophe connection object
* @param pass the password
*
* @ingroup Deprecated
*/
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param path path to a certificate file
*
* @ingroup Deprecated
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param path path to a folder containing certificates
*
* @ingroup Deprecated
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, path);
}
/** Set the Client Certificate and Private Key or PKCS#12 encoded file that
* will be bound to the connection. If any of them was previously set, it
* will be discarded. This should not be used after a connection is created.
* The function will make a copy of the strings passed in.
*
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup Deprecated
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (!cert && key) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, key);
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
} else {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
}
}
/** Set the number of retry attempts to decrypt a private key file.
*
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* @param conn a Strophe connection object
* @param retries The number of retries that should be tried
*
* @ingroup Deprecated
*/
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries)
{
int val;
if (retries > INT_MAX) {
val = INT_MAX;
strophe_warn(conn->ctx, "xmpp", "retries capped from %u to %d", retries,
val);
} else {
val = (int)retries;
}
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, val);
}
/** Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* @param conn a Strophe connection object
* @param cb The callback function that shall be called
* @param userdata An opaque data pointer that will be passed to the callback
*
* @ingroup Deprecated
*/
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK, cb);
xmpp_conn_set_pointer(conn, XMPP_SETTING_PASSWORD_CALLBACK_USERDATA,
userdata);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup Deprecated
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER, hndl);
}
/** Register sockopt callback
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started.
*
* If the connection is already connected, this callback will be called
* immediately.
*
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn The Strophe connection object this callback is being registered
* for
* @param callback a xmpp_sockopt_callback callback function that will receive
* notifications of connection status
*
* @ingroup Deprecated
*/
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
callback);
}
/** Set TCP keepalive parameters /** Set TCP keepalive parameters
* Turn on TCP keepalive and set timeout and interval. Zero timeout * Turn on TCP keepalive and set timeout and interval. Zero timeout
* disables TCP keepalives. The parameters are applied immediately for * disables TCP keepalives. The parameters are applied immediately for
@@ -252,5 +435,25 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
conn->ka_timeout = timeout; conn->ka_timeout = timeout;
conn->ka_interval = interval; conn->ka_interval = interval;
conn->ka_count = 0; conn->ka_count = 0;
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
xmpp_sockopt_cb_keepalive);
}
/** Disable TLS for this connection, called by users of the library.
* Occasionally a server will be misconfigured to send the starttls
* feature, but will not support the handshake.
*
* @param conn a Strophe connection object
*
* @note this function is deprecated
* @see xmpp_conn_set_flags()
*
* @ingroup Deprecated
*/
void xmpp_conn_disable_tls(xmpp_conn_t *conn)
{
long flags = xmpp_conn_get_flags(conn);
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
(void)xmpp_conn_set_flags(conn, flags);
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* event.c /* event.c
** strophe XMPP client library -- event loop and management ** strophe XMPP client library -- event loop and management
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -57,8 +58,10 @@
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
#ifndef STROPHE_MESSAGE_BUFFER_SIZE
/** Max buffer size for receiving messages. */ /** Max buffer size for receiving messages. */
#define STROPE_MESSAGE_BUFFER_SIZE 4096 #define STROPHE_MESSAGE_BUFFER_SIZE 4096
#endif
static int _connect_next(xmpp_conn_t *conn) static int _connect_next(xmpp_conn_t *conn)
{ {
@@ -89,13 +92,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
{ {
xmpp_connlist_t *connitem; xmpp_connlist_t *connitem;
xmpp_conn_t *conn; xmpp_conn_t *conn;
struct conn_interface *intf;
fd_set rfds, wfds; fd_set rfds, wfds;
sock_t max = 0; sock_t max = 0;
int ret; int ret;
struct timeval tv; struct timeval tv;
xmpp_send_queue_t *sq, *tsq; xmpp_send_queue_t *sq, *tsq;
int towrite; int towrite;
char buf[STROPE_MESSAGE_BUFFER_SIZE]; char buf[STROPHE_MESSAGE_BUFFER_SIZE];
uint64_t next; uint64_t next;
uint64_t usec; uint64_t usec;
int tls_read_bytes = 0; int tls_read_bytes = 0;
@@ -111,16 +115,18 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
connitem = connitem->next; connitem = connitem->next;
continue; continue;
} }
intf = &conn->intf;
/* if we're running tls, there may be some remaining data waiting to /* if we're running tls, there may be some remaining data waiting to
* be sent, so push that out */ * be sent, so push that out */
if (conn->tls) { if (conn->tls) {
ret = tls_clear_pending_write(conn->tls); ret = tls_clear_pending_write(intf);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { if (ret < 0 && !tls_is_recoverable(intf, tls_error(intf))) {
/* an error occurred */ /* an error occurred */
strophe_debug(ctx, "xmpp", strophe_debug(
"Send error occurred, disconnecting."); ctx, "xmpp",
"Send error of pending data occurred, disconnecting.");
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
goto next_item; goto next_item;
@@ -132,15 +138,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
while (sq) { while (sq) {
towrite = sq->len - sq->written; towrite = sq->len - sq->written;
if (conn->tls) { ret = conn_interface_write(intf, &sq->data[sq->written], towrite);
ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
conn->error = tls_error(conn->tls);
} else {
ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
if (ret < 0 && !sock_is_recoverable(sock_error()))
conn->error = sock_error();
}
if (ret > 0 && ret < towrite) if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */ sq->written += ret; /* not all data could be sent now */
sq->wip = 1; sq->wip = 1;
@@ -158,7 +156,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (!(tsq->owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled) { if (!(tsq->owner & XMPP_QUEUE_SM) && conn->sm_state->sm_enabled) {
tsq->sm_h = conn->sm_state->sm_sent_nr; tsq->sm_h = conn->sm_state->sm_sent_nr;
conn->sm_state->sm_sent_nr++; conn->sm_state->sm_sent_nr++;
strophe_debug_verbose(1, ctx, "xmpp", "SM_Q_MOVE: %p", tsq); strophe_debug_verbose(1, ctx, "xmpp", "SM_Q_MOVE: %p, h=%lu",
tsq, tsq->sm_h);
add_queue_back(&conn->sm_state->sm_queue, tsq); add_queue_back(&conn->sm_state->sm_queue, tsq);
tsq = NULL; tsq = NULL;
} }
@@ -176,6 +175,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (!sq) if (!sq)
conn->send_queue_tail = NULL; conn->send_queue_tail = NULL;
} }
intf->flush(intf);
/* tear down connection on error */ /* tear down connection on error */
if (conn->error) { if (conn->error) {
@@ -210,6 +210,7 @@ next_item:
connitem = ctx->connlist; connitem = ctx->connlist;
while (connitem) { while (connitem) {
conn = connitem->conn; conn = connitem->conn;
intf = &conn->intf;
switch (conn->state) { switch (conn->state) {
case XMPP_STATE_CONNECTING: case XMPP_STATE_CONNECTING:
@@ -244,7 +245,7 @@ next_item:
/* Check if there is something in the SSL buffer. */ /* Check if there is something in the SSL buffer. */
if (conn->tls) if (conn->tls)
tls_read_bytes += tls_pending(conn->tls); tls_read_bytes += tls_pending(intf);
if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max) if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max)
max = conn->sock; max = conn->sock;
@@ -263,9 +264,9 @@ next_item:
/* select errored */ /* select errored */
if (ret < 0) { if (ret < 0) {
if (!sock_is_recoverable(sock_error())) if (!sock_is_recoverable(NULL, sock_error(NULL)))
strophe_error(ctx, "xmpp", "event watcher internal error %d", strophe_error(ctx, "xmpp", "event watcher internal error %d",
sock_error()); sock_error(NULL));
return; return;
} }
@@ -277,6 +278,7 @@ next_item:
connitem = ctx->connlist; connitem = ctx->connlist;
while (connitem) { while (connitem) {
conn = connitem->conn; conn = connitem->conn;
intf = &conn->intf;
switch (conn->state) { switch (conn->state) {
case XMPP_STATE_CONNECTING: case XMPP_STATE_CONNECTING:
@@ -304,14 +306,9 @@ next_item:
break; break;
case XMPP_STATE_CONNECTED: case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) || if (FD_ISSET(conn->sock, &rfds) || intf->pending(intf)) {
(conn->tls && tls_pending(conn->tls))) {
if (conn->tls) { ret = intf->read(intf, buf, STROPHE_MESSAGE_BUFFER_SIZE);
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE);
} else {
ret =
sock_read(conn->sock, buf, STROPE_MESSAGE_BUFFER_SIZE);
}
if (ret > 0) { if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret); ret = parser_feed(conn->parser, buf, ret);
@@ -321,15 +318,13 @@ next_item:
"parse error"); "parse error");
} }
} else { } else {
if (conn->tls) { int err = intf->get_error(intf);
if (!tls_is_recoverable(tls_error(conn->tls))) { if (!intf->error_is_recoverable(intf, err)) {
strophe_debug(ctx, "xmpp", strophe_debug(ctx, "xmpp", "Unrecoverable error: %d.",
"Unrecoverable TLS error, %d.", err);
tls_error(conn->tls)); conn->error = err;
conn->error = tls_error(conn->tls); conn_disconnect(conn);
conn_disconnect(conn); } else if (!conn->tls) {
}
} else {
/* return of 0 means socket closed by server */ /* return of 0 means socket closed by server */
strophe_debug(ctx, "xmpp", strophe_debug(ctx, "xmpp",
"Socket closed by remote host."); "Socket closed by remote host.");

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* handler.c /* handler.c
** strophe XMPP client library -- event handler management ** strophe XMPP client library -- event handler management
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -80,9 +81,9 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
item = head; item = head;
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and /* don't fire user handlers until stream negotiation has completed
and skip newly added handlers */ and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || if ((item->user_handler && !conn->stream_negotiation_completed) ||
!item->enabled) { !item->enabled) {
item = item->next; item = item->next;
continue; continue;
@@ -116,9 +117,10 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
item = conn->handlers; item = conn->handlers;
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and /* don't fire user handlers until stream negotiation has completed and
skip newly added handlers */ skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) { if ((item->user_handler && !conn->stream_negotiation_completed) ||
!item->enabled) {
item = item->next; item = item->next;
continue; continue;
} }
@@ -174,9 +176,9 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
item = conn->timed_handlers; item = conn->timed_handlers;
while (item) { while (item) {
/* don't fire user handlers until authentication succeeds and /* don't fire user handlers until stream negotiation has completed
skip newly added handlers */ and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || if ((item->user_handler && !conn->stream_negotiation_completed) ||
!item->enabled) { !item->enabled) {
item = item->next; item = item->next;
continue; continue;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* hash.c /* hash.c
** strophe XMPP client library -- hash table implementation ** strophe XMPP client library -- hash table implementation
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* hash.h /* hash.h
** strophe XMPP client library -- hash table interface ** strophe XMPP client library -- hash table interface
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* jid.c /* jid.c
** strophe XMPP client library -- helper functions for parsing JIDs ** strophe XMPP client library -- helper functions for parsing JIDs
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* ostypes.h /* ostypes.h
** strophe XMPP client library -- type definitions for platforms ** strophe XMPP client library -- type definitions for platforms
** without stdint.h ** without stdint.h
@@ -7,7 +8,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* parser.h /* parser.h
** strophe XMPP client library -- parser structures and functions ** strophe XMPP client library -- parser structures and functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* parser.c /* parser.c
** strophe XMPP client library -- xml parser handlers and utility functions ** strophe XMPP client library -- xml parser handlers and utility functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* parser.c /* parser.c
** strophe XMPP client library -- xml parser handlers and utility functions ** strophe XMPP client library -- xml parser handlers and utility functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* rand.c /* rand.c
* strophe XMPP client library -- pseudo-random number generator * strophe XMPP client library -- pseudo-random number generator
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* resolver.c /* resolver.c
* strophe XMPP client library -- DNS resolver * strophe XMPP client library -- DNS resolver
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* resolver.h /* resolver.h
* strophe XMPP client library -- DNS resolver * strophe XMPP client library -- DNS resolver
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* sasl.c /* sasl.c
** strophe XMPP client library -- SASL authentication helpers ** strophe XMPP client library -- SASL authentication helpers
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -374,6 +375,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
/** generate auth response string for the SASL SCRAM mechanism */ /** generate auth response string for the SASL SCRAM mechanism */
char *sasl_scram(xmpp_ctx_t *ctx, char *sasl_scram(xmpp_ctx_t *ctx,
const struct hash_alg *alg, const struct hash_alg *alg,
const char *channel_binding,
const char *challenge, const char *challenge,
const char *first_bare, const char *first_bare,
const char *jid, const char *jid,
@@ -397,6 +399,7 @@ char *sasl_scram(xmpp_ctx_t *ctx,
char *result = NULL; char *result = NULL;
size_t response_len; size_t response_len;
size_t auth_len; size_t auth_len;
int l;
UNUSED(jid); UNUSED(jid);
@@ -427,37 +430,44 @@ char *sasl_scram(xmpp_ctx_t *ctx,
} }
ival = strtol(i, &saveptr, 10); ival = strtol(i, &saveptr, 10);
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge); /* "c=<channel_binding>," + r + ",p=" + sign_b64 + '\0' */
auth = strophe_alloc(ctx, auth_len); response_len = 3 + strlen(channel_binding) + strlen(r) + 3 +
if (!auth) { ((alg->digest_size + 2) / 3 * 4) + 1;
response = strophe_alloc(ctx, response_len);
if (!response) {
goto out_sval; goto out_sval;
} }
/* "c=biws," + r + ",p=" + sign_b64 + '\0' */ auth_len = 3 + response_len + strlen(first_bare) + strlen(challenge);
response_len = 7 + strlen(r) + 3 + ((alg->digest_size + 2) / 3 * 4) + 1; auth = strophe_alloc(ctx, auth_len);
response = strophe_alloc(ctx, response_len); if (!auth) {
if (!response) { goto out_response;
goto out_auth;
} }
strophe_snprintf(response, response_len, "c=biws,%s", r); l = strophe_snprintf(response, response_len, "c=%s,%s", channel_binding, r);
strophe_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge, if (l < 0 || (size_t)l >= response_len) {
response); goto out_auth;
}
l = strophe_snprintf(auth, auth_len, "%s,%s,%s", first_bare, challenge,
response);
if (l < 0 || (size_t)l >= auth_len) {
goto out_auth;
}
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval, SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval,
sval_len, (uint32_t)ival, key); sval_len, (uint32_t)ival, key);
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign); SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
SCRAM_ClientProof(alg, sign, key, sign); SCRAM_ClientProof(alg, key, sign, sign);
sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size); sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size);
if (!sign_b64) { if (!sign_b64) {
goto out_response; goto out_auth;
} }
/* Check for buffer overflow */ /* Check for buffer overflow */
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) { if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
strophe_free(ctx, sign_b64); strophe_free(ctx, sign_b64);
goto out_response; goto out_auth;
} }
strcat(response, ",p="); strcat(response, ",p=");
strcat(response, sign_b64); strcat(response, sign_b64);
@@ -466,14 +476,14 @@ char *sasl_scram(xmpp_ctx_t *ctx,
response_b64 = response_b64 =
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response)); xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response));
if (!response_b64) { if (!response_b64) {
goto out_response; goto out_auth;
} }
result = response_b64; result = response_b64;
out_response:
strophe_free(ctx, response);
out_auth: out_auth:
strophe_free(ctx, auth); strophe_free(ctx, auth);
out_response:
strophe_free(ctx, response);
out_sval: out_sval:
strophe_free(ctx, sval); strophe_free(ctx, sval);
out: out:

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* sasl.h /* sasl.h
** strophe XMPP client library -- SASL authentication helpers ** strophe XMPP client library -- SASL authentication helpers
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -28,6 +29,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
const char *password); const char *password);
char *sasl_scram(xmpp_ctx_t *ctx, char *sasl_scram(xmpp_ctx_t *ctx,
const struct hash_alg *alg, const struct hash_alg *alg,
const char *channel_binding,
const char *challenge, const char *challenge,
const char *first_bare, const char *first_bare,
const char *jid, const char *jid,

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* scram.c /* scram.c
* strophe XMPP client library * strophe XMPP client library
* *
@@ -9,7 +10,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -41,6 +42,15 @@ const struct hash_alg scram_sha1 = {
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update, (void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
(void (*)(void *, uint8_t *))crypto_SHA1_Final}; (void (*)(void *, uint8_t *))crypto_SHA1_Final};
const struct hash_alg scram_sha1_plus = {
"SCRAM-SHA-1-PLUS",
SASL_MASK_SCRAMSHA1_PLUS,
SHA1_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
(void (*)(void *))crypto_SHA1_Init,
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
const struct hash_alg scram_sha256 = { const struct hash_alg scram_sha256 = {
"SCRAM-SHA-256", "SCRAM-SHA-256",
SASL_MASK_SCRAMSHA256, SASL_MASK_SCRAMSHA256,
@@ -50,6 +60,15 @@ const struct hash_alg scram_sha256 = {
(void (*)(void *, const uint8_t *, size_t))sha256_process, (void (*)(void *, const uint8_t *, size_t))sha256_process,
(void (*)(void *, uint8_t *))sha256_done}; (void (*)(void *, uint8_t *))sha256_done};
const struct hash_alg scram_sha256_plus = {
"SCRAM-SHA-256-PLUS",
SASL_MASK_SCRAMSHA256_PLUS,
SHA256_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
(void (*)(void *))sha256_init,
(void (*)(void *, const uint8_t *, size_t))sha256_process,
(void (*)(void *, uint8_t *))sha256_done};
const struct hash_alg scram_sha512 = { const struct hash_alg scram_sha512 = {
"SCRAM-SHA-512", "SCRAM-SHA-512",
SASL_MASK_SCRAMSHA512, SASL_MASK_SCRAMSHA512,
@@ -59,6 +78,43 @@ const struct hash_alg scram_sha512 = {
(void (*)(void *, const uint8_t *, size_t))sha512_process, (void (*)(void *, const uint8_t *, size_t))sha512_process,
(void (*)(void *, uint8_t *))sha512_done}; (void (*)(void *, uint8_t *))sha512_done};
const struct hash_alg scram_sha512_plus = {
"SCRAM-SHA-512-PLUS",
SASL_MASK_SCRAMSHA512_PLUS,
SHA512_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
(void (*)(void *))sha512_init,
(void (*)(void *, const uint8_t *, size_t))sha512_process,
(void (*)(void *, uint8_t *))sha512_done};
/* The order of this list defines the order in which the SCRAM algorithms are
* tried if the server supports them.
* Their order is derived from
* https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
*/
const struct hash_alg *scram_algs[] = {
/* *1 */
&scram_sha512_plus,
/* *1 */
&scram_sha256_plus,
/* *1 */
&scram_sha1_plus,
/* *1 */
&scram_sha512,
/* *1 */
&scram_sha256,
/* *1 */
&scram_sha1,
};
/* *1 - I want to use clang-format here, but by default it will put multiple
* elements per line if there's no comment. Currently clang-format also doesn't
* have an option to enforce it to behave like that, besides by putting comments
* between each element (or I couldn't find a way to do it). In order to prevent
* clang-format from re-formatting the array I added the comments above and
* wrote this lengthy description.
*/
const size_t scram_algs_num = sizeof(scram_algs) / sizeof(scram_algs[0]);
union common_hash_ctx { union common_hash_ctx {
SHA1_CTX sha1; SHA1_CTX sha1;
sha256_context sha256; sha256_context sha256;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* scram.h /* scram.h
* strophe XMPP client library -- SCRAM helper functions * strophe XMPP client library -- SCRAM helper functions
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -33,9 +34,8 @@ struct hash_alg {
void (*final)(void *, uint8_t *); void (*final)(void *, uint8_t *);
}; };
extern const struct hash_alg scram_sha1; extern const struct hash_alg *scram_algs[];
extern const struct hash_alg scram_sha256; extern const size_t scram_algs_num;
extern const struct hash_alg scram_sha512;
void SCRAM_ClientKey(const struct hash_alg *alg, void SCRAM_ClientKey(const struct hash_alg *alg,
const uint8_t *password, const uint8_t *password,

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* sock.c /* sock.c
** strophe XMPP client library -- socket abstraction implementation ** strophe XMPP client library -- socket abstraction implementation
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -37,6 +38,18 @@
#include "common.h" #include "common.h"
#include "resolver.h" #include "resolver.h"
const struct conn_interface sock_intf = {
sock_read,
sock_write,
/* no flush */
conn_int_nop,
/* no pending */
conn_int_nop,
sock_error,
sock_is_recoverable,
NULL,
};
struct _xmpp_sock_t { struct _xmpp_sock_t {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn; xmpp_conn_t *conn;
@@ -63,8 +76,9 @@ void sock_shutdown(void)
#endif #endif
} }
int sock_error(void) int sock_error(struct conn_interface *intf)
{ {
UNUSED(intf);
#ifdef _WIN32 #ifdef _WIN32
return WSAGetLastError(); return WSAGetLastError();
#else #else
@@ -109,7 +123,8 @@ static void sock_getaddrinfo(xmpp_sock_t *xsock)
rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints, rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints,
&xsock->ainfo_list); &xsock->ainfo_list);
if (rc != 0) { if (rc != 0) {
strophe_debug(xsock->ctx, "sock", "getaddrinfo() failed with %d", strophe_debug(xsock->ctx, "sock",
"getaddrinfo() failed with %s (%d)", gai_strerror(rc),
rc); rc);
xsock->ainfo_list = NULL; xsock->ainfo_list = NULL;
} }
@@ -193,7 +208,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
{ {
struct addrinfo *ainfo; struct addrinfo *ainfo;
sock_t sock; sock_t sock;
int rc = 0; int rc;
char buf[64]; char buf[64];
do { do {
@@ -214,6 +229,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock != INVALID_SOCKET) { if (sock != INVALID_SOCKET) {
rc = 0;
if (xsock->conn->sockopt_cb) { if (xsock->conn->sockopt_cb) {
/* Don't allow user to overwrite sockfd value. */ /* Don't allow user to overwrite sockfd value. */
sock_t sock_copy = sock; sock_t sock_copy = sock;
@@ -221,7 +237,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
if (rc != 0) { if (rc != 0) {
strophe_debug(xsock->ctx, "sock", strophe_debug(xsock->ctx, "sock",
"User's setsockopt callback" "User's setsockopt callback"
"failed with %d (errno=%d)", " failed with %d (errno=%d)",
rc, errno); rc, errno);
} }
} }
@@ -230,7 +246,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
if (rc == 0) if (rc == 0)
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen); rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
/* Assume only connect() can cause "in progress" error. */ /* Assume only connect() can cause "in progress" error. */
if (rc != 0 && !_in_progress(sock_error())) { if (rc != 0 && !_in_progress(sock_error(NULL))) {
sock_close(sock); sock_close(sock);
sock = INVALID_SOCKET; sock = INVALID_SOCKET;
} }
@@ -375,18 +391,19 @@ int sock_set_nonblocking(sock_t sock)
return _sock_set_blocking_mode(sock, 0); return _sock_set_blocking_mode(sock, 0);
} }
int sock_read(sock_t sock, void *buff, size_t len) int sock_read(struct conn_interface *intf, void *buff, size_t len)
{ {
return recv(sock, buff, len, 0); return recv(intf->conn->sock, buff, len, 0);
} }
int sock_write(sock_t sock, const void *buff, size_t len) int sock_write(struct conn_interface *intf, const void *buff, size_t len)
{ {
return send(sock, buff, len, 0); return send(intf->conn->sock, buff, len, 0);
} }
int sock_is_recoverable(int error) int sock_is_recoverable(struct conn_interface *intf, int error)
{ {
UNUSED(intf);
#ifdef _WIN32 #ifdef _WIN32
return (error == WSAEINTR || error == WSAEWOULDBLOCK || return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
error == WSAEINPROGRESS); error == WSAEINPROGRESS);
@@ -415,15 +432,15 @@ int sock_connect_error(sock_t sock)
/* it's possible that the error wasn't ENOTCONN, so if it wasn't, /* it's possible that the error wasn't ENOTCONN, so if it wasn't,
* return that */ * return that */
#ifdef _WIN32 #ifdef _WIN32
if (sock_error() != WSAENOTCONN) if (sock_error(NULL) != WSAENOTCONN)
return sock_error(); return sock_error(NULL);
#else #else
if (sock_error() != ENOTCONN) if (sock_error(NULL) != ENOTCONN)
return sock_error(); return sock_error(NULL);
#endif #endif
/* load the correct error into errno through error slippage */ /* load the correct error into errno through error slippage */
recv(sock, &temp, 1, 0); recv(sock, &temp, 1, 0);
return sock_error(); return sock_error(NULL);
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* sock.h /* sock.h
** strophe XMPP client library -- socket abstraction header ** strophe XMPP client library -- socket abstraction header
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -29,12 +30,14 @@ typedef int sock_t;
typedef SOCKET sock_t; typedef SOCKET sock_t;
#endif #endif
extern const struct conn_interface sock_intf;
typedef struct _xmpp_sock_t xmpp_sock_t; typedef struct _xmpp_sock_t xmpp_sock_t;
void sock_initialize(void); void sock_initialize(void);
void sock_shutdown(void); void sock_shutdown(void);
int sock_error(void); int sock_error(struct conn_interface *intf);
xmpp_sock_t *sock_new(xmpp_conn_t *conn, xmpp_sock_t *sock_new(xmpp_conn_t *conn,
const char *domain, const char *domain,
@@ -46,9 +49,9 @@ int sock_close(sock_t sock);
int sock_set_blocking(sock_t sock); int sock_set_blocking(sock_t sock);
int sock_set_nonblocking(sock_t sock); int sock_set_nonblocking(sock_t sock);
int sock_read(sock_t sock, void *buff, size_t len); int sock_read(struct conn_interface *intf, void *buff, size_t len);
int sock_write(sock_t sock, const void *buff, size_t len); int sock_write(struct conn_interface *intf, const void *buff, size_t len);
int sock_is_recoverable(int error); int sock_is_recoverable(struct conn_interface *intf, int error);
/* checks for an error after connect, return 0 if connect successful */ /* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(sock_t sock); int sock_connect_error(sock_t sock);
int sock_set_keepalive(sock_t sock, int sock_set_keepalive(sock_t sock,

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* stanza.c /* stanza.c
** strophe XMPP client library -- XMPP stanza object and utilities ** strophe XMPP client library -- XMPP stanza object and utilities
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -41,15 +42,10 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t)); stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t));
if (stanza != NULL) { if (stanza != NULL) {
memset(stanza, 0, sizeof(xmpp_stanza_t));
stanza->ref = 1; stanza->ref = 1;
stanza->ctx = ctx; stanza->ctx = ctx;
stanza->type = XMPP_STANZA_UNKNOWN; stanza->type = XMPP_STANZA_UNKNOWN;
stanza->prev = NULL;
stanza->next = NULL;
stanza->children = NULL;
stanza->parent = NULL;
stanza->data = NULL;
stanza->attributes = NULL;
} }
return stanza; return stanza;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls.c /* tls.c
** strophe XMPP client library -- generic TLS functions ** strophe XMPP client library -- generic TLS functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -29,6 +30,17 @@
#include "common.h" #include "common.h"
const struct conn_interface tls_intf = {
tls_read,
tls_write,
tls_clear_pending_write,
tls_pending,
tls_error,
tls_is_recoverable,
/* init conn */
NULL,
};
struct _dnsname_t { struct _dnsname_t {
char **data; char **data;
size_t cur, max; size_t cur, max;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls.h /* tls.h
** strophe XMPP client library -- TLS abstraction header ** strophe XMPP client library -- TLS abstraction header
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -44,20 +45,24 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn); xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
int tls_set_credentials(tls_t *tls, const char *cafilename); int tls_set_credentials(tls_t *tls, const char *cafilename);
int tls_init_channel_binding(tls_t *tls,
const char **binding_prefix,
size_t *binding_prefix_len);
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size);
int tls_start(tls_t *tls); int tls_start(tls_t *tls);
int tls_stop(tls_t *tls); int tls_stop(tls_t *tls);
int tls_error(tls_t *tls); int tls_pending(struct conn_interface *intf);
int tls_read(struct conn_interface *intf, void *buff, size_t len);
int tls_write(struct conn_interface *intf, const void *buff, size_t len);
int tls_clear_pending_write(struct conn_interface *intf);
int tls_pending(tls_t *tls); int tls_error(struct conn_interface *intf);
int tls_read(tls_t *tls, void *buff, size_t len); int tls_is_recoverable(struct conn_interface *intf, int error);
int tls_write(tls_t *tls, const void *buff, size_t len);
int tls_clear_pending_write(tls_t *tls);
int tls_is_recoverable(int error);
/* provided by tls.c */ /* provided by tls.c */
extern const struct conn_interface tls_intf;
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx); xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname); int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls_dummy.c /* tls_dummy.c
** strophe XMPP client library -- TLS abstraction dummy impl. ** strophe XMPP client library -- TLS abstraction dummy impl.
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -74,6 +75,23 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
return -1; return -1;
} }
int tls_init_channel_binding(tls_t *tls,
const char **binding_prefix,
size_t *binding_prefix_len)
{
UNUSED(tls);
UNUSED(binding_prefix);
UNUSED(binding_prefix_len);
return -1;
}
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
{
UNUSED(tls);
UNUSED(size);
return NULL;
}
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
UNUSED(tls); UNUSED(tls);
@@ -86,43 +104,43 @@ int tls_stop(tls_t *tls)
return -1; return -1;
} }
int tls_error(tls_t *tls) int tls_error(struct conn_interface *intf)
{ {
UNUSED(tls); UNUSED(intf);
/* todo: some kind of error polling/dump */
return 0; return 0;
} }
int tls_pending(tls_t *tls) int tls_pending(struct conn_interface *intf)
{ {
UNUSED(tls); UNUSED(intf);
return 0; return 0;
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(struct conn_interface *intf, void *buff, size_t len)
{ {
UNUSED(tls); UNUSED(intf);
UNUSED(buff); UNUSED(buff);
UNUSED(len); UNUSED(len);
return -1; return -1;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{ {
UNUSED(tls); UNUSED(intf);
UNUSED(buff); UNUSED(buff);
UNUSED(len); UNUSED(len);
return -1; return -1;
} }
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(struct conn_interface *intf)
{ {
UNUSED(tls); UNUSED(intf);
return -1; return -1;
} }
int tls_is_recoverable(int error) int tls_is_recoverable(struct conn_interface *intf, int error)
{ {
UNUSED(intf);
UNUSED(error); UNUSED(error);
return 0; return 0;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls.c /* tls.c
** strophe XMPP client library -- TLS abstraction header ** strophe XMPP client library -- TLS abstraction header
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -24,12 +25,26 @@
#include "tls.h" #include "tls.h"
#include "sock.h" #include "sock.h"
#if GNUTLS_VERSION_NUMBER < 0x030702
/* This is a very dirty workaround to make this file compile on older GnuTLS
* We simply define our own value for the later introduced
* `GNUTLS_CB_TLS_EXPORTER` which makes it compile, but it will fail on runtime
* when the combination of the following options happen:
* * GnuTLS < 3.7.2
* * TLS 1.3
* * A SCRAM PLUS variant to authenticate
* We will think about fixing this once a user pops up who has that problem.
*/
#define GNUTLS_CB_TLS_EXPORTER 3
#endif
struct _tls { struct _tls {
xmpp_ctx_t *ctx; /* do we need this? */ xmpp_ctx_t *ctx; /* do we need this? */
xmpp_conn_t *conn; xmpp_conn_t *conn;
gnutls_session_t session; gnutls_session_t session;
gnutls_certificate_credentials_t cred; gnutls_certificate_credentials_t cred;
gnutls_x509_crt_t client_cert; gnutls_x509_crt_t client_cert;
gnutls_datum_t channel_binding;
int lasterror; int lasterror;
}; };
@@ -506,8 +521,8 @@ error_out:
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
if (tls->client_cert) gnutls_free(tls->channel_binding.data);
gnutls_x509_crt_deinit(tls->client_cert); gnutls_x509_crt_deinit(tls->client_cert);
gnutls_deinit(tls->session); gnutls_deinit(tls->session);
gnutls_certificate_free_credentials(tls->cred); gnutls_certificate_free_credentials(tls->cred);
strophe_free(tls->ctx, tls); strophe_free(tls->ctx, tls);
@@ -554,6 +569,55 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
return err == GNUTLS_E_SUCCESS; return err == GNUTLS_E_SUCCESS;
} }
int tls_init_channel_binding(tls_t *tls,
const char **binding_prefix,
size_t *binding_prefix_len)
{
gnutls_channel_binding_t binding_type;
gnutls_protocol_t tls_version = gnutls_protocol_get_version(tls->session);
switch (tls_version) {
case GNUTLS_SSL3:
case GNUTLS_TLS1_0:
case GNUTLS_TLS1_1:
case GNUTLS_TLS1_2:
*binding_prefix = "tls-unique";
*binding_prefix_len = strlen("tls-unique");
binding_type = GNUTLS_CB_TLS_UNIQUE;
break;
case GNUTLS_TLS1_3:
*binding_prefix = "tls-exporter";
*binding_prefix_len = strlen("tls-exporter");
binding_type = GNUTLS_CB_TLS_EXPORTER;
break;
default:
strophe_error(tls->ctx, "tls", "Unsupported TLS Version: %s",
gnutls_protocol_get_name(tls_version));
return -1;
}
if (tls->channel_binding.data) {
gnutls_free(tls->channel_binding.data);
tls->channel_binding.data = NULL;
}
int ret = gnutls_session_channel_binding(tls->session, binding_type,
&tls->channel_binding);
if (ret) {
strophe_error(tls->ctx, "tls", "could not get channel binding: %s",
gnutls_strerror(ret));
}
return ret;
}
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
{
if (!tls->channel_binding.data || !tls->channel_binding.size) {
strophe_error(tls->ctx, "tls", "No channel binding data available");
}
*size = tls->channel_binding.size;
return tls->channel_binding.data;
}
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
sock_set_blocking(tls->conn->sock); sock_set_blocking(tls->conn->sock);
@@ -569,24 +633,26 @@ int tls_stop(tls_t *tls)
return tls->lasterror == GNUTLS_E_SUCCESS; return tls->lasterror == GNUTLS_E_SUCCESS;
} }
int tls_error(tls_t *tls) int tls_error(struct conn_interface *intf)
{ {
return tls->lasterror; return intf->conn->tls->lasterror;
} }
int tls_is_recoverable(int error) int tls_is_recoverable(struct conn_interface *intf, int error)
{ {
UNUSED(intf);
return !gnutls_error_is_fatal(error); return !gnutls_error_is_fatal(error);
} }
int tls_pending(tls_t *tls) int tls_pending(struct conn_interface *intf)
{ {
return gnutls_record_check_pending(tls->session); return gnutls_record_check_pending(intf->conn->tls->session);
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(struct conn_interface *intf, void *buff, size_t len)
{ {
int ret; int ret;
tls_t *tls = intf->conn->tls;
ret = gnutls_record_recv(tls->session, buff, len); ret = gnutls_record_recv(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0; tls->lasterror = ret < 0 ? ret : 0;
@@ -594,9 +660,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return ret; return ret;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{ {
int ret; int ret;
tls_t *tls = intf->conn->tls;
ret = gnutls_record_send(tls->session, buff, len); ret = gnutls_record_send(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0; tls->lasterror = ret < 0 ? ret : 0;
@@ -604,8 +671,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
return ret; return ret;
} }
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(struct conn_interface *intf)
{ {
UNUSED(tls); UNUSED(intf);
return 0; return 0;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls_openssl.c /* tls_openssl.c
** strophe XMPP client library -- TLS abstraction openssl impl. ** strophe XMPP client library -- TLS abstraction openssl impl.
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -50,8 +51,10 @@
#if OPENSSL_VERSION_NUMBER < 0x30000000L #if OPENSSL_VERSION_NUMBER < 0x30000000L
#define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e) #define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e)
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get_peer_certificate(s)
#else #else
#define STROPHE_ERR_func_error_string(e) "" #define STROPHE_ERR_func_error_string(e) ""
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get1_peer_certificate(s)
#endif #endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -106,6 +109,9 @@ struct _tls {
SSL_CTX *ssl_ctx; SSL_CTX *ssl_ctx;
SSL *ssl; SSL *ssl;
X509 *client_cert; X509 *client_cert;
void *channel_binding_data;
size_t channel_binding_size;
FILE *keylogfile;
int lasterror; int lasterror;
}; };
@@ -280,9 +286,9 @@ void tls_shutdown(void)
#endif #endif
} }
int tls_error(tls_t *tls) int tls_error(struct conn_interface *intf)
{ {
return tls->lasterror; return intf->conn->tls->lasterror;
} }
/** Search through the SubjectAlternativeNames and return the next /** Search through the SubjectAlternativeNames and return the next
@@ -411,8 +417,10 @@ _get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm); alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
#else #else
const X509_ALGOR *palg; const X509_ALGOR *palg;
const ASN1_OBJECT *obj;
X509_get0_signature(NULL, &palg, err_cert); X509_get0_signature(NULL, &palg, err_cert);
alg_nid = OBJ_obj2nid(palg->algorithm); X509_ALGOR_get0(&obj, NULL, NULL, palg);
alg_nid = OBJ_obj2nid(obj);
#endif #endif
} break; } break;
default: default:
@@ -551,6 +559,36 @@ static int _tls_password_callback(char *buf, int size, int rwflag, void *u)
return tls_caching_password_callback(buf, size, u); return tls_caching_password_callback(buf, size, u);
} }
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
static void _keylog_cb(const SSL *ssl, const char *line)
{
xmpp_conn_t *conn = SSL_get_app_data(ssl);
fwrite(line, strlen(line), 1, conn->tls->keylogfile);
fputc('\n', conn->tls->keylogfile);
fflush(conn->tls->keylogfile);
}
#endif
static void _try_open_keylogfile(tls_t *tls)
{
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
const char *first_line = "# SSL Key logfile generated by libstrophe\n";
const char *SSLKEYLOGFILE = getenv("SSLKEYLOGFILE");
if (!SSLKEYLOGFILE || *SSLKEYLOGFILE == '\0')
return;
tls->keylogfile = fopen(SSLKEYLOGFILE, "abe");
if (!tls->keylogfile) {
strophe_warn(tls->ctx, "tls", "Could not open SSL keylog file %s",
SSLKEYLOGFILE);
return;
}
fwrite(first_line, strlen(first_line), 1, tls->keylogfile);
SSL_CTX_set_keylog_callback(tls->ssl_ctx, _keylog_cb);
#else
UNUSED(tls);
#endif
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls)); tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls));
@@ -694,6 +732,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
ret = SSL_set_fd(tls->ssl, conn->sock); ret = SSL_set_fd(tls->ssl, conn->sock);
if (ret <= 0) if (ret <= 0)
goto err_free_ssl; goto err_free_ssl;
_try_open_keylogfile(tls);
} }
return tls; return tls;
@@ -712,6 +752,9 @@ err:
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
if (tls->keylogfile)
fclose(tls->keylogfile);
strophe_free(tls->ctx, tls->channel_binding_data);
SSL_free(tls->ssl); SSL_free(tls->ssl);
X509_free(tls->client_cert); X509_free(tls->client_cert);
SSL_CTX_free(tls->ssl_ctx); SSL_CTX_free(tls->ssl_ctx);
@@ -721,7 +764,7 @@ void tls_free(tls_t *tls)
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn) xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{ {
if (conn && conn->tls && conn->tls->ssl) { if (conn && conn->tls && conn->tls->ssl) {
X509 *cert = SSL_get_peer_certificate(conn->tls->ssl); X509 *cert = STROPHE_SSL_get1_peer_certificate(conn->tls->ssl);
if (cert) { if (cert) {
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert); xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
X509_free(cert); X509_free(cert);
@@ -738,6 +781,83 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
return -1; return -1;
} }
int tls_init_channel_binding(tls_t *tls,
const char **binding_prefix,
size_t *binding_prefix_len)
{
const char *label = NULL;
size_t labellen = 0;
int ssl_version = SSL_version(tls->ssl);
switch (ssl_version) {
case SSL3_VERSION:
*binding_prefix = "tls-unique";
*binding_prefix_len = strlen("tls-unique");
tls->channel_binding_size = 36;
break;
case TLS1_VERSION:
case TLS1_1_VERSION:
case TLS1_2_VERSION:
*binding_prefix = "tls-unique";
*binding_prefix_len = strlen("tls-unique");
tls->channel_binding_size = 12;
break;
#ifdef TLS1_3_VERSION
case TLS1_3_VERSION:
label = "EXPORTER-Channel-Binding";
labellen = 24;
*binding_prefix = "tls-exporter";
*binding_prefix_len = strlen("tls-exporter");
tls->channel_binding_size = 32;
break;
#endif
default:
strophe_error(tls->ctx, "tls", "Unsupported TLS/SSL Version: %s",
SSL_get_version(tls->ssl));
return -1;
}
strophe_free_and_null(tls->ctx, tls->channel_binding_data);
tls->channel_binding_data =
strophe_alloc(tls->ctx, tls->channel_binding_size);
if (!tls->channel_binding_data)
return -1;
if (ssl_version <= TLS1_2_VERSION) {
size_t len;
if (SSL_session_reused(tls->ssl)) {
len = SSL_get_peer_finished(tls->ssl, tls->channel_binding_data,
tls->channel_binding_size);
} else {
len = SSL_get_finished(tls->ssl, tls->channel_binding_data,
tls->channel_binding_size);
}
if (len != tls->channel_binding_size) {
strophe_error(tls->ctx, "tls",
"Got channel binding data of wrong size %zu", len);
return -1;
}
} else {
if (SSL_export_keying_material(tls->ssl, tls->channel_binding_data,
tls->channel_binding_size, label,
labellen, NULL, 0, 0) != 1) {
strophe_error(tls->ctx, "tls",
"Could not get channel binding data");
return -1;
}
}
return 0;
}
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
{
if (!tls->channel_binding_data || !tls->channel_binding_size) {
strophe_error(tls->ctx, "tls", "No channel binding data available");
}
*size = tls->channel_binding_size;
return tls->channel_binding_data;
}
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
int error; int error;
@@ -750,7 +870,7 @@ int tls_start(tls_t *tls)
ret = SSL_connect(tls->ssl); ret = SSL_connect(tls->ssl);
error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0; error = ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0;
if (ret == -1 && tls_is_recoverable(error)) { if (ret == -1 && tls_is_recoverable(NULL, error)) {
/* wait for something to happen on the sock before looping back */ /* wait for something to happen on the sock before looping back */
_tls_sock_wait(tls, error); _tls_sock_wait(tls, error);
continue; continue;
@@ -791,7 +911,7 @@ int tls_stop(tls_t *tls)
++retries; ++retries;
ret = SSL_shutdown(tls->ssl); ret = SSL_shutdown(tls->ssl);
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0; error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
if (ret == 1 || !tls_is_recoverable(error) || if (ret == 1 || !tls_is_recoverable(NULL, error) ||
retries >= TLS_SHUTDOWN_MAX_RETRIES) { retries >= TLS_SHUTDOWN_MAX_RETRIES) {
break; break;
} }
@@ -810,21 +930,23 @@ int tls_stop(tls_t *tls)
return ret <= 0 ? 0 : 1; return ret <= 0 ? 0 : 1;
} }
int tls_is_recoverable(int error) int tls_is_recoverable(struct conn_interface *intf, int error)
{ {
UNUSED(intf);
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ || return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT || error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
error == SSL_ERROR_WANT_ACCEPT); error == SSL_ERROR_WANT_ACCEPT);
} }
int tls_pending(tls_t *tls) int tls_pending(struct conn_interface *intf)
{ {
return SSL_pending(tls->ssl); return SSL_pending(intf->conn->tls->ssl);
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(struct conn_interface *intf, void *buff, size_t len)
{ {
int ret; int ret;
tls_t *tls = intf->conn->tls;
ret = SSL_read(tls->ssl, buff, len); ret = SSL_read(tls->ssl, buff, len);
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0); _tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
@@ -832,9 +954,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return ret; return ret;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{ {
int ret; int ret;
tls_t *tls = intf->conn->tls;
ret = SSL_write(tls->ssl, buff, len); ret = SSL_write(tls->ssl, buff, len);
_tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0); _tls_set_error(tls, ret <= 0 ? SSL_get_error(tls->ssl, ret) : 0);
@@ -842,9 +965,9 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
return ret; return ret;
} }
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(struct conn_interface *intf)
{ {
UNUSED(tls); UNUSED(intf);
return 0; return 0;
} }
@@ -882,7 +1005,7 @@ static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
static void _tls_set_error(tls_t *tls, int error) static void _tls_set_error(tls_t *tls, int error)
{ {
if (error != 0 && !tls_is_recoverable(error)) { if (error != 0 && !tls_is_recoverable(NULL, error)) {
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d", strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d",
TLS_ERROR_STR(error, tls_errors), error, errno, TLS_ERROR_STR(error, tls_errors), error, errno,
tls->lasterror); tls->lasterror);
@@ -913,7 +1036,7 @@ static void _tls_dump_cert_info(tls_t *tls)
X509 *cert; X509 *cert;
char *name; char *name;
cert = SSL_get_peer_certificate(tls->ssl); cert = STROPHE_SSL_get1_peer_certificate(tls->ssl);
if (cert == NULL) if (cert == NULL)
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer"); strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else { else {

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls_schannel.c /* tls_schannel.c
** strophe XMPP client library -- TLS abstraction schannel impl. ** strophe XMPP client library -- TLS abstraction schannel impl.
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -236,6 +237,23 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
return -1; return -1;
} }
int tls_init_channel_binding(tls_t *tls,
const char **binding_prefix,
size_t *binding_prefix_len)
{
UNUSED(tls);
UNUSED(binding_prefix);
UNUSED(binding_prefix_len);
return -1;
}
const void *tls_get_channel_binding_data(tls_t *tls, size_t *size)
{
UNUSED(tls);
UNUSED(size);
return NULL;
}
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
ULONG ctxtreq = 0, ctxtattr = 0; ULONG ctxtreq = 0, ctxtattr = 0;
@@ -244,9 +262,11 @@ int tls_start(tls_t *tls)
SECURITY_STATUS ret; SECURITY_STATUS ret;
int sent; int sent;
char *name; char *name;
struct conn_interface *intf;
/* use the domain there as our name */ /* use the domain there as our name */
name = tls->conn->domain; name = tls->conn->domain;
intf = tls->conn->intf;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
@@ -295,9 +315,9 @@ int tls_start(tls_t *tls)
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer; unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
unsigned int writelen = sbdout.pBuffers[0].cbBuffer; unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen); sent = sock_write(intf, writebuff, writelen);
if (sent == -1) { if (sent == -1) {
tls->lasterror = sock_error(); tls->lasterror = sock_error(intf);
} else { } else {
writebuff += sent; writebuff += sent;
writelen -= sent; writelen -= sent;
@@ -335,13 +355,13 @@ int tls_start(tls_t *tls)
select(tls->sock, &fds, NULL, NULL, &tv); select(tls->sock, &fds, NULL, NULL, &tv);
inbytes = sock_read(tls->sock, p, tls->spi->cbMaxToken - len); inbytes = sock_read(intf, p, tls->spi->cbMaxToken - len);
if (inbytes > 0) { if (inbytes > 0) {
len += inbytes; len += inbytes;
p += inbytes; p += inbytes;
} else { } else {
tls->lasterror = sock_error(); tls->lasterror = sock_error(intf);
} }
} }
@@ -356,9 +376,9 @@ int tls_start(tls_t *tls)
if (sbdout.pBuffers[0].cbBuffer) { if (sbdout.pBuffers[0].cbBuffer) {
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer; unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
unsigned int writelen = sbdout.pBuffers[0].cbBuffer; unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen); sent = sock_write(intf, writebuff, writelen);
if (sent == -1) { if (sent == -1) {
tls->lasterror = sock_error(); tls->lasterror = sock_error(intf);
} else { } else {
writebuff += sent; writebuff += sent;
writelen -= sent; writelen -= sent;
@@ -405,20 +425,22 @@ int tls_stop(tls_t *tls)
return -1; return -1;
} }
int tls_error(tls_t *tls) int tls_error(struct conn_interface *intf)
{ {
return tls->lasterror; return intf->conn->tls->lasterror;
} }
int tls_is_recoverable(int error) int tls_is_recoverable(struct conn_interface *intf, int error)
{ {
UNUSED(intf);
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE || return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE || error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
error == WSAEINPROGRESS); error == WSAEINPROGRESS);
} }
int tls_pending(tls_t *tls) int tls_pending(struct conn_interface *intf)
{ {
tls_t *tls = intf->conn->tls;
// There are 3 cases: // There are 3 cases:
// - there is data in ready buffer, so it is by default pending // - there is data in ready buffer, so it is by default pending
// - there is data in recv buffer. If it is not decrypted yet, means it // - there is data in recv buffer. If it is not decrypted yet, means it
@@ -434,9 +456,10 @@ int tls_pending(tls_t *tls)
return 0; return 0;
} }
int tls_read(tls_t *tls, void *buff, size_t len) int tls_read(struct conn_interface *intf, void *buff, size_t len)
{ {
int bytes; int bytes;
tls_t *tls = intf->conn->tls;
/* first, if we've got some ready data, put that in the buffer */ /* first, if we've got some ready data, put that in the buffer */
if (tls->readybufferpos < tls->readybufferlen) { if (tls->readybufferpos < tls->readybufferlen) {
@@ -459,7 +482,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
read = tls_read(tls, newbuff, len - bytes); read = tls_read(tls, newbuff, len - bytes);
if (read == -1) { if (read == -1) {
if (tls_is_recoverable(tls->lasterror)) { if (tls_is_recoverable(intf, tls->lasterror)) {
return bytes; return bytes;
} }
@@ -471,7 +494,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
} }
/* next, top up our recv buffer */ /* next, top up our recv buffer */
bytes = sock_read(tls->sock, tls->recvbuffer + tls->recvbufferpos, bytes = sock_read(intf, tls->recvbuffer + tls->recvbufferpos,
tls->recvbuffermaxlen - tls->recvbufferpos); tls->recvbuffermaxlen - tls->recvbufferpos);
if (bytes == 0) { if (bytes == 0) {
@@ -480,8 +503,8 @@ int tls_read(tls_t *tls, void *buff, size_t len)
} }
if (bytes == -1) { if (bytes == -1) {
if (!tls_is_recoverable(sock_error())) { if (!tls_is_recoverable(intf, sock_error(intf))) {
tls->lasterror = sock_error(); tls->lasterror = sock_error(intf);
return -1; return -1;
} }
} }
@@ -556,16 +579,17 @@ int tls_read(tls_t *tls, void *buff, size_t len)
return -1; return -1;
} }
int tls_clear_pending_write(tls_t *tls) int tls_clear_pending_write(struct conn_interface *intf)
{ {
tls_t *tls = intf->conn->tls;
if (tls->sendbufferpos < tls->sendbufferlen) { if (tls->sendbufferpos < tls->sendbufferlen) {
int bytes; int bytes;
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos, bytes = sock_write(intf, tls->sendbuffer + tls->sendbufferpos,
tls->sendbufferlen - tls->sendbufferpos); tls->sendbufferlen - tls->sendbufferpos);
if (bytes == -1) { if (bytes == -1) {
tls->lasterror = sock_error(); tls->lasterror = sock_error(intf);
return -1; return -1;
} else if (bytes > 0) { } else if (bytes > 0) {
tls->sendbufferpos += bytes; tls->sendbufferpos += bytes;
@@ -579,12 +603,13 @@ int tls_clear_pending_write(tls_t *tls)
return 1; return 1;
} }
int tls_write(tls_t *tls, const void *buff, size_t len) int tls_write(struct conn_interface *intf, const void *buff, size_t len)
{ {
SecBufferDesc sbdenc; SecBufferDesc sbdenc;
SecBuffer sbenc[4]; SecBuffer sbenc[4];
const unsigned char *p = buff; const unsigned char *p = buff;
int sent = 0, ret, remain = len; int sent = 0, ret, remain = len;
tls_t *tls = intf->conn->tls;
ret = tls_clear_pending_write(tls); ret = tls_clear_pending_write(tls);
if (ret <= 0) { if (ret <= 0) {
@@ -644,7 +669,7 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
ret = tls_clear_pending_write(tls); ret = tls_clear_pending_write(tls);
if (ret == -1 && !tls_is_recoverable(tls_error(tls))) { if (ret == -1 && !tls_is_recoverable(intf, tls_error(tls))) {
return -1; return -1;
} }
@@ -656,7 +681,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
remain = 0; remain = 0;
} }
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) { if (ret == 0 ||
(ret == -1 && tls_is_recoverable(intf, tls_error(tls)))) {
return sent; return sent;
} }
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* util.c /* util.c
** strophe XMPP client library -- various utility functions ** strophe XMPP client library -- various utility functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* util.h /* util.h
** strophe XMPP client library -- various utility functions ** strophe XMPP client library -- various utility functions
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* uuid.c /* uuid.c
* strophe XMPP client library -- UUID generation * strophe XMPP client library -- UUID generation
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file

125
strophe.h
View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* strophe.h /* strophe.h
** strophe XMPP client library C API ** strophe XMPP client library C API
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
** **
** This software is dual licensed under the MIT and GPLv3 licenses. ** This software is dual licensed under the MIT or GPLv3 licenses.
*/ */
/** @file /** @file
@@ -83,6 +84,14 @@ extern "C" {
* Namespace definition for Stream Management. * Namespace definition for Stream Management.
*/ */
#define XMPP_NS_SM "urn:xmpp:sm:3" #define XMPP_NS_SM "urn:xmpp:sm:3"
/** @def XMPP_NS_COMPRESSION
* Namespace definition for Stream Compression.
*/
#define XMPP_NS_COMPRESSION "http://jabber.org/protocol/compress"
/** @def XMPP_NS_FEATURE_COMPRESSION
* Namespace definition for Stream Compression.
*/
#define XMPP_NS_FEATURE_COMPRESSION "http://jabber.org/features/compress"
/* error defines */ /* error defines */
/** @def XMPP_EOK /** @def XMPP_EOK
@@ -190,6 +199,15 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
* Disable Stream-Management XEP-0198. * Disable Stream-Management XEP-0198.
*/ */
#define XMPP_CONN_FLAG_DISABLE_SM (1UL << 5) #define XMPP_CONN_FLAG_DISABLE_SM (1UL << 5)
/** @def XMPP_CONN_FLAG_ENABLE_COMPRESSION
* Enable Stream-Compression XEP-0138.
*/
#define XMPP_CONN_FLAG_ENABLE_COMPRESSION (1UL << 6)
/** @def XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
* Don't reset the compressed stream after each stanza.
* Only enable this flag if you know what you're doing.
*/
#define XMPP_CONN_FLAG_COMPRESSION_DONT_RESET (1UL << 7)
/* connect callback */ /* connect callback */
typedef enum { typedef enum {
@@ -353,38 +371,70 @@ typedef int (*xmpp_sockopt_callback)(xmpp_conn_t *conn, void *sock);
/* an example callback that sets basic keepalive parameters */ /* an example callback that sets basic keepalive parameters */
int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock); int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx); xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn); xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
int xmpp_conn_release(xmpp_conn_t *conn); int xmpp_conn_release(xmpp_conn_t *conn);
/** Connection settings
*/
typedef enum xmpp_conn_setting_t {
/* String values */
XMPP_SETTING_JID = 0x0, /**< JID */
XMPP_SETTING_PASS, /**< Password */
XMPP_SETTING_CAFILE, /**< CAfile */
XMPP_SETTING_CAPATH, /**< CApath */
XMPP_SETTING_CLIENT_CERT, /**< Client Certificate */
XMPP_SETTING_CLIENT_KEY, /**< Key of Client Certificate */
/* Int values */
XMPP_SETTING_PASSWORD_RETRIES = 0x40, /**< Number of retry attempts to
decrypt a private key file. */
XMPP_SETTING_COMPRESSION_LEVEL, /**< Compression level. */
/* Pointer values */
XMPP_SETTING_PASSWORD_CALLBACK_USERDATA = 0x80, /**< Userdata for password
callback function */
/* Functionpointer values */
XMPP_SETTING_PASSWORD_CALLBACK = 0xC0, /**< Callback function to retrieve
password for key file. */
XMPP_SETTING_CERTFAIL_HANDLER, /**< Handler function when certificate chain
can't be verified */
XMPP_SETTING_SOCKOPT_CALLBACK, /**< Callback function when a new socket is
created. */
} xmpp_conn_setting_t;
void xmpp_conn_set_int(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
int value);
void xmpp_conn_set_string(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
const char *value);
void xmpp_conn_set_pointer(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
void *value);
/* Provide a wrapper macro, so users don't have to cast their function pointer
* type manually. */
typedef int (*xmpp_conn_pfn_t)();
#define xmpp_conn_set_functionpointer(c, s, p) \
do { \
xmpp_conn_set_functionpointer_impl(c, s, (xmpp_conn_pfn_t)p); \
} while (0)
void xmpp_conn_set_functionpointer_impl(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
xmpp_conn_pfn_t pfn);
long xmpp_conn_get_flags(const xmpp_conn_t *conn); long xmpp_conn_get_flags(const xmpp_conn_t *conn);
int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags); int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn); xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn); const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn); unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn);
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n); char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn); const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn); xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
void xmpp_conn_disable_tls(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn); int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
int xmpp_conn_is_connecting(xmpp_conn_t *conn); int xmpp_conn_is_connecting(xmpp_conn_t *conn);
int xmpp_conn_is_connected(xmpp_conn_t *conn); int xmpp_conn_is_connected(xmpp_conn_t *conn);
int xmpp_conn_is_disconnected(xmpp_conn_t *conn); int xmpp_conn_is_disconnected(xmpp_conn_t *conn);
@@ -428,6 +478,7 @@ int xmpp_conn_tls_start(xmpp_conn_t *conn);
void xmpp_disconnect(xmpp_conn_t *conn); void xmpp_disconnect(xmpp_conn_t *conn);
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza); void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...); void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...);
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len); void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len);
@@ -690,11 +741,19 @@ void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
*/ */
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len); void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
/** /*
* Formerly "private but exported" functions made public for now to announce * Formerly "private but exported" functions made public for now to announce
* deprecation */ * deprecation */
#include <stdarg.h> #include <stdarg.h>
#if !defined(XMPP_DEPRECATED)
/**
* XMPP_DEPRECATED(x) macro to show a compiler warning for deprecated API
* functions
*
* @param x The function that can be used as a replacement or 'internal' if
* there is no replacement
*/
#if defined(__GNUC__) #if defined(__GNUC__)
#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405) #if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
#define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x))) #define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
@@ -706,6 +765,7 @@ void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
#else #else
#define XMPP_DEPRECATED(x) #define XMPP_DEPRECATED(x)
#endif #endif
#endif
XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size); XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
XMPP_DEPRECATED(internal) XMPP_DEPRECATED(internal)
@@ -742,6 +802,33 @@ void xmpp_debug_verbose(
XMPP_DEPRECATED(xmpp_conn_set_sockopt_callback) XMPP_DEPRECATED(xmpp_conn_set_sockopt_callback)
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval); void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
XMPP_DEPRECATED(xmpp_conn_set_flags)
void xmpp_conn_disable_tls(xmpp_conn_t *conn);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
XMPP_DEPRECATED(xmpp_conn_set_int)
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
#ifdef __cplusplus #ifdef __cplusplus
} }

Binary file not shown.

Binary file not shown.

View File

@@ -1,16 +1,19 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICfjCCAjSgAwIBAgIIW5u5Vwn2Mv0wCgYIKoZIzj0EAwIwSzFJMEcGA1UEAwxA MIIDIDCCAqagAwIBAgIIddFxfQ2VcRIwCgYIKoZIzj0EAwQwSzFJMEcGA1UEAwxA
dmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxlbmd0aC5pcy5hLnZhbGlk dmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxlbmd0aC5pcy5hLnZhbGlk
LmFzY2lpLmNoYXJhY3RlcjAgFw0yMTAzMDExOTExMDBaGA8yMTIxMDMwMTE5MTEw LmFzY2lpLmNoYXJhY3RlcjAgFw0yMzA4MDkxMzI3MDBaGA8yMTI0MDgwOTEzMjcw
MFowSzFJMEcGA1UEAwxAdmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxl MFowSzFJMEcGA1UEAwxAdmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxl
bmd0aC5pcy5hLnZhbGlkLmFzY2lpLmNoYXJhY3RlcjBJMBMGByqGSM49AgEGCCqG bmd0aC5pcy5hLnZhbGlkLmFzY2lpLmNoYXJhY3RlcjB2MBAGByqGSM49AgEGBSuB
SM49AwEBAzIABI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE BAAiA2IABHfN9a5xAEPYWz+0O6Jfe95WGUeuq6Eca5po4UGcJgs78L6d4KT+FR/a
85RReISg+9/JDaOCAQ4wggEKMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPjLGyHxqlOV yDSi/BmS0ZAksXbshkSjQA6XmAwWkNInJF/buAwh/hFVAOXwx3eKtguPskxg1xYj
nXJQ9YBrnureO8LiMB8GA1UdIwQYMBaAFPjLGyHxqlOVnXJQ9YBrnureO8LiMAsG 0WZ3WrY9oKOCAVMwggFPMAkGA1UdEwQCMAAwHQYDVR0OBBYEFNeonZqrLTGCm3Vk
A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjCBmgYDVR0RBIGSMIGPoE4G +X3TtMfDQVf4MGQGA1UdIwRdMFuhT6RNMEsxSTBHBgNVBAMMQHZlcnkubG9uZy51
CCsGAQUFBwgFoEIMQHZlcnkubG9uZy51c2VybmFtZUBzby50aGUuYXNuMS5sZW5n c2VybmFtZUBzby50aGUuYXNuMS5sZW5ndGguaXMuYS52YWxpZC5hc2NpaS5jaGFy
dGguaXMuYS52YWxpZC5hc2NpaS5jaGFyYWN0ZXKBDnlldEBub3RoZXIuc2Fugg53 YWN0ZXKCCHXRcX0NlXESMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
d3cuc3Ryb3BoZS5pbaAdBggrBgEFBQcIBaARDA9zZWNvbmRAeG1wcC5qaWQwCgYI AjCBmgYDVR0RBIGSMIGPoE4GCCsGAQUFBwgFoEIMQHZlcnkubG9uZy51c2VybmFt
KoZIzj0EAwIDOAAwNQIZAJmfqBhBMdaKCiWEuXu84K4+lznfzlRfmwIYCGRD1xk0 ZUBzby50aGUuYXNuMS5sZW5ndGguaXMuYS52YWxpZC5hc2NpaS5jaGFyYWN0ZXKB
9cRa3V6PVwYWz6HcdRdMUBUj DnlldEBub3RoZXIuc2Fugg53d3cuc3Ryb3BoZS5pbaAdBggrBgEFBQcIBaARDA9z
ZWNvbmRAeG1wcC5qaWQwCgYIKoZIzj0EAwQDaAAwZQIxAJTzJY/q/zFws0FPPfVI
VXc+kaGdxwzM1FKlVMwxl+PzXAoeL0Z7FtGSkaCWyaokaAIwLaYxuQhgisetYxbU
qTyv0MdS2uUy6NNcVNztWCMS350TuuVm3f9wmwOjfaeoHft3
-----END CERTIFICATE----- -----END CERTIFICATE-----

Binary file not shown.

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* check_parser.h /* check_parser.h
** strophe XMPP client library -- parser tests ** strophe XMPP client library -- parser tests
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express or ** This software is provided AS-IS with no warranty, either express or
** implied. ** implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,5 +1,6 @@
-----BEGIN EC PRIVATE KEY----- -----BEGIN EC PRIVATE KEY-----
MF8CAQEEGF7SsbTSOjzb97nFc7Qbt4sic+1nZk+ETqAKBggqhkjOPQMBAaE0AzIA MIGkAgEBBDBZ90AXrC5n1ZxFGq4WpqMgvH7qw2YddaUzzPFtf9qDRDrRe3xW6nTr
BI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE85RReISg+9/J Iywpxdh26GWgBwYFK4EEACKhZANiAAR3zfWucQBD2Fs/tDuiX3veVhlHrquhHGua
DQ== aOFBnCYLO/C+neCk/hUf2sg0ovwZktGQJLF27IZEo0AOl5gMFpDSJyRf27gMIf4R
VQDl8Md3irYLj7JMYNcWI9Fmd1q2PaA=
-----END EC PRIVATE KEY----- -----END EC PRIVATE KEY-----

View File

@@ -1,8 +1,9 @@
-----BEGIN EC PRIVATE KEY----- -----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,30B7F2152A39184AEEF290ED2B1DBC0E DEK-Info: AES-256-CBC,D1537075EE9323A68A08B79257D87D53
IojJAF1hGHL9qnu5MCzl5l1PzsnxLj38JjLBLPXaNekiAbag5H9Tzr7y5nfyviPM faIortcMN9tCcmwidAJlFDOS68OJlAH1Bzjh2sqhZDhFJEU/w3bOihTDk1cV0yg1
hi6syrkXgLOBF+mZWJouOxCNx7+t6eWVfsDZcnzsw6HrTN/2xwkYP/3lYfzlnt6q JHSxolcX7aYLaBfhSdbnUDaeNhyvfF97O6lMHXbiSdkWBMKrOjSwpW5BcemQgbpI
/AKYQIUUPc/31J6xg3kGRQ== gjCi7KYWb2Z3CqcELR9624u4vRgytJQliqLW1jjnGMELcuq7HaoB2wP0XmXp9/BV
QMQU504S6V8JbogFZeNGCOq+EW5C8tEBCz82y1PRUr0=
-----END EC PRIVATE KEY----- -----END EC PRIVATE KEY-----

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* res_query_dump.c /* res_query_dump.c
* Simple program to dump res_query(3) response * Simple program to dump res_query(3) response
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* Linux and OSX: /* Linux and OSX:

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test.c /* test.c
* strophe XMPP client library -- common routines for tests * strophe XMPP client library -- common routines for tests
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test.h /* test.h
** libstrophe XMPP client library -- common routines for tests ** libstrophe XMPP client library -- common routines for tests
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#ifndef __LIBSTROPHE_TEST_H__ #ifndef __LIBSTROPHE_TEST_H__
@@ -34,46 +35,48 @@
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif #endif
#define COMPARE(v1, v2) \ #define COMPARE(should, is) \
do { \ do { \
const char *__v1 = v1; \ const char *__should = should; \
const char *__v2 = v2; \ const char *__is = is; \
if ((__v1 == NULL) && (__v2 == NULL)) { \ if ((__should == NULL) && (__is == NULL)) { \
/* noop */ \ /* noop */ \
} else if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \ } else if (!__should || !__is || strcmp(__should, __is) != 0) { \
printf("Error: %s\n" \ printf("Error: %s\n" \
"Expected: %s\n" \ "Expected: %s\n" \
"Got: %s\n", \ "Got: %s\n", \
#v1 " != " #v2, __v1, __v2); \ #should " != " #is, __should, __is); \
exit(1); \ exit(1); \
} \ } \
} while (0) } while (0)
#define COMPARE_BUF(v1, len1, v2, len2) \ #define COMPARE_BUF(should, should_len, is, is_len) \
do { \ do { \
const uint8_t *__v1 = (uint8_t *)(v1); \ const uint8_t *__should = (uint8_t *)(should); \
const uint8_t *__v2 = (uint8_t *)(v2); \ const uint8_t *__is = (uint8_t *)(is); \
size_t __len1 = len1; \ size_t __should_len = should_len; \
size_t __len2 = len2; \ size_t __is_len = is_len; \
if (__len1 != __len2 || memcmp(__v1, __v2, __len1) != 0) { \ if (__should_len != __is_len || \
printf("Error: %s\n", #v1 " != " #v2); \ memcmp(__should, __is, __should_len) != 0) { \
printf("Expected: 0x%s\n", test_bin_to_hex(__v1, __len1)); \ printf("Error: %s\n", #should " != " #is); \
printf("Got: 0x%s\n", test_bin_to_hex(__v2, __len2)); \ printf("Expected: 0x%s\n", \
exit(1); \ test_bin_to_hex(__should, __should_len)); \
} \ printf("Got: 0x%s\n", test_bin_to_hex(__is, __is_len)); \
exit(1); \
} \
} while (0) } while (0)
#define ENSURE_EQ(v1, v2) \ #define ENSURE_EQ(should, is) \
do { \ do { \
int __v1 = v1; \ int __should = should; \
int __v2 = v2; \ int __is = is; \
if (__v1 != __v2) { \ if (__should != __is) { \
printf("Error: %s\n" \ printf("Error: %s\n" \
"Expected: %d\n" \ "Expected: %d\n" \
"Got: %d\n", \ "Got: %d\n", \
#v1 " != " #v2, __v2, __v1); \ #should " != " #is, __is, __should); \
exit(1); \ exit(1); \
} \ } \
} while (0) } while (0)
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len); void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len);

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_base64.c /* test_base64.c
** libstrophe XMPP client library -- test routines for the base64 codec ** libstrophe XMPP client library -- test routines for the base64 codec
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_ctx.c /* test_ctx.c
** libstrophe XMPP client library -- test routines for the library run-time ** libstrophe XMPP client library -- test routines for the library run-time
*context *context
@@ -7,7 +8,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdio.h> #include <stdio.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_hash.c /* test_hash.c
** libstrophe XMPP client library -- self-test for the hash-table implementation ** libstrophe XMPP client library -- self-test for the hash-table implementation
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_jid.c /* test_jid.c
** libstrophe XMPP client library -- test routines for the jid utils ** libstrophe XMPP client library -- test routines for the jid utils
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdio.h> #include <stdio.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_md5.c /* test_md5.c
* strophe XMPP client library -- test vectors for MD5 * strophe XMPP client library -- test vectors for MD5
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* gcc -o test_md5 -I./src tests/test_md5.c tests/test.c src/md5.c */ /* gcc -o test_md5 -I./src tests/test_md5.c tests/test.c src/md5.c */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* check_rand.c /* check_rand.c
* strophe XMPP client library -- test vectors for Hash_DRBG * strophe XMPP client library -- test vectors for Hash_DRBG
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* gcc -o test_rand -I./src tests/test_rand.c tests/test.c src/sha1.c */ /* gcc -o test_rand -I./src tests/test_rand.c tests/test.c src/sha1.c */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_resolver.c /* test_resolver.c
* strophe XMPP client library -- tests for resolver * strophe XMPP client library -- tests for resolver
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_sasl.c /* test_sasl.c
** libstrophe XMPP client library -- test routines for the SASL implementation ** libstrophe XMPP client library -- test routines for the SASL implementation
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdio.h> #include <stdio.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_scram.c /* test_scram.c
* strophe XMPP client library -- test vectors for SCRAM-SHA1 * strophe XMPP client library -- test vectors for SCRAM-SHA1
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* gcc -o test_scram -I./src tests/test_scram.c tests/test.c src/sha1.c */ /* gcc -o test_scram -I./src tests/test_scram.c tests/test.c src/sha1.c */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_send_queue.c /* test_send_queue.c
** libstrophe XMPP client library -- test routines for the send queue ** libstrophe XMPP client library -- test routines for the send queue
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>
@@ -39,48 +40,48 @@ int main()
xmpp_conn_set_sm_state(conn, sm_state); xmpp_conn_set_sm_state(conn, sm_state);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0); ENSURE_EQ(0, xmpp_conn_send_queue_len(conn));
state = conn->state; state = conn->state;
conn->state = XMPP_STATE_CONNECTED; conn->state = XMPP_STATE_CONNECTED;
xmpp_send_raw(conn, "foo", 3); xmpp_send_raw(conn, "foo", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1); ENSURE_EQ(1, xmpp_conn_send_queue_len(conn));
xmpp_send_raw(conn, "bar", 3); xmpp_send_raw(conn, "bar", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2); ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
xmpp_send_raw(conn, "baz", 3); xmpp_send_raw(conn, "baz", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3); ENSURE_EQ(3, xmpp_conn_send_queue_len(conn));
xmpp_send_raw(conn, "baan", 4); xmpp_send_raw(conn, "baan", 4);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 4); ENSURE_EQ(4, xmpp_conn_send_queue_len(conn));
conn->send_queue_head->wip = 1; conn->send_queue_head->wip = 1;
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3); ENSURE_EQ(3, xmpp_conn_send_queue_len(conn));
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST); ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST);
COMPARE("bar", ret); COMPARE("bar", ret);
xmpp_free(ctx, ret); xmpp_free(ctx, ret);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2); ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
conn->send_queue_head->wip = 0; conn->send_queue_head->wip = 0;
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3); ENSURE_EQ(3, xmpp_conn_send_queue_len(conn));
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST); ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_OLDEST);
COMPARE("foo", ret); COMPARE("foo", ret);
xmpp_free(ctx, ret); xmpp_free(ctx, ret);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2); ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST); ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST);
COMPARE("baan", ret); COMPARE("baan", ret);
xmpp_free(ctx, ret); xmpp_free(ctx, ret);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1); ENSURE_EQ(1, xmpp_conn_send_queue_len(conn));
ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST); ret = xmpp_conn_send_queue_drop_element(conn, XMPP_QUEUE_YOUNGEST);
COMPARE("baz", ret); COMPARE("baz", ret);
xmpp_free(ctx, ret); xmpp_free(ctx, ret);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0); ENSURE_EQ(0, xmpp_conn_send_queue_len(conn));
conn->state = state; conn->state = state;

View File

@@ -7,6 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <limits.h>
#undef HAVE_VSNPRINTF #undef HAVE_VSNPRINTF
#undef HAVE_SNPRINTF #undef HAVE_SNPRINTF
@@ -28,7 +29,14 @@ int main(void)
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d", char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
"%4d", "0x%x", "0x%04x", NULL}; "%4d", "0x%x", "0x%04x", NULL};
long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0}; int int_nums[] = {-1, 134, 91340, 341, 0203,
0x76543210, INT_MIN, INT_MAX, 0};
char *long_fmt[] = {"%-1.5ld", "%1.5ld", "%123.9ld", "%5.5ld",
"%10.5ld", "% 10.5ld", "%+22.33ld", "%01.3ld",
"%4ld", "0x%lx", "0x%04lx", NULL};
long long_nums[] = {-1L, 134L, 91340L,
341L, 0203L, 0xFEDCBA9876543210L,
LONG_MIN, LONG_MAX, 0L};
int x, y; int x, y;
int fail = 0; int fail = 0;
int num = 0; int num = 0;
@@ -60,6 +68,19 @@ int main(void)
} }
num++; num++;
} }
for (x = 0; long_fmt[x] != NULL; x++)
for (y = 0; long_nums[y] != 0; y++) {
strophe_snprintf(buf1, sizeof(buf1), long_fmt[x], long_nums[y]);
sprintf(buf2, long_fmt[x], long_nums[y]);
if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: "
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
long_fmt[x], buf1, buf2);
fail++;
}
num++;
}
printf("%d tests failed out of %d.\n", fail, num); printf("%d tests failed out of %d.\n", fail, num);
return fail != 0 ? 1 : 0; return fail != 0 ? 1 : 0;
} }

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_sock.c /* test_sock.c
** libstrophe XMPP client library -- test routines for the socket abstraction ** libstrophe XMPP client library -- test routines for the socket abstraction
** **
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <stdio.h> #include <stdio.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_stanza.c /* test_stanza.c
* libstrophe XMPP client library -- test routines for stanza functions * libstrophe XMPP client library -- test routines for stanza functions
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */ /* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
@@ -174,7 +175,7 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL); xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
assert(error != NULL); assert(error != NULL);
mood = xmpp_stanza_new_from_string(ctx, str_mood); mood = xmpp_stanza_new_from_string(ctx, str_mood);
assert(stanza != NULL); assert(mood != NULL);
assert(xmpp_stanza_get_to(error) != NULL); assert(xmpp_stanza_get_to(error) != NULL);
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error)); COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_string.c /* test_string.c
* strophe XMPP client library -- tests for re-implemented string functions * strophe XMPP client library -- tests for re-implemented string functions
* *
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express * This software is provided AS-IS with no warranty, either express
* or implied. * or implied.
* *
* This program is dual licensed under the MIT and GPLv3 licenses. * This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_xmppaddr.c /* test_xmppaddr.c
** libstrophe XMPP client library -- test routines for the xmppaddr ** libstrophe XMPP client library -- test routines for the xmppaddr
** certificate API's ** certificate API's
@@ -7,7 +8,7 @@
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
** **
** This program is dual licensed under the MIT and GPLv3 licenses. ** This program is dual licensed under the MIT or GPLv3 licenses.
*/ */
#include <assert.h> #include <assert.h>
@@ -15,6 +16,7 @@
#include <string.h> #include <string.h>
#include <sys/param.h> #include <sys/param.h>
#define XMPP_DEPRECATED(x)
#include "strophe.h" #include "strophe.h"
#include "test.h" #include "test.h"
@@ -40,12 +42,14 @@ int main()
} client_cert[] = { } client_cert[] = {
{0, "tests/cert.pem", "tests/key.pem"}, {0, "tests/cert.pem", "tests/key.pem"},
{1, "tests/cert.pem", "tests/key_encrypted.pem"}, {1, "tests/cert.pem", "tests/key_encrypted.pem"},
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
{0, "tests/cert.emptypass.pfx", NULL}, {0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL}, {0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL}, {1, "tests/cert.pfx", NULL},
/* Backward compatibility checks for change introduced in #208
* To be removed, once xmpp_conn_set_client_cert() is gone */
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
}; };
const char *srcdir; const char *srcdir;
@@ -77,9 +81,15 @@ int main()
keyfile = NULL; keyfile = NULL;
if (client_cert[m].needs_callback) if (client_cert[m].needs_callback)
xmpp_conn_set_password_callback(conn, password_callback, NULL); xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK,
password_callback);
xmpp_conn_set_client_cert(conn, certfile, keyfile); if (certfile) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, certfile);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, keyfile);
} else {
xmpp_conn_set_client_cert(conn, certfile, keyfile);
}
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn); xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);