59 Commits

Author SHA1 Message Date
Steffen Jaeckel
dfb3e86824 Use void* to store function pointer when compiled as C23.
[0] decided that `rettype (*foo)();` must now be interpreted as
`rettype (*foo)(void);`. Luckily it also allows now to store function
pointers in a `void*` (c.f. Ch. J.5.7).

[0]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-26 17:24:12 +01:00
Steffen Jaeckel
a81f0a8a5f Auto-format according to new clang-format.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-26 15:18:52 +01:00
Steffen Jaeckel
5509ec3b35 Update CI
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-26 14:17:54 +01:00
Steffen Jaeckel
67b1a2f3f4 Add support for DragonFlyBSD in configure.ac
Hinted to by gnemmi in profanity@rooms.dismail.de

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2025-03-13 19:49:14 +01:00
Steffen Jaeckel
7c2e78937d Release libstrophe-0.14.0
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2025-03-13 14:44:37 +01:00
Steffen Jaeckel
b7bae1502f Update docs of SM-serialization.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2025-03-13 14:44:08 +01:00
Steffen Jaeckel
e3d734c5ff Fix SM-serialization testcase
`xmpp_run_once()` uses `FD_SET()` to determine which sockets to `select()`
on. The socket gets initialized to `INVALID_SOCKET = -1` inside
`xmpp_conn_new()` which leads to a buffer overflow once `FD_SET()` is
called.

This is only exposed when enabling a higher optimization level, which
was only done in the `release-test` CI job.

* Fix this testcase by initializing the socket to a possible value.
* Build the Valgrind CI jobs with `-O2`.
* Make the output of the `release-test` more verbose.

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2024-11-19 16:26:50 +01:00
Steffen Jaeckel
e7b08faaa7 Clean up SM state serialization
* Refactor `xmpp_sm_state_restore()`

Add new internal functions to load u32 and string values. This also brings
length checks in order to verify we don't read more sm_state than there
potentially is and type checks to ensure we have the correct CBOR types.

Each element is added to the queue right after creation, so it won't leak
in case creating its content fails.

* Refactor `sm_state_serialize()`

* Store & restore ints as/from big endian, CBOR requires that

* Bring API names in line with the usual naming

* Auto-format sources

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
2024-11-19 16:26:50 +01:00
Stephen Paul Weber
f3fa9f557b Allow serializing SM state
It is useful in some applications to get a snapshot of the stream
management state for storage outside the process, in order to recover
from crashes and other things.  The get_sm_state already present is not
suitable for this because it returns a live object tied in to the
current context and such, and containing much unneeded internal-api
data.

Introduce xmpp_sm_state_set_callback which is called every time the
state changes with a serialized state, and a dual xmpp_sm_state_restore
which takes in this serialized state and sets up a new sm_state based on
that.

The serialization is considered opaque from the PoV of the API, but is
based on CBOR to facilitate easy debugging.
2024-11-19 16:26:49 +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
Steffen Jaeckel
f13ea6e556 Release libstrophe-0.12.3
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-08-02 15:42:54 +02:00
Steffen Jaeckel
29f68c0dd7 Update AUTHORS file
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-08-02 15:42:54 +02:00
Steffen Jaeckel
3c0966d74e Run CI also on next branch
Like that we can test stuff without opening a PR, before it necessarily
lands on `master`.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-08-02 15:42:27 +02:00
Steffen Jaeckel
c90128779f Fix xmpp_stanza_release() for cloned child-stanzas.
Break the linked-list of children before releasing a child.

Before this patch it was possible, when a child is cloned and stored
for longer than the lifetime of its parent, that its `next` pointer
points to invalid memory that was already free'd when the parent stanza
was released.

This issue exists already since the initial version of
`xmpp_stanza_release()`.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-07-28 15:36:54 +02:00
Steffen Jaeckel
acb8e0f629 Handle missing <bind>
This patch handles the case where the server sends its list of features,
but the `<bind>` feature is missing.
A server doing so is violating RFC6120 (c.f. [0]), but it happened in [1].
Previously we ended up in a segfault, now we terminate the connection.

Reproducing this was done with netcat and profanity:

```
shell1    $ nc -l -p 5222
profanity $ /connect foo@127.0.0.1 tls disable

-> nc receives: '<?xml version="1.0"?><stream:stream to="127.0.0.1" xml:lang="en" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">'

nc send: <?xml version="1.0"?>
<stream:stream from="127.0.0.1" id="foobarbaz" lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">
<features xmlns="http://etherx.jabber.org/streams"><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></features>

-> nc receives: '<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">XXXXXXXXXX</auth>'

nc send: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

-> nc receives: '<?xml version="1.0"?><stream:stream to="127.0.0.1" xml:lang="en" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams"><stream:stream from="127.0.0.1" id="foobarbaz" lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">'

nc send: <?xml version="1.0"?>
<stream:stream from="127.0.0.1" id="foobarbaz" lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">
<features xmlns="http://etherx.jabber.org/streams"/>

-> pre-patch this lead to a segfault of profanity, now the stream gets closed.
```

[0] https://datatracker.ietf.org/doc/html/rfc6120#section-7.2
[1] https://github.com/profanity-im/profanity/issues/1849

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-07-28 15:36:54 +02:00
Dmitry Podgorny
f3460460e9 sock: Introduce xmpp_sock_t abstraction
libstrophe uses non-blocking sockets and the connect() syscall may
return before a TCP connection is established. This doesn't allow
to catch all possible errors synchronously and some of the errors
are handled in the event handler.

In a scenario with multiple SRV records and/or multiple IP addresses
resolution, we need to repeat connection attempt on a failure.

xmpp_sock_t resolves the above problem. It keeps resolved records and
addresses to repeat connect attempt asynchronously.
2023-06-16 20:33:00 +03:00
Steffen Jaeckel
37555868f6 improve JID parsing according to RFC7622
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-03-10 11:11:44 +01:00
Steffen Jaeckel
b0855f75f5 don't return RR list on error
The resolver maybe returned an error code but allocated an RR list. Free
this list now in the resolver instead of depending on the user to free it
even though there was an error.

This API is only library internal, but still it makes more sense like that.

This issue was discovered in CI job [0].

[0] https://github.com/strophe/libstrophe/actions/runs/3874980845/jobs/6776501943

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-01-19 10:30:08 +01:00
Steffen Jaeckel
977ef75b14 fix potential memory leak
If functions `xmpp_conn_set_cafile()` or `xmpp_conn_set_capath()` are
called twice they leaked the previously allocated memory.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-01-09 15:55:23 +01:00
Steffen Jaeckel
d7d7435f21 less calls to xmpp_stanza_release()
Instead of using the "cloning version" `xmpp_stanza_add_child()` use the
version that takes ownership, so we don't have to release directly
afterwards.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-01-09 15:55:23 +01:00
Steffen Jaeckel
d22558e0e3 send_stanza() now takes ownership of the stanza
Instead of always releasing the stanza after calling `send_stanza()`, this
is done inside the function now.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2023-01-09 15:55:23 +01:00
Anna “CyberTailor”
96ece6fbdb test configure script with dash in CI 2022-11-12 13:23:20 +01:00
Anna “CyberTailor”
a60d2ea19d configure: fix non-portable "==" tests 2022-11-12 12:58:35 +01:00
87 changed files with 2855 additions and 977 deletions

View File

@@ -2,18 +2,20 @@ name: CI
on:
push:
branches: [master]
branches:
- master
- next
pull_request:
branches: [master]
jobs:
linux-tests:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
valgrind:
- { configure: '' , make: 'check' }
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
- { configure: '' , cflags: '', make: 'check' }
- { configure: '--enable-valgrind' , cflags: '-O2', make: 'check-valgrind' }
options:
- { configure: '' }
- { configure: '--without-libxml2' }
@@ -22,6 +24,7 @@ jobs:
- { configure: '--disable-tls' }
- { configure: '--enable-cares' }
- { configure: '--disable-getrandom' }
- { configure: '--disable-static' }
name: Regular Tests
steps:
- uses: actions/checkout@v2
@@ -32,7 +35,7 @@ jobs:
- name: Build the library
run: |
./bootstrap.sh
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3"
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3 ${{ matrix.valgrind.cflags }}"
make -j$(nproc)
- name: Run tests
run: |
@@ -43,26 +46,35 @@ jobs:
cat test-suite*.log || true
xssl-tests:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
matrix:
xssl_versions:
- { version: "master", continue: true, libressl: true }
- { version: "OPENBSD_7_1", continue: true, libressl: true }
- { version: "master", 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
# - { 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"
# - { version: "v3.4.3", continue: true, libressl: true }
- { version: "v3.4.2", continue: true, libressl: true }
- { version: "OPENBSD_6_9", continue: true, libressl: true }
- { version: "v3.1.5", continue: true, libressl: true }
- { version: "v2.1.10", continue: true, libressl: true }
- { version: "openssl-3.0", continue: true, libressl: false }
- { version: "openssl-3.0.4", continue: false, libressl: false }
valgrind:
- { configure: '' , make: 'check' }
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
# - { version: "v3.4.3", continue: true, libressl: true }
- { version: "v3.4.2", continue: true, libressl: true }
- { version: "OPENBSD_6_9", continue: true, libressl: true }
- { version: "v3.1.5", continue: true, libressl: true }
- { version: "v2.1.10", continue: true, libressl: true }
- { version: "openssl-3.0", continue: true, libressl: false }
- { version: "openssl-3.0.13", continue: false, libressl: false }
- { version: "openssl-3.1", continue: true, libressl: false }
- { version: "openssl-3.1.5", continue: false, libressl: false }
- { 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
continue-on-error: ${{ matrix.xssl_versions.continue }}
steps:
@@ -80,11 +92,19 @@ jobs:
- name: Build the library
run: |
./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)
- name: Run tests
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
if: ${{ failure() }}
run: |
@@ -95,13 +115,18 @@ jobs:
name: Check if release would work
steps:
- uses: actions/checkout@v2
- name: install dependencies
- name: install dependencies & bootstrap
run: |
sudo apt update
sudo apt install -y libtool pkg-config libexpat1-dev
- name: Setup the library
run: |
sudo apt install -y libtool pkg-config libexpat1-dev dash
./bootstrap.sh
- name: Check if configure works with non-bash shells
# https://github.com/actions/runner/issues/241 requires us to use this following line...
shell: 'script --return --quiet --command "bash {0}"'
run: |
[ "`CONFIG_SHELL=/bin/dash ./configure 2>&1 1>/dev/null | tee /dev/tty | wc -l`" = "0" ]
- name: Re-run configure with the default shell
run: |
./configure
- name: Try release & tests
run: |
@@ -110,9 +135,14 @@ jobs:
if: ${{ !failure() }}
run: |
cat testbuild.log
- name: Error logs
if: ${{ failure() }}
run: |
cat testbuild.log || true
cat testerr.log || true
code-style:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
name: Check coding style
continue-on-error: true
steps:

2
.gitignore vendored
View File

@@ -46,6 +46,7 @@ examples/roster
examples/uuid
examples/vcard
testbuild*.log
testerr*.log
test-release/
test_stamp
test-suite*.log
@@ -65,6 +66,7 @@ tests/test_resolver
tests/test_sasl
tests/test_scram
tests/test_send_queue
tests/test_serialize_sm
tests/test_sha1
tests/test_sha256
tests/test_sha512

View File

@@ -1 +1,8 @@
Current maintainer:
Steffen Jaeckel <gh@jaeckel.eu>
Previous maintainers:
Dmitry Podgorny <pasis.ua@gmail.com>
Jack Moffit <jack@metajack.im>
Other contributors can be extracted from the Git log.

View File

@@ -1,3 +1,38 @@
0.14.0
- Add SM-state serialization mechanism (#239)
- Add support for `SCRAM-SHA-512-PLUS` (da122981)
- Add support for `SSLKEYLOGFILE` with OpenSSL (d82df127)
- Fix some issues related to Stream Management (03d43132, 4359536a)
- Fix a potential segfault (9fef4b7d)
- New API:
- xmpp_conn_set_sm_callback()
- xmpp_conn_restore_sm_state()
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
- Improve TCP-connection establishment (#221)
- Handle case where the server doesn't provide the `bind` feature (#224)
- Fix configure script for non-bash shells (#218)
- Parse JID's according to RFC7622 (#219)
- Fix potential memory leak in internal DNS resolver (#219)
- Fix potential memory leaks in `xmpp_conn_set_cafile()` and `xmpp_conn_set_capath()` (#219)
- Internal improvements (#219)
0.12.2
- Fix reconnect issues when Stream Management is enabled (#211)
- Fix resolver ... this time for real hopefully (fixup of #200) (#214)
@@ -12,7 +47,7 @@
- Fix some build steps when builddir != srcdir (#208)
- Allow the user to disable build of examples (#209)
- 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`
parameter. Originally it was via `key`. Currently both styles are supported,
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
# control system is used.
PROJECT_NUMBER = 0.12
PROJECT_NUMBER = 0.14
# 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

View File

@@ -1,5 +1,5 @@
libstrophe XMPP client library
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.

View File

@@ -10,6 +10,9 @@ COVERAGE_POST=@COVERAGE_POST@
PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@
ZLIB_CFLAGS=@ZLIB_CFLAGS@
ZLIB_LIBS=@ZLIB_LIBS@
if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@
@@ -32,8 +35,8 @@ STROPHE_LIBS = $(COVERAGE_PRE) libstrophe.la $(COVERAGE_POST) $(COVERAGE_LDFLAGS
## Main build targets
lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) -no-undefined
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) $(ZLIB_LIBS) -no-undefined
# Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@
@@ -82,6 +85,12 @@ if NEED_SNPRINTF
libstrophe_la_SOURCES += src/snprintf.c
endif
if DISABLE_COMPRESSION
libstrophe_la_SOURCES += src/compression_dummy.c
else
libstrophe_la_SOURCES += src/compression.c
endif
if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c
else
@@ -175,23 +184,30 @@ endif
## Tests
TESTS = \
STATIC_TESTS = \
tests/check_parser \
tests/test_hash \
tests/test_jid \
tests/test_ctx \
tests/test_send_queue \
tests/test_serialize_sm \
tests/test_string \
tests/test_resolver
TESTS = \
tests/test_sha1 \
tests/test_sha256 \
tests/test_sha512 \
tests/test_md5 \
tests/test_rand \
tests/test_scram \
tests/test_ctx \
tests/test_base64 \
tests/test_hash \
tests/test_jid \
tests/test_send_queue \
tests/test_snprintf \
tests/test_string \
tests/test_stanza \
tests/test_resolver
tests/test_stanza
if !DISABLE_STATIC
TESTS += $(STATIC_TESTS)
endif
if !DISABLE_TLS
TESTS += tests/test_xmppaddr
@@ -270,6 +286,11 @@ tests_test_send_queue_CFLAGS = -I$(top_srcdir)/src
tests_test_send_queue_LDADD = $(STROPHE_LIBS)
tests_test_send_queue_LDFLAGS = -static
tests_test_serialize_sm_SOURCES = tests/test_serialize_sm.c tests/test.c tests/test.h
tests_test_serialize_sm_CFLAGS = -I$(top_srcdir)/src
tests_test_serialize_sm_LDADD = $(STROPHE_LIBS)
tests_test_serialize_sm_LDFLAGS = -static
tests_test_snprintf_SOURCES = tests/test_snprintf.c
tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src
@@ -312,6 +333,7 @@ dist-archives:
test-release: dist
@touch testbuild-$(PACKAGE_VERSION).log && ln -sf testbuild-$(PACKAGE_VERSION).log testbuild.log
@touch testerr-$(PACKAGE_VERSION).log && ln -sf testerr-$(PACKAGE_VERSION).log testerr.log
@mkdir -p test-release && cp $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.* test-release && pushd test-release && \
tar xzf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.gz && pushd $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && ./testbuild.sh && popd && rm -rf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && \
echo "Success" && popd

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
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
------------------
@@ -88,7 +88,7 @@ or if you have everything configured properly:
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
--------

View File

@@ -1,6 +1,6 @@
m4_define([v_maj], [0])
m4_define([v_min], [12])
m4_define([v_patch], [2])
m4_define([v_min], [14])
m4_define([v_patch], [0])
m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min))
@@ -18,9 +18,10 @@ PKG_PROG_PKG_CONFIG
AC_CANONICAL_HOST
AS_CASE([$host_os],
[dragonfly*], [PLATFORM="bsd"],
[freebsd*], [PLATFORM="bsd"],
[openbsd*], [PLATFORM="bsd"],
[netbsd*], [PLATFORM="bsd"],
[openbsd*], [PLATFORM="bsd"],
[*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"],
@@ -51,6 +52,8 @@ AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([getrandom],
[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],
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
@@ -123,7 +126,7 @@ if test x"$have_va_copy$have___va_copy" = x"nono"; then
AC_DEFINE([VA_LIST_IS_ARRAY], [1],[Define if va_list is an array type])])
fi
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
if test "x$enable_tls" != xno -a "x$with_gnutls" = xyes; then
PKG_CHECK_MODULES([gnutls], [gnutls],
[PC_REQUIRES="gnutls ${PC_REQUIRES}"],
[AC_CHECK_HEADER([gnutls/gnutls.h],
@@ -133,7 +136,7 @@ if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
],
[AC_MSG_ERROR([gnutls not found; gnutls required])]
)])
elif test "x$enable_tls" != xno -a "x$with_schannel" == xyes; then
elif test "x$enable_tls" != xno -a "x$with_schannel" = xyes; then
if test "x$PLATFORM" != xwin32; then
AC_MSG_ERROR([schannel is only supported on Windows])
fi
@@ -247,6 +250,18 @@ 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],
[AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir],
@@ -255,7 +270,9 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
AC_SUBST([pkgconfigdir], [${with_pkgconfigdir}])])
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_STATIC], [test x$enable_static = xno])
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
AM_CONDITIONAL([TLS_WITH_SCHANNEL], [test x$with_schannel = xyes])
@@ -289,5 +306,7 @@ AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS)
AC_SUBST(WARNING_FLAGS)
AC_SUBST(ZLIB_CFLAGS)
AC_SUBST(ZLIB_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* active.c
** libstrophe XMPP client library -- basic usage example
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* basic.c
** libstrophe XMPP client library -- basic usage example
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* bot.c
** libstrophe XMPP client library -- basic usage example
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -76,13 +77,19 @@ int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
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)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *body, *reply;
const char *type;
char *intext, *replytext;
int quit = 0;
body = xmpp_stanza_get_child_by_name(stanza, "body");
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) {
replytext = strdup("bye!");
quit = 1;
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
} else if (strcmp(intext, "reconnect") == 0) {
replytext = strdup("alright, let's see what happens!");
reconnect = 1;
quit = 1;
xmpp_timed_handler_add(conn, _quit_handler, 500, NULL);
} else {
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
@@ -119,9 +126,6 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_release(reply);
free(replytext);
if (quit)
xmpp_disconnect(conn);
return 1;
}
@@ -213,7 +217,10 @@ static void usage(int exit_code)
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
"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);
}
@@ -243,6 +250,10 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0)
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))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* complex.c
** libstrophe XMPP client library -- more complex usage example
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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>
@@ -238,6 +239,9 @@ static void usage(int exit_code)
" --enable-certfail Enable certfail handler.\n"
" --legacy-ssl Use old style SSL.\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"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
@@ -272,6 +276,10 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0)
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)
verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* component.c
** libstrophe XMPP client library -- external component (XEP-0114) example
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* perf.c
* strophe XMPP client library -- performance measure
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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

View File

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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* roster.c
** libstrophe XMPP client library -- handler example
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* vcard.c
* strophe XMPP client library -- vCard example
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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>

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* common.h
** strophe XMPP client library -- internal common structures
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express 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
@@ -29,12 +30,17 @@
#include "snprintf.h"
/** handlers **/
#if (__STDC_VERSION__ >= 202000L)
typedef void* xmpp_void_handler;
#else
typedef int (*xmpp_void_handler)();
#endif
typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t {
/* common members */
int user_handler;
int (*handler)();
xmpp_void_handler handler;
void *userdata;
int enabled; /* handlers are added disabled and enabled after the
* handler chain is processed to prevent stanzas from
@@ -92,6 +98,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_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
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 */
void strophe_error(const xmpp_ctx_t *ctx,
@@ -119,6 +132,12 @@ void strophe_log_internal(const xmpp_ctx_t *ctx,
const char *fmt,
va_list ap);
#if defined(__OpenBSD__)
#define STR_MAYBE_NULL(p) (p) ? (p) : "(null)"
#else
#define STR_MAYBE_NULL(p) (p)
#endif
/** connection **/
/* opaque connection object */
@@ -159,9 +178,16 @@ struct _xmpp_send_queue_t {
#define SASL_MASK_SCRAMSHA256 (1 << 4)
#define SASL_MASK_SCRAMSHA512 (1 << 5)
#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)
#define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK)
enum {
XMPP_PORT_CLIENT = 5222,
@@ -180,14 +206,36 @@ struct _xmpp_sm_t {
int sm_support;
int sm_enabled;
int can_resume, resume, dont_request_resume;
xmpp_queue_t sm_queue;
int r_sent;
uint32_t sm_handled_nr;
uint32_t sm_sent_nr;
xmpp_queue_t sm_queue;
char *id, *previd, *bound_jid;
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 conn_interface intf;
unsigned int ref;
xmpp_ctx_t *ctx;
xmpp_conn_type_t type;
@@ -198,6 +246,7 @@ struct _xmpp_conn_t {
int error;
xmpp_stream_error_t *stream_error;
xmpp_sock_t *xsock;
sock_t sock;
int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */
@@ -234,6 +283,11 @@ struct _xmpp_conn_t {
int sm_disable;
xmpp_sm_state_t *sm_state;
struct {
struct xmpp_compression *state;
int allowed, supported, dont_reset;
} compression;
char *lang;
char *domain;
char *jid;
@@ -261,8 +315,9 @@ struct _xmpp_conn_t {
/* stream open handler */
xmpp_open_handler open_handler;
/* user handlers only get called after authentication */
int authenticated;
/* user handlers only get called after the stream negotiation has completed
*/
int stream_negotiation_completed;
/* connection events handler */
xmpp_conn_handler conn_handler;
@@ -273,6 +328,8 @@ struct _xmpp_conn_t {
hash_t *id_handlers;
xmpp_handlist_t *handlers;
xmpp_sockopt_callback sockopt_cb;
xmpp_sm_callback sm_callback;
void *sm_callback_ctx;
};
void conn_disconnect(xmpp_conn_t *conn);
@@ -326,6 +383,8 @@ void handler_add(xmpp_conn_t *conn,
void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */
void trigger_sm_callback(xmpp_conn_t *conn);
void reset_sm_state(xmpp_sm_state_t *sm_state);
void disconnect_mem_error(xmpp_conn_t *conn);
/* auth functions */
@@ -336,6 +395,7 @@ void auth_handle_open_stub(xmpp_conn_t *conn);
/* queue functions */
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);
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, Z_DEFAULT_COMPRESSION);
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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* crypto.c
* strophe XMPP client library -- public interface for digests, encodings
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* ctx.c
** strophe XMPP client library -- run-time context implementation
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -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);
if (ctx != NULL) {
memset(ctx, 0, sizeof(xmpp_ctx_t));
if (mem != NULL)
ctx->mem = mem;
else
@@ -474,12 +477,9 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
else
ctx->log = log;
ctx->connlist = NULL;
ctx->timed_handlers = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
ctx->verbosity = 0;
if (ctx->rand == NULL) {
strophe_free(ctx, ctx);
ctx = NULL;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* deprecated.c
** strophe XMPP client library -- File with deprecated API functions.
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -254,3 +255,22 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
conn->ka_count = 0;
xmpp_conn_set_sockopt_callback(conn, 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
** strophe XMPP client library -- event loop and management
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -38,7 +39,7 @@
#include <sys/select.h>
#include <errno.h>
#include <unistd.h>
#define _sleep(x) usleep((x)*1000)
#define _sleep(x) usleep((x) * 1000)
#else
#include <winsock2.h>
#ifndef ETIMEDOUT
@@ -57,8 +58,22 @@
#include "common.h"
#include "parser.h"
#ifndef STROPHE_MESSAGE_BUFFER_SIZE
/** 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)
{
sock_close(conn->sock);
conn->sock = sock_connect(conn->xsock);
if (conn->sock == INVALID_SOCKET)
return -1;
conn->timeout_stamp = time_stamp();
return 0;
}
/** Run the event loop once.
* This function will run send any data that has been queued by
@@ -77,13 +92,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
{
xmpp_connlist_t *connitem;
xmpp_conn_t *conn;
struct conn_interface *intf;
fd_set rfds, wfds;
sock_t max = 0;
int ret;
struct timeval tv;
xmpp_send_queue_t *sq, *tsq;
int towrite;
char buf[STROPE_MESSAGE_BUFFER_SIZE];
char buf[STROPHE_MESSAGE_BUFFER_SIZE];
uint64_t next;
uint64_t usec;
int tls_read_bytes = 0;
@@ -99,16 +115,18 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
connitem = connitem->next;
continue;
}
intf = &conn->intf;
/* if we're running tls, there may be some remaining data waiting to
* be sent, so push that out */
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 */
strophe_debug(ctx, "xmpp",
"Send error occurred, disconnecting.");
strophe_debug(
ctx, "xmpp",
"Send error of pending data occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
goto next_item;
@@ -120,15 +138,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
while (sq) {
towrite = sq->len - sq->written;
if (conn->tls) {
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();
}
ret = conn_interface_write(intf, &sq->data[sq->written], towrite);
if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */
sq->wip = 1;
@@ -146,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) {
tsq->sm_h = 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);
tsq = NULL;
}
@@ -163,7 +174,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
/* if we've sent everything update the tail */
if (!sq)
conn->send_queue_tail = NULL;
trigger_sm_callback(conn);
}
intf->flush(intf);
/* tear down connection on error */
if (conn->error) {
@@ -198,6 +211,7 @@ next_item:
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
intf = &conn->intf;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
@@ -209,9 +223,14 @@ next_item:
conn->connect_timeout)
FD_SET(conn->sock, &wfds);
else {
conn->error = ETIMEDOUT;
strophe_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn);
ret = _connect_next(conn);
if (ret != 0) {
conn->error = ETIMEDOUT;
conn_disconnect(conn);
} else {
FD_SET(conn->sock, &wfds);
}
}
break;
case XMPP_STATE_CONNECTED:
@@ -227,7 +246,7 @@ next_item:
/* Check if there is something in the SSL buffer. */
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)
max = conn->sock;
@@ -246,9 +265,9 @@ next_item:
/* select errored */
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",
sock_error());
sock_error(NULL));
return;
}
@@ -260,6 +279,7 @@ next_item:
connitem = ctx->connlist;
while (connitem) {
conn = connitem->conn;
intf = &conn->intf;
switch (conn->state) {
case XMPP_STATE_CONNECTING:
@@ -272,7 +292,11 @@ next_item:
/* connection failed */
strophe_debug(ctx, "xmpp", "connection failed, error %d",
ret);
conn_disconnect(conn);
ret = _connect_next(conn);
if (ret != 0) {
conn->error = ret;
conn_disconnect(conn);
}
break;
}
@@ -283,14 +307,9 @@ next_item:
break;
case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) ||
(conn->tls && tls_pending(conn->tls))) {
if (conn->tls) {
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE);
} else {
ret =
sock_read(conn->sock, buf, STROPE_MESSAGE_BUFFER_SIZE);
}
if (FD_ISSET(conn->sock, &rfds) || intf->pending(intf)) {
ret = intf->read(intf, buf, STROPHE_MESSAGE_BUFFER_SIZE);
if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret);
@@ -300,15 +319,13 @@ next_item:
"parse error");
}
} else {
if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) {
strophe_debug(ctx, "xmpp",
"Unrecoverable TLS error, %d.",
tls_error(conn->tls));
conn->error = tls_error(conn->tls);
conn_disconnect(conn);
}
} else {
int err = intf->get_error(intf);
if (!intf->error_is_recoverable(intf, err)) {
strophe_debug(ctx, "xmpp", "Unrecoverable error: %d.",
err);
conn->error = err;
conn_disconnect(conn);
} else if (!conn->tls) {
/* return of 0 means socket closed by server */
strophe_debug(ctx, "xmpp",
"Socket closed by remote host.");

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* handler.c
** strophe XMPP client library -- event handler management
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -24,8 +25,6 @@
#include "common.h"
#include "ostypes.h"
typedef int (*xmpp_void_handler)();
/* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
@@ -80,9 +79,9 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
item = head;
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 */
if ((item->user_handler && !conn->authenticated) ||
if ((item->user_handler && !conn->stream_negotiation_completed) ||
!item->enabled) {
item = item->next;
continue;
@@ -116,9 +115,10 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
item = conn->handlers;
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 */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
if ((item->user_handler && !conn->stream_negotiation_completed) ||
!item->enabled) {
item = item->next;
continue;
}
@@ -174,9 +174,9 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
item = conn->timed_handlers;
while (item) {
/* don't fire user handlers until authentication succeeds and
skip newly added handlers */
if ((item->user_handler && !conn->authenticated) ||
/* don't fire user handlers until stream negotiation has completed
and skip newly added handlers */
if ((item->user_handler && !conn->stream_negotiation_completed) ||
!item->enabled) {
item = item->next;
continue;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* hash.c
** strophe XMPP client library -- hash table implementation
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* hash.h
** strophe XMPP client library -- hash table interface
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* jid.c
** strophe XMPP client library -- helper functions for parsing JIDs
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -37,8 +38,10 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
size_t len, nlen, dlen, rlen;
/* jid must at least have a domain */
if (domain == NULL)
if (domain == NULL) {
strophe_error(ctx, "jid", "domainpart missing.");
return NULL;
}
/* accumulate lengths */
dlen = strlen(domain);
@@ -46,6 +49,26 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
rlen = (resource) ? strlen(resource) + 1 : 0;
len = nlen + dlen + rlen;
if (dlen > 1023) {
strophe_error(ctx, "jid", "domainpart too long.");
return NULL;
}
if (nlen > 1024) {
strophe_error(ctx, "jid", "localpart too long.");
return NULL;
}
if (rlen > 1024) {
strophe_error(ctx, "jid", "resourcepart too long.");
return NULL;
}
if (node) {
if (strcspn(node, "\"&'/:<>@") != nlen - 1) {
strophe_error(ctx, "jid", "localpart contained invalid character.");
return NULL;
}
}
/* concat components */
result = strophe_alloc(ctx, len + 1);
if (result != NULL) {
@@ -96,17 +119,29 @@ char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
*/
char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
{
char *dup_jid = strophe_strdup(ctx, jid);
char *result = NULL;
const char *c;
c = strchr(jid, '@');
/* Apply the same parsing rules from rfc7622 Section 3.2
* 1. Strip resource
* 2. take part before the '@'
*/
char *resource = strchr(dup_jid, '/');
if (resource != NULL) {
*resource = '\0';
}
c = strchr(dup_jid, '@');
if (c != NULL) {
result = strophe_alloc(ctx, (c - jid) + 1);
result = strophe_alloc(ctx, (c - dup_jid) + 1);
if (result != NULL) {
memcpy(result, jid, (c - jid));
result[c - jid] = '\0';
memcpy(result, dup_jid, (c - dup_jid));
result[c - dup_jid] = '\0';
}
}
strophe_free(ctx, dup_jid);
return result;
}
@@ -120,24 +155,29 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
*/
char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
{
char *result = NULL;
const char *c;
size_t dlen;
char *dup_jid = strophe_strdup(ctx, jid);
c = strchr(jid, '@');
if (c == NULL) {
/* no node, assume domain */
c = jid;
/* rfc7622 Section 3.2
* 1. Remove any portion from the first '/' character to the end of the
* string (if there is a '/' character present).
*/
char *resource = strchr(dup_jid, '/');
if (resource != NULL) {
*resource = '\0';
}
/* 2. Remove any portion from the beginning of the string to the first
* '@' character (if there is an '@' character present).
*/
char *at_sign = strchr(dup_jid, '@');
char *result = NULL;
if (at_sign != NULL) {
result = strophe_strdup(ctx, (at_sign + 1));
} else {
/* advance past the separator */
c++;
}
dlen = strcspn(c, "/"); /* do not include resource */
result = strophe_alloc(ctx, dlen + 1);
if (result != NULL) {
memcpy(result, c, dlen);
result[dlen] = '\0';
result = strophe_strdup(ctx, dup_jid);
}
strophe_free(ctx, dup_jid);
return result;
}

View File

@@ -37,7 +37,7 @@
#define PUT_32BIT_LSB_FIRST(cp, value) \
do { \
(cp)[0] = (value)&0xFF; \
(cp)[0] = (value) & 0xFF; \
(cp)[1] = ((value) >> 8) & 0xFF; \
(cp)[2] = ((value) >> 16) & 0xFF; \
(cp)[3] = ((value) >> 24) & 0xFF; \

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* ostypes.h
** strophe XMPP client library -- type definitions for platforms
** without stdint.h
@@ -7,7 +8,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* parser.h
** strophe XMPP client library -- parser structures and functions
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* parser.c
** 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
** 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
@@ -152,8 +153,7 @@ static void complete_inner_text(parser_t *parser)
/* FIXME: disconnect on allocation error */
if (stanza) {
xmpp_stanza_set_text(stanza, parser->inner_text);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
xmpp_stanza_add_child_ex(parser->stanza, stanza, 0);
}
strophe_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
@@ -195,8 +195,7 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
if (parser->stanza != NULL) {
complete_inner_text(parser);
xmpp_stanza_add_child(parser->stanza, child);
xmpp_stanza_release(child);
xmpp_stanza_add_child_ex(parser->stanza, child, 0);
}
parser->stanza = child;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* parser.c
** 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
** 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
@@ -164,10 +165,7 @@ static void _start_element(void *userdata,
xmpp_stanza_set_ns(child, (char *)uri);
/* add child to parent */
xmpp_stanza_add_child(parser->stanza, child);
/* the child is owned by the toplevel stanza now */
xmpp_stanza_release(child);
xmpp_stanza_add_child_ex(parser->stanza, child, 0);
/* make child the current stanza */
parser->stanza = child;
@@ -223,8 +221,7 @@ static void _characters(void *userdata, const xmlChar *chr, int len)
}
xmpp_stanza_set_text_with_size(stanza, (char *)chr, len);
xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza);
xmpp_stanza_add_child_ex(parser->stanza, stanza, 0);
}
/* create a new parser */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* rand.c
* strophe XMPP client library -- pseudo-random number generator
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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
@@ -67,9 +68,9 @@ struct _xmpp_rand_t {
};
/* returns smallest number mupliple of y that not less than x */
#define round_up(x, y) (((x) + (y)-1) / (y) * (y))
#define round_up(x, y) (((x) + (y) - 1) / (y) * (y))
/* returns smallest integer number that not less than x/y */
#define div_round_up(x, y) (((x) + (y)-1) / (y))
#define div_round_up(x, y) (((x) + (y) - 1) / (y))
/* adds two arrays as numbers in big-endian representation and stores
* result in the first one.

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* resolver.c
* strophe XMPP client library -- DNS resolver
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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
@@ -91,6 +92,25 @@ void resolver_shutdown(void)
#endif
}
resolver_srv_rr_t *resolver_srv_rr_new(xmpp_ctx_t *ctx,
const char *host,
unsigned short port,
unsigned short prio,
unsigned short weight)
{
resolver_srv_rr_t *rr = strophe_alloc(ctx, sizeof(*rr));
if (rr) {
memset(rr, 0, sizeof(*rr));
rr->port = port;
rr->priority = prio;
rr->weight = weight;
if (host) {
snprintf(rr->target, sizeof(rr->target), "%s", host);
}
}
return rr;
}
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t *rr_head;
@@ -158,6 +178,10 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx,
set = resolver_ares_srv_lookup_buf(ctx, buf, len, srv_rr_list);
#else
set = resolver_raw_srv_lookup_buf(ctx, buf, len, srv_rr_list);
if (set != XMPP_DOMAIN_FOUND && *srv_rr_list != NULL) {
resolver_srv_free(ctx, *srv_rr_list);
*srv_rr_list = NULL;
}
#endif
resolver_srv_list_sort(srv_rr_list);
@@ -434,17 +458,19 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
j += 10;
if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
rr = strophe_alloc(ctx, sizeof(*rr));
rr->next = *srv_rr_list;
rr->priority = xmpp_ntohs_ptr(&buf[j]);
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
name_len = message_name_get(buf, len, j + 6, rr->target,
sizeof(rr->target));
if (name_len > 0)
*srv_rr_list = rr;
else
strophe_free(ctx, rr); /* skip broken record */
rr = resolver_srv_rr_new(ctx, NULL, 0, 0, 0);
if (rr) {
rr->next = *srv_rr_list;
rr->priority = xmpp_ntohs_ptr(&buf[j]);
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
rr->port = xmpp_ntohs_ptr(&buf[j + 4]);
name_len = message_name_get(buf, len, j + 6, rr->target,
sizeof(rr->target));
if (name_len > 0)
*srv_rr_list = rr;
else
strophe_free(ctx, rr); /* skip broken record */
}
}
j += rdlength;
}
@@ -604,7 +630,7 @@ static void netbuf_add_16bitnum(unsigned char *buf,
/* assuming big endian */
*p++ = (num >> 8) & 0xff;
*p++ = (num)&0xff;
*p++ = (num) & 0xff;
*offset += 2;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* resolver.h
* strophe XMPP client library -- DNS resolver
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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
@@ -36,6 +37,12 @@ typedef struct resolver_srv_rr_struc {
void resolver_initialize(void);
void resolver_shutdown(void);
resolver_srv_rr_t *resolver_srv_rr_new(xmpp_ctx_t *ctx,
const char *host,
unsigned short port,
unsigned short prio,
unsigned short weight);
/** Perform lookup for RFC1035 message format.
* This function allocates all elements.
*

View File

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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* sasl.h
** strophe XMPP client library -- SASL authentication helpers
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -28,6 +29,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
const char *password);
char *sasl_scram(xmpp_ctx_t *ctx,
const struct hash_alg *alg,
const char *channel_binding,
const char *challenge,
const char *first_bare,
const char *jid,

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* scram.c
* strophe XMPP client library
*
@@ -9,7 +10,7 @@
* This software is provided AS-IS with no warranty, either express
* 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
@@ -41,6 +42,15 @@ const struct hash_alg scram_sha1 = {
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
(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 = {
"SCRAM-SHA-256",
SASL_MASK_SCRAMSHA256,
@@ -50,6 +60,15 @@ const struct hash_alg scram_sha256 = {
(void (*)(void *, const uint8_t *, size_t))sha256_process,
(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 = {
"SCRAM-SHA-512",
SASL_MASK_SCRAMSHA512,
@@ -59,6 +78,43 @@ const struct hash_alg scram_sha512 = {
(void (*)(void *, const uint8_t *, size_t))sha512_process,
(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 {
SHA1_CTX sha1;
sha256_context sha256;

View File

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

View File

@@ -53,7 +53,7 @@ extern "C" {
(y)[0] = (uint8_t)(((x) >> 24) & 255); \
(y)[1] = (uint8_t)(((x) >> 16) & 255); \
(y)[2] = (uint8_t)(((x) >> 8) & 255); \
(y)[3] = (uint8_t)((x)&255); \
(y)[3] = (uint8_t)((x) & 255); \
} while (0)
#define LOAD32H(x, y) \
@@ -72,7 +72,7 @@ extern "C" {
(y)[4] = (uint8_t)(((x) >> 24) & 255); \
(y)[5] = (uint8_t)(((x) >> 16) & 255); \
(y)[6] = (uint8_t)(((x) >> 8) & 255); \
(y)[7] = (uint8_t)((x)&255); \
(y)[7] = (uint8_t)((x) & 255); \
} while (0)
#define LOAD64H(x, y) \
@@ -96,13 +96,13 @@ extern "C" {
#define CONST64(n) n##ULL
#endif
#define RORc(x, y) \
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
#define RORc(x, y) \
(((((uint32_t)(x) & 0xFFFFFFFFUL) >> (uint32_t)((y) & 31)) | \
((uint32_t)(x) << (uint32_t)((32 - ((y) & 31)) & 31))) & \
0xFFFFFFFFUL)
#define ROR64c(x, y) \
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
#define ROR64c(x, y) \
(((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y) & CONST64(63))) | \
((x) << (((uint64_t)64 - ((y) & 63)) & 63))) & \
CONST64(0xFFFFFFFFFFFFFFFF))
#ifdef __cplusplus

View File

@@ -9,7 +9,7 @@
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
#define R(x, n) (((x) & 0xFFFFFFFFUL) >> (n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))

View File

@@ -52,7 +52,7 @@ static const uint64_t K[80] = {
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
#define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* sock.c
** strophe XMPP client library -- socket abstraction implementation
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -24,6 +25,7 @@
#include <iphlpapi.h>
#include <mstcpip.h> /* tcp_keepalive */
#else
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
@@ -34,6 +36,30 @@
#endif
#include "common.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 {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
struct addrinfo *ainfo_list;
struct addrinfo *ainfo_cur;
resolver_srv_rr_t *srv_rr_list;
resolver_srv_rr_t *srv_rr_cur;
const char *host;
unsigned short port;
};
void sock_initialize(void)
{
@@ -50,8 +76,9 @@ void sock_shutdown(void)
#endif
}
int sock_error(void)
int sock_error(struct conn_interface *intf)
{
UNUSED(intf);
#ifdef _WIN32
return WSAGetLastError();
#else
@@ -68,50 +95,166 @@ static int _in_progress(int error)
#endif
}
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port)
static void sock_getaddrinfo(xmpp_sock_t *xsock)
{
sock_t sock;
char service[6];
struct addrinfo *res, *ainfo, hints;
int err;
struct addrinfo hints;
int rc;
strophe_snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif /* AI_ADDRCONFIG */
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(host, service, &hints, &res);
if (err != 0)
return -1;
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock < 0)
continue;
if (conn->sockopt_cb != NULL)
err = (conn->sockopt_cb)(conn, &sock);
if (err != 0) {
sock_close(sock);
continue;
}
err = sock_set_nonblocking(sock);
if (err == 0) {
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
if (err == 0 || _in_progress(sock_error()))
break;
}
sock_close(sock);
if (xsock->ainfo_list) {
freeaddrinfo(xsock->ainfo_list);
xsock->ainfo_list = NULL;
}
freeaddrinfo(res);
sock = ainfo == NULL ? -1 : sock;
if (xsock->srv_rr_cur) {
/* Cache host and port for debug logs. */
xsock->host = xsock->srv_rr_cur->target;
xsock->port = xsock->srv_rr_cur->port;
strophe_snprintf(service, 6, "%u", xsock->srv_rr_cur->port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
#ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
#endif /* AI_ADDRCONFIG */
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints,
&xsock->ainfo_list);
if (rc != 0) {
strophe_debug(xsock->ctx, "sock",
"getaddrinfo() failed with %s (%d)", gai_strerror(rc),
rc);
xsock->ainfo_list = NULL;
}
}
xsock->ainfo_cur = xsock->ainfo_list;
}
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
const char *domain,
const char *host,
unsigned short port)
{
xmpp_ctx_t *ctx = conn->ctx;
xmpp_sock_t *xsock;
int found = XMPP_DOMAIN_NOT_FOUND;
xsock = strophe_alloc(ctx, sizeof(*xsock));
if (!xsock) {
return NULL;
}
xsock->ctx = ctx;
xsock->conn = conn;
xsock->host = NULL;
xsock->port = 0;
if (!host) {
found = resolver_srv_lookup(ctx, "xmpp-client", "tcp", domain,
&xsock->srv_rr_list);
if (XMPP_DOMAIN_NOT_FOUND == found)
strophe_debug(ctx, "sock",
"SRV lookup failed, connecting via domain.");
}
if (XMPP_DOMAIN_NOT_FOUND == found) {
/* Resolution failed or the host is provided explicitly. */
xsock->srv_rr_list =
resolver_srv_rr_new(ctx, host ? host : domain, port, 0, 0);
}
xsock->srv_rr_cur = xsock->srv_rr_list;
xsock->ainfo_list = NULL;
sock_getaddrinfo(xsock);
if (xsock->srv_rr_cur)
xsock->srv_rr_cur = xsock->srv_rr_cur->next;
return xsock;
}
void sock_free(xmpp_sock_t *xsock)
{
if (!xsock)
return;
if (xsock->ainfo_list)
freeaddrinfo(xsock->ainfo_list);
if (xsock->srv_rr_list)
resolver_srv_free(xsock->ctx, xsock->srv_rr_list);
strophe_free(xsock->ctx, xsock);
}
static const char *_sockaddr2str(struct sockaddr *sa, char *buf, size_t buflen)
{
buf[0] = '\0';
switch (sa->sa_family) {
case AF_INET:
inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, buf, buflen);
break;
case AF_INET6:
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, buf,
buflen);
break;
default:
strophe_snprintf(buf, buflen, "<Unknown>");
}
return buf;
}
sock_t sock_connect(xmpp_sock_t *xsock)
{
struct addrinfo *ainfo;
sock_t sock;
int rc;
char buf[64];
do {
if (!xsock->ainfo_cur) {
sock_getaddrinfo(xsock);
if (xsock->srv_rr_cur)
xsock->srv_rr_cur = xsock->srv_rr_cur->next;
}
if (!xsock->ainfo_cur) {
/* We tried all available addresses. */
return INVALID_SOCKET;
}
ainfo = xsock->ainfo_cur;
strophe_debug(xsock->ctx, "sock", "Connecting to %s:%u via %s",
xsock->host, xsock->port,
_sockaddr2str(ainfo->ai_addr, buf, sizeof(buf)));
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock != INVALID_SOCKET) {
rc = 0;
if (xsock->conn->sockopt_cb) {
/* Don't allow user to overwrite sockfd value. */
sock_t sock_copy = sock;
rc = xsock->conn->sockopt_cb(xsock->conn, &sock_copy);
if (rc != 0) {
strophe_debug(xsock->ctx, "sock",
"User's setsockopt callback"
" failed with %d (errno=%d)",
rc, errno);
}
}
if (rc == 0)
rc = sock_set_nonblocking(sock);
if (rc == 0)
rc = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
/* Assume only connect() can cause "in progress" error. */
if (rc != 0 && !_in_progress(sock_error(NULL))) {
sock_close(sock);
sock = INVALID_SOCKET;
}
}
strophe_debug(xsock->ctx, "sock", "sock_connect() result %d", sock);
xsock->ainfo_cur = xsock->ainfo_cur->ai_next;
} while (sock == INVALID_SOCKET);
return sock;
}
@@ -248,18 +391,19 @@ int sock_set_nonblocking(sock_t sock)
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
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
error == WSAEINPROGRESS);
@@ -288,15 +432,15 @@ int sock_connect_error(sock_t sock)
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
* return that */
#ifdef _WIN32
if (sock_error() != WSAENOTCONN)
return sock_error();
if (sock_error(NULL) != WSAENOTCONN)
return sock_error(NULL);
#else
if (sock_error() != ENOTCONN)
return sock_error();
if (sock_error(NULL) != ENOTCONN)
return sock_error(NULL);
#endif
/* load the correct error into errno through error slippage */
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
** strophe XMPP client library -- socket abstraction header
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -20,6 +21,7 @@
#ifndef _WIN32
typedef int sock_t;
#define INVALID_SOCKET (-1)
#else
#include <winsock2.h>
#include <ws2tcpip.h>
@@ -28,19 +30,28 @@ typedef int sock_t;
typedef SOCKET sock_t;
#endif
extern const struct conn_interface sock_intf;
typedef struct _xmpp_sock_t xmpp_sock_t;
void sock_initialize(void);
void sock_shutdown(void);
int sock_error(void);
int sock_error(struct conn_interface *intf);
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port);
xmpp_sock_t *sock_new(xmpp_conn_t *conn,
const char *domain,
const char *host,
unsigned short port);
void sock_free(xmpp_sock_t *xsock);
sock_t sock_connect(xmpp_sock_t *xsock);
int sock_close(sock_t sock);
int sock_set_blocking(sock_t sock);
int sock_set_nonblocking(sock_t sock);
int sock_read(sock_t sock, void *buff, size_t len);
int sock_write(sock_t sock, const void *buff, size_t len);
int sock_is_recoverable(int error);
int sock_read(struct conn_interface *intf, void *buff, size_t len);
int sock_write(struct conn_interface *intf, const void *buff, size_t len);
int sock_is_recoverable(struct conn_interface *intf, int error);
/* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(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
** strophe XMPP client library -- XMPP stanza object and utilities
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -41,15 +42,10 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t));
if (stanza != NULL) {
memset(stanza, 0, sizeof(xmpp_stanza_t));
stanza->ref = 1;
stanza->ctx = ctx;
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;
@@ -182,6 +178,7 @@ int xmpp_stanza_release(xmpp_stanza_t *stanza)
while (child) {
tchild = child;
child = child->next;
tchild->next = NULL;
xmpp_stanza_release(tchild);
}
@@ -1604,8 +1601,7 @@ xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *text)
}
xmpp_stanza_set_ns(error_type, XMPP_NS_STREAMS_IETF);
xmpp_stanza_add_child(error, error_type);
xmpp_stanza_release(error_type);
xmpp_stanza_add_child_ex(error, error_type, 0);
if (text) {
xmpp_stanza_t *error_text = xmpp_stanza_new(ctx);
@@ -1615,11 +1611,9 @@ xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *text)
xmpp_stanza_set_ns(error_text, XMPP_NS_STREAMS_IETF);
xmpp_stanza_set_text(content, text);
xmpp_stanza_add_child(error_text, content);
xmpp_stanza_release(content);
xmpp_stanza_add_child_ex(error_text, content, 0);
xmpp_stanza_add_child(error, error_text);
xmpp_stanza_release(error_text);
xmpp_stanza_add_child_ex(error, error_text, 0);
}
return error;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls.c
** strophe XMPP client library -- generic TLS functions
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -29,6 +30,17 @@
#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 {
char **data;
size_t cur, max;

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls.h
** strophe XMPP client library -- TLS abstraction header
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -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);
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_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_read(tls_t *tls, void *buff, size_t len);
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);
int tls_error(struct conn_interface *intf);
int tls_is_recoverable(struct conn_interface *intf, int error);
/* provided by tls.c */
extern const struct conn_interface tls_intf;
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
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
** strophe XMPP client library -- TLS abstraction dummy impl.
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -74,6 +75,23 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
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)
{
UNUSED(tls);
@@ -86,43 +104,43 @@ int tls_stop(tls_t *tls)
return -1;
}
int tls_error(tls_t *tls)
int tls_error(struct conn_interface *intf)
{
UNUSED(tls);
/* todo: some kind of error polling/dump */
UNUSED(intf);
return 0;
}
int tls_pending(tls_t *tls)
int tls_pending(struct conn_interface *intf)
{
UNUSED(tls);
UNUSED(intf);
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(len);
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(len);
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;
}
int tls_is_recoverable(int error)
int tls_is_recoverable(struct conn_interface *intf, int error)
{
UNUSED(intf);
UNUSED(error);
return 0;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls.c
** strophe XMPP client library -- TLS abstraction header
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -24,12 +25,26 @@
#include "tls.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 {
xmpp_ctx_t *ctx; /* do we need this? */
xmpp_conn_t *conn;
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
gnutls_x509_crt_t client_cert;
gnutls_datum_t channel_binding;
int lasterror;
};
@@ -506,8 +521,8 @@ error_out:
void tls_free(tls_t *tls)
{
if (tls->client_cert)
gnutls_x509_crt_deinit(tls->client_cert);
gnutls_free(tls->channel_binding.data);
gnutls_x509_crt_deinit(tls->client_cert);
gnutls_deinit(tls->session);
gnutls_certificate_free_credentials(tls->cred);
strophe_free(tls->ctx, tls);
@@ -554,6 +569,55 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
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)
{
sock_set_blocking(tls->conn->sock);
@@ -569,24 +633,26 @@ int tls_stop(tls_t *tls)
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);
}
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;
tls_t *tls = intf->conn->tls;
ret = gnutls_record_recv(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
@@ -594,9 +660,10 @@ int tls_read(tls_t *tls, void *buff, size_t len)
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;
tls_t *tls = intf->conn->tls;
ret = gnutls_record_send(tls->session, buff, len);
tls->lasterror = ret < 0 ? ret : 0;
@@ -604,8 +671,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
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;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls_openssl.c
** strophe XMPP client library -- TLS abstraction openssl impl.
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -50,8 +51,10 @@
#if OPENSSL_VERSION_NUMBER < 0x30000000L
#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
#define STROPHE_ERR_func_error_string(e) ""
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get1_peer_certificate(s)
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -106,6 +109,9 @@ struct _tls {
SSL_CTX *ssl_ctx;
SSL *ssl;
X509 *client_cert;
void *channel_binding_data;
size_t channel_binding_size;
FILE *keylogfile;
int lasterror;
};
@@ -280,9 +286,9 @@ void tls_shutdown(void)
#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
@@ -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);
#else
const X509_ALGOR *palg;
const ASN1_OBJECT *obj;
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
} break;
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);
}
#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 = 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);
if (ret <= 0)
goto err_free_ssl;
_try_open_keylogfile(tls);
}
return tls;
@@ -712,6 +752,9 @@ err:
void tls_free(tls_t *tls)
{
if (tls->keylogfile)
fclose(tls->keylogfile);
strophe_free(tls->ctx, tls->channel_binding_data);
SSL_free(tls->ssl);
X509_free(tls->client_cert);
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)
{
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) {
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
X509_free(cert);
@@ -738,6 +781,83 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
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 error;
@@ -750,7 +870,7 @@ int tls_start(tls_t *tls)
ret = SSL_connect(tls->ssl);
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 */
_tls_sock_wait(tls, error);
continue;
@@ -791,7 +911,7 @@ int tls_stop(tls_t *tls)
++retries;
ret = SSL_shutdown(tls->ssl);
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) {
break;
}
@@ -810,21 +930,23 @@ int tls_stop(tls_t *tls)
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 ||
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
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;
tls_t *tls = intf->conn->tls;
ret = SSL_read(tls->ssl, buff, len);
_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;
}
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;
tls_t *tls = intf->conn->tls;
ret = SSL_write(tls->ssl, buff, len);
_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;
}
int tls_clear_pending_write(tls_t *tls)
int tls_clear_pending_write(struct conn_interface *intf)
{
UNUSED(tls);
UNUSED(intf);
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)
{
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",
TLS_ERROR_STR(error, tls_errors), error, errno,
tls->lasterror);
@@ -913,7 +1036,7 @@ static void _tls_dump_cert_info(tls_t *tls)
X509 *cert;
char *name;
cert = SSL_get_peer_certificate(tls->ssl);
cert = STROPHE_SSL_get1_peer_certificate(tls->ssl);
if (cert == NULL)
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else {

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* tls_schannel.c
** strophe XMPP client library -- TLS abstraction schannel impl.
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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
@@ -236,6 +237,23 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
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)
{
ULONG ctxtreq = 0, ctxtattr = 0;
@@ -244,9 +262,11 @@ int tls_start(tls_t *tls)
SECURITY_STATUS ret;
int sent;
char *name;
struct conn_interface *intf;
/* use the domain there as our name */
name = tls->conn->domain;
intf = tls->conn->intf;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
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 int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen);
sent = sock_write(intf, writebuff, writelen);
if (sent == -1) {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
} else {
writebuff += sent;
writelen -= sent;
@@ -335,13 +355,13 @@ int tls_start(tls_t *tls)
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) {
len += inbytes;
p += inbytes;
} 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) {
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;
unsigned int writelen = sbdout.pBuffers[0].cbBuffer;
sent = sock_write(tls->sock, writebuff, writelen);
sent = sock_write(intf, writebuff, writelen);
if (sent == -1) {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
} else {
writebuff += sent;
writelen -= sent;
@@ -405,20 +425,22 @@ int tls_stop(tls_t *tls)
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 ||
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
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 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
@@ -434,9 +456,10 @@ int tls_pending(tls_t *tls)
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;
tls_t *tls = intf->conn->tls;
/* first, if we've got some ready data, put that in the buffer */
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);
if (read == -1) {
if (tls_is_recoverable(tls->lasterror)) {
if (tls_is_recoverable(intf, tls->lasterror)) {
return bytes;
}
@@ -471,7 +494,7 @@ int tls_read(tls_t *tls, void *buff, size_t len)
}
/* 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);
if (bytes == 0) {
@@ -480,8 +503,8 @@ int tls_read(tls_t *tls, void *buff, size_t len)
}
if (bytes == -1) {
if (!tls_is_recoverable(sock_error())) {
tls->lasterror = sock_error();
if (!tls_is_recoverable(intf, sock_error(intf))) {
tls->lasterror = sock_error(intf);
return -1;
}
}
@@ -556,16 +579,17 @@ int tls_read(tls_t *tls, void *buff, size_t len)
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) {
int bytes;
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
bytes = sock_write(intf, tls->sendbuffer + tls->sendbufferpos,
tls->sendbufferlen - tls->sendbufferpos);
if (bytes == -1) {
tls->lasterror = sock_error();
tls->lasterror = sock_error(intf);
return -1;
} else if (bytes > 0) {
tls->sendbufferpos += bytes;
@@ -579,12 +603,13 @@ int tls_clear_pending_write(tls_t *tls)
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;
SecBuffer sbenc[4];
const unsigned char *p = buff;
int sent = 0, ret, remain = len;
tls_t *tls = intf->conn->tls;
ret = tls_clear_pending_write(tls);
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);
if (ret == -1 && !tls_is_recoverable(tls_error(tls))) {
if (ret == -1 && !tls_is_recoverable(intf, tls_error(tls))) {
return -1;
}
@@ -656,7 +681,8 @@ int tls_write(tls_t *tls, const void *buff, size_t len)
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;
}
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* util.c
** strophe XMPP client library -- various utility functions
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* util.h
** strophe XMPP client library -- various utility functions
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express
** 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* uuid.c
* strophe XMPP client library -- UUID generation
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* strophe.h
** strophe XMPP client library C API
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express or
** implied.
**
** This software is dual licensed under the MIT and GPLv3 licenses.
** This software is dual licensed under the MIT or GPLv3 licenses.
*/
/** @file
@@ -17,6 +18,7 @@
#define __LIBSTROPHE_STROPHE_H__
#include <stddef.h> /* size_t */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -83,6 +85,14 @@ extern "C" {
* Namespace definition for Stream Management.
*/
#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 */
/** @def XMPP_EOK
@@ -190,6 +200,15 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
* Disable Stream-Management XEP-0198.
*/
#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 */
typedef enum {
@@ -381,7 +400,6 @@ char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
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);
void xmpp_conn_disable_tls(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);
@@ -397,8 +415,38 @@ typedef enum {
char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
xmpp_queue_element_t which);
xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn);
int xmpp_conn_set_sm_state(xmpp_conn_t *conn, xmpp_sm_state_t *sm_state);
xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn);
/** The function which will be called when Strophe updates its internal SM
* state.
*
* Please note that you have to create a copy of the buffer, since the library
* will free the buffer right after return of the callback function.
*
*
* @param conn The Strophe connection object this callback
* originates from.
* @param ctx The `ctx` pointer as passed to
* \ref xmpp_conn_set_sm_callback
* @param sm_state A pointer to a buffer containing the serialized SM
* state.
* @param sm_state_len The length of `sm_state`.
*
* @return 0 on success, -1 on error
*
* @ingroup Connections
*/
typedef void (*xmpp_sm_callback)(xmpp_conn_t *conn,
void *ctx,
const unsigned char *sm_state,
size_t sm_state_len);
void xmpp_conn_set_sm_callback(xmpp_conn_t *conn,
xmpp_sm_callback cb,
void *ctx);
int xmpp_conn_restore_sm_state(xmpp_conn_t *conn,
const unsigned char *sm_state,
size_t sm_state_len);
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state);
@@ -690,11 +738,18 @@ 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);
/**
/*
* Formerly "private but exported" functions made public for now to announce
* deprecation */
#include <stdarg.h>
/**
* 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 (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
#define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
@@ -742,6 +797,8 @@ void xmpp_debug_verbose(
XMPP_DEPRECATED(xmpp_conn_set_sockopt_callback)
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);
#ifdef __cplusplus
}

View File

@@ -1,6 +1,7 @@
#!/bin/sh
logfile="../../testbuild.log"
errfile="../../testerr.log"
err_out() {
tail $logfile
@@ -8,6 +9,6 @@ err_out() {
}
./bootstrap.sh
./configure >> $logfile || err_out
make -j$(( `nproc` * 2 + 1 )) >> $logfile || err_out
make check >> $logfile || err_out
./configure >> $logfile 2>> $errfile || err_out
make -j$(( `nproc` * 2 + 1 )) >> $logfile 2>> $errfile || err_out
make check >> $logfile 2>> $errfile || err_out

Binary file not shown.

Binary file not shown.

View File

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

Binary file not shown.

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* check_parser.h
** strophe XMPP client library -- parser tests
**
@@ -6,7 +7,7 @@
** This software is provided AS-IS with no warranty, either express 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>

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* res_query_dump.c
* Simple program to dump res_query(3) response
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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:

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test.c
* strophe XMPP client library -- common routines for tests
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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>

View File

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

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_ctx.c
** libstrophe XMPP client library -- test routines for the library run-time
*context
@@ -7,7 +8,7 @@
** This software is provided AS-IS with no warranty, either express
** 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_hash.c
** 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
** 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_jid.c
** 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
** 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>
@@ -15,114 +16,80 @@
#include "strophe.h"
#include "common.h"
static const char jid1[] = "foo@bar.com";
static const char jid2[] = "anyone@example.com/hullo";
static const char jid3[] = "manic.porter@xyz.net/frob";
static const char jid4[] = "domain.tld";
#include "test.h"
static const char *_s(const char *s)
{
return s == NULL ? "<NULL>" : s;
}
int test_jid(xmpp_ctx_t *ctx)
static int test_jid(xmpp_ctx_t *ctx)
{
char *bare;
char *node;
char *domain;
char *resource;
size_t n;
struct {
const char *jid;
const char *bare;
const char *node;
const char *domain;
const char *resource;
} testcases[] = {
{"foo@bar.com", "foo@bar.com", "foo", "bar.com", NULL},
{
"anyone@example.com/hullo",
"anyone@example.com",
"anyone",
"example.com",
"hullo",
},
{
"a.example.com/b@example.net",
"a.example.com",
NULL,
"a.example.com",
"b@example.net",
},
{
"manic.porter@xyz.net/frob",
"manic.porter@xyz.net",
"manic.porter",
"xyz.net",
"frob",
},
{
"domain.tld",
"domain.tld",
NULL,
"domain.tld",
NULL,
},
};
bare = xmpp_jid_bare(ctx, jid1);
node = xmpp_jid_node(ctx, jid1);
domain = xmpp_jid_domain(ctx, jid1);
resource = xmpp_jid_resource(ctx, jid1);
printf("jid '%s' parsed to %s, %s, %s\n", jid1, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "foo@bar.com"))
return 1;
if (node == NULL || strcmp(node, "foo"))
return 1;
if (domain == NULL || strcmp(domain, "bar.com"))
return 1;
if (resource != NULL)
return 1;
if (bare)
strophe_free(ctx, bare);
if (node)
strophe_free(ctx, node);
if (domain)
strophe_free(ctx, domain);
if (resource)
strophe_free(ctx, resource);
for (n = 0; n < sizeof(testcases) / sizeof(testcases[0]); ++n) {
bare = xmpp_jid_bare(ctx, testcases[n].jid);
node = xmpp_jid_node(ctx, testcases[n].jid);
domain = xmpp_jid_domain(ctx, testcases[n].jid);
resource = xmpp_jid_resource(ctx, testcases[n].jid);
printf("jid '%s' parsed to %s, %s, %s\n", testcases[n].jid, _s(node),
_s(domain), _s(resource));
COMPARE(testcases[n].bare, bare);
COMPARE(testcases[n].node, node);
COMPARE(testcases[n].domain, domain);
COMPARE(testcases[n].resource, resource);
if (bare)
strophe_free(ctx, bare);
if (node)
strophe_free(ctx, node);
if (domain)
strophe_free(ctx, domain);
if (resource)
strophe_free(ctx, resource);
}
bare = xmpp_jid_bare(ctx, jid2);
node = xmpp_jid_node(ctx, jid2);
domain = xmpp_jid_domain(ctx, jid2);
resource = xmpp_jid_resource(ctx, jid2);
printf("jid '%s' parsed to %s, %s, %s\n", jid2, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "anyone@example.com"))
return 1;
if (node == NULL || strcmp(node, "anyone"))
return 1;
if (domain == NULL || strcmp(domain, "example.com"))
return 1;
if (resource == NULL || strcmp(resource, "hullo"))
return 1;
if (bare)
strophe_free(ctx, bare);
if (node)
strophe_free(ctx, node);
if (domain)
strophe_free(ctx, domain);
if (resource)
strophe_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3);
node = xmpp_jid_node(ctx, jid3);
domain = xmpp_jid_domain(ctx, jid3);
resource = xmpp_jid_resource(ctx, jid3);
printf("jid '%s' parsed to %s, %s, %s\n", jid3, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net"))
return 1;
if (node == NULL || strcmp(node, "manic.porter"))
return 1;
if (domain == NULL || strcmp(domain, "xyz.net"))
return 1;
if (resource == NULL || strcmp(resource, "frob"))
return 1;
if (bare)
strophe_free(ctx, bare);
if (node)
strophe_free(ctx, node);
if (domain)
strophe_free(ctx, domain);
if (resource)
strophe_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4);
node = xmpp_jid_node(ctx, jid4);
domain = xmpp_jid_domain(ctx, jid4);
resource = xmpp_jid_resource(ctx, jid4);
printf("jid '%s' parsed to %s, %s, %s\n", jid4, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "domain.tld"))
return 1;
if (node != NULL)
return 1;
if (domain == NULL || strcmp(domain, "domain.tld"))
return 1;
if (resource != NULL)
return 1;
if (bare)
strophe_free(ctx, bare);
if (node)
strophe_free(ctx, node);
if (domain)
strophe_free(ctx, domain);
if (resource)
strophe_free(ctx, resource);
printf("test_jid() finished successfully\n");
return 0;
}
@@ -143,6 +110,19 @@ int test_jid_new(xmpp_ctx_t *ctx)
return 1;
strophe_free(ctx, jid);
const char *invalid_chars = "\"&'/:<>@";
char localpart[] = "localpart";
do {
localpart[1] = *invalid_chars;
jid = xmpp_jid_new(ctx, localpart, "bar.com", NULL);
if (jid != NULL) {
printf("Shouldn't have created JID with localpart=\"%s\"\n",
localpart);
return 1;
}
invalid_chars++;
} while (*invalid_chars != '\0');
return 0;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_md5.c
* strophe XMPP client library -- test vectors for MD5
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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 */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* check_rand.c
* strophe XMPP client library -- test vectors for Hash_DRBG
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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 */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_resolver.c
* strophe XMPP client library -- tests for resolver
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_sasl.c
** 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
** 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_scram.c
* strophe XMPP client library -- test vectors for SCRAM-SHA1
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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 */

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_send_queue.c
** 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
** 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>
@@ -39,48 +40,48 @@ int main()
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;
conn->state = XMPP_STATE_CONNECTED;
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);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2);
ENSURE_EQ(2, xmpp_conn_send_queue_len(conn));
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);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 4);
ENSURE_EQ(4, xmpp_conn_send_queue_len(conn));
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);
COMPARE("bar", 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;
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);
COMPARE("foo", 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);
COMPARE("baan", 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);
COMPARE("baz", 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;

166
tests/test_serialize_sm.c Normal file
View File

@@ -0,0 +1,166 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_serialize_sm.c
** libstrophe XMPP client library -- test routines for the send queue
**
** Copyright (C) 2024 Stephen Paul Weber
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT or GPLv3 licenses.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
#include "test.h"
void callback(xmpp_conn_t *conn,
void *ctx,
const unsigned char *sm_state,
size_t sm_state_len)
{
int *callback_count = ctx;
(*callback_count)++;
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state, 5);
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 10, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x04SMID", 9, sm_state + 15, 9);
if (*callback_count == 1) {
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 5, 5);
COMPARE_BUF("\x9a\x00\x00\x00\x02", 5, sm_state + 24, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x03"
"foo",
8, sm_state + 29, 8);
COMPARE_BUF("\x7a\x00\x00\x00\x1a<r xmlns='urn:xmpp:sm:3'/>", 31,
sm_state + 37, 31);
COMPARE_BUF("\xba\x00\x00\x00\x00", 5, sm_state + 68, 5);
ENSURE_EQ(sm_state_len, 73);
xmpp_conn_t *newconn = xmpp_conn_new(conn->ctx);
xmpp_conn_restore_sm_state(newconn, sm_state, sm_state_len);
ENSURE_EQ(newconn->sm_state->sm_sent_nr, 0);
ENSURE_EQ(newconn->sm_state->sm_handled_nr, 0);
COMPARE(newconn->sm_state->id, "SMID");
ENSURE_EQ(newconn->send_queue_len, 2);
ENSURE_EQ(newconn->send_queue_user_len, 2);
ENSURE_EQ((size_t)(newconn->sm_state->sm_queue.head), 0);
xmpp_conn_release(newconn);
}
if (*callback_count == 2) {
COMPARE_BUF("\x1a\x00\x00\x00\x01", 5, sm_state + 5, 5);
COMPARE_BUF("\x9a\x00\x00\x00\x01", 5, sm_state + 24, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x1a<r xmlns='urn:xmpp:sm:3'/>", 31,
sm_state + 29, 31);
COMPARE_BUF("\xba\x00\x00\x00\x01", 5, sm_state + 60, 5);
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 65, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x03"
"foo",
8, sm_state + 70, 8);
ENSURE_EQ(sm_state_len, 78);
xmpp_conn_t *newconn = xmpp_conn_new(conn->ctx);
xmpp_conn_restore_sm_state(newconn, sm_state, sm_state_len);
ENSURE_EQ(newconn->sm_state->sm_sent_nr, 1);
ENSURE_EQ(newconn->sm_state->sm_handled_nr, 0);
COMPARE(newconn->sm_state->id, "SMID");
ENSURE_EQ(newconn->send_queue_len, 1);
ENSURE_EQ(newconn->send_queue_user_len, 1);
ENSURE_EQ(newconn->sm_state->sm_queue.head->sm_h, 0);
xmpp_conn_release(newconn);
}
if (*callback_count == 3) {
COMPARE_BUF("\x1a\x00\x00\x00\x01", 5, sm_state + 5, 5);
COMPARE_BUF("\x9a\x00\x00\x00\x00", 5, sm_state + 24, 5);
COMPARE_BUF("\xba\x00\x00\x00\x01", 5, sm_state + 29, 5);
COMPARE_BUF("\x1a\x00\x00\x00\x00", 5, sm_state + 34, 5);
COMPARE_BUF("\x7a\x00\x00\x00\x03"
"foo",
8, sm_state + 39, 8);
ENSURE_EQ(sm_state_len, 47);
xmpp_conn_t *newconn = xmpp_conn_new(conn->ctx);
xmpp_conn_restore_sm_state(newconn, sm_state, sm_state_len);
ENSURE_EQ(newconn->sm_state->sm_sent_nr, 1);
ENSURE_EQ(newconn->sm_state->sm_handled_nr, 0);
COMPARE(newconn->sm_state->id, "SMID");
ENSURE_EQ(newconn->send_queue_len, 0);
ENSURE_EQ(newconn->send_queue_user_len, 0);
ENSURE_EQ(newconn->sm_state->sm_queue.head->sm_h, 0);
xmpp_conn_release(newconn);
}
}
int fake_read(struct conn_interface *intf, void *buff, size_t len)
{
return 0;
}
int fake_write(struct conn_interface *intf, const void *buff, size_t len)
{
return len;
}
int fake_flush(struct conn_interface *intf)
{
return 0;
}
int fake_error_is_recoverable(struct conn_interface *intf, int err)
{
return 0;
}
int main()
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
xmpp_conn_state_t state;
xmpp_sm_state_t *sm_state;
char *ret;
unsigned int n;
int callback_count = 0;
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
sm_state = strophe_alloc(ctx, sizeof(*sm_state));
memset(sm_state, 0, sizeof(*sm_state));
sm_state->ctx = ctx;
sm_state->sm_support = sm_state->sm_enabled = sm_state->can_resume = 1;
sm_state->id = strophe_strdup(ctx, "SMID");
xmpp_conn_set_sm_state(conn, sm_state);
xmpp_conn_set_sm_callback(conn, callback, &callback_count);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0);
struct conn_interface intf = {fake_read, fake_write,
fake_flush, fake_flush,
fake_flush, fake_error_is_recoverable,
conn};
conn->intf = intf;
state = conn->state;
conn->state = XMPP_STATE_CONNECTED;
conn->sock = 123;
xmpp_send_raw(conn, "foo", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1);
ENSURE_EQ(callback_count, 1);
xmpp_run_once(ctx, 0);
ENSURE_EQ(callback_count, 3);
conn->state = state;
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -7,6 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <limits.h>
#undef HAVE_VSNPRINTF
#undef HAVE_SNPRINTF
@@ -28,7 +29,14 @@ int main(void)
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
"%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 fail = 0;
int num = 0;
@@ -60,6 +68,19 @@ int main(void)
}
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);
return fail != 0 ? 1 : 0;
}

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_sock.c
** 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
** 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_stanza.c
* libstrophe XMPP client library -- test routines for stanza functions
*
@@ -6,7 +7,7 @@
* This software is provided AS-IS with no warranty, either express
* 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 */
@@ -174,7 +175,7 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
assert(error != NULL);
mood = xmpp_stanza_new_from_string(ctx, str_mood);
assert(stanza != NULL);
assert(mood != NULL);
assert(xmpp_stanza_get_to(error) != NULL);
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
* 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
* 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>

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: MIT OR GPL-3.0-only */
/* test_xmppaddr.c
** libstrophe XMPP client library -- test routines for the xmppaddr
** certificate API's
@@ -7,7 +8,7 @@
** This software is provided AS-IS with no warranty, either express
** 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>