36 Commits

Author SHA1 Message Date
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
Steffen Jaeckel
70a908e18b Release libstrophe-0.12.2
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-08-08 11:48:47 +02:00
Steffen Jaeckel
004a5bf7fc fix infitite looping in resolver
...this time for real ...hopefully :)

fixup of 870f2174d5

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-08-05 14:54:50 +02:00
Steffen Jaeckel
e9bd06354a always print the broken message in the resolver tests
If Valgrind complains in this testcase we found a bug in the internal
resolver implementation, but as we didn't have the broken message we also
couldn't reproduce the failure.
Now we can reproduce it if it happens again.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-08-05 13:59:17 +02:00
Steffen Jaeckel
54b92c0255 re-use _auth_success() instead of copying ...
... and forgetting to 1. clear the password cache and 2. print a message
of what exactly happened ...

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-08-05 12:36:31 +02:00
Steffen Jaeckel
6881a2e770 add option to use clock_gettime() in perf example
This is done to support architectures where `rdtsc()` is not implemented.
In case it is available use `clock_gettime()`. Otherwise still fall back
to use `clock()`.

The first approach was to always use `clock_gettime()` if it is available
but the overhead it brings compared to `rdtsc()` is high, so I chose to
only try to use it if `rdtsc()` is not implemented.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-08-05 12:36:22 +02:00
Steffen Jaeckel
e29f422511 reset relevant parts of SM state on disconnect
Prevent assuming SM is enabled if the connection gets re-used without a
complete destroy&re-create of the connection object.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-08-04 11:54:36 +02:00
Tu Duong Quyet
1a8be1d617 Make it right to check/implement va_copy 2022-08-04 11:52:35 +02:00
Steffen Jaeckel
8ea15cf656 disable ASM in libressl
Valgrind spits a false-positive when the AESNI extension is used from ASM.

https://github.com/libressl-portable/portable/issues/760#issuecomment-1175461956

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-07-11 13:05:57 +02:00
Steffen Jaeckel
a8807feb5c Release libstrophe-0.12.1
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-07-05 00:08:47 +02:00
Steffen Jaeckel
4d15f1db0b disable some LibreSSL builds
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-07-04 20:13:00 +02:00
Steffen Jaeckel
957725348e also run CI tests with OpenSSL 3.0
... and extend build matrix of libressl.

Most of those new libressl build jobs are marked as `continue: true` since
either they don't build or they cause memory leaks (3.5/OPENBSD_7_1)
The `OPENBSD_X_Y` branches are also marked like that since they will
evolve and maybe break at a later point in time. Currently they represent
the buildable versions of their respective releases (3.3.6 resp. 3.4.3).

Also change CI distro to ubuntu-22.04 as using OpenSSL 3 on 20.04 fails.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-07-04 20:12:54 +02:00
Stu Tomlinson
357edbd367 Add XMPP_CONN_FLAG_DISABLE_SM to docs 2022-06-23 17:24:38 +01:00
Stu Tomlinson
3d01915407 Accept PKCS#12 file in either key or cert 2022-06-23 17:24:38 +01:00
Stu Tomlinson
e90a6e9f71 Add getpass() for Windows 2022-06-23 09:44:00 +01:00
Stu Tomlinson
3891b73c44 Open PKCS12 files as binary
Opening as text on Windows causes read failures:
tls DEBUG error:0680008E:asn1 encoding routines::not enough data
2022-06-23 09:44:00 +01:00
Stu Tomlinson
a66c3234d7 Fix tests with OpenSSL 3
RC2-40-CBC is disabled in OpenSSL 3, so recreate cert.emptypass.pfx
using AES-256-CBC
2022-06-23 09:44:00 +01:00
Stu Tomlinson
2a81327ab0 Ignore coding style change in git blame
github supports .git-blame-ignore-revs to ignore certain commits in
blame view, add the coding style change commit to this file

Can be used locally too with:
$ git blame --ignore-revs-file .git-blame-ignore-revs
2022-06-23 09:44:00 +01:00
Stu Tomlinson
1d6714c59b Fix 'make check' when builddir != srcdir 2022-06-23 09:44:00 +01:00
Stu Tomlinson
a771b3d4fe Support building docs when builddir != srcdir 2022-06-23 09:44:00 +01:00
Stu Tomlinson
700abd95b6 Add schannel option to autotools build 2022-06-23 09:43:59 +01:00
Fabrice Fontaine
476dd4c4f7 add --disable-examples
Allow the user to disable build of examples

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2022-06-11 23:31:08 +02:00
Michael Vetter
f0383d50cd Include unistd.h for ssize_t
When compiling on buildroot I get:
`src/tls.c:235:28: error: ‘ssize_t’ undeclared (first use in this
function); did you mean ‘size_t’? `

To have this POSIX type available we will need to include
`sys/types.h` or `unistd.h`.
2022-06-08 10:36:35 +02:00
Steffen Jaeckel
044398eeba update README
* fix link to CI
* improve "Documentation" part
* add comment regarding signing key

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-05-10 13:08:29 +02:00
35 changed files with 865 additions and 405 deletions

2
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,2 @@
# Unify coding style with clang-format
562a06425b96450481cdbc88e8872a2bf5a7d8aa

View File

@@ -2,7 +2,9 @@ name: CI
on:
push:
branches: [master]
branches:
- master
- next
pull_request:
branches: [master]
@@ -42,34 +44,45 @@ jobs:
run: |
cat test-suite*.log || true
libressl-tests:
runs-on: ubuntu-20.04
xssl-tests:
runs-on: ubuntu-22.04
strategy:
matrix:
libressl_versions:
- { version: "v3.4.2", continue: true }
- { version: "v3.1.5", continue: false }
- { version: "v2.1.10", continue: false }
xssl_versions:
- { version: "master", 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 }
# 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' }
name: LibreSSL tests
continue-on-error: ${{ matrix.libressl_versions.continue }}
name: xSSL tests
continue-on-error: ${{ matrix.xssl_versions.continue }}
steps:
- uses: actions/checkout@v2
- name: install dependencies
run: |
sudo apt update
sudo apt install -y libtool pkg-config libexpat1-dev valgrind
- name: build&install libressl
- name: build&install the TLS stack
env:
LIBRESSL_COMMIT: ${{ matrix.libressl_versions.version }}
XSSL_COMMITISH: ${{ matrix.xssl_versions.version }}
LIBRESSL: ${{ matrix.xssl_versions.libressl }}
run: |
./travis/before_script.sh
- name: Build the library
run: |
./bootstrap.sh
./configure ${{ matrix.valgrind.configure }} PKG_CONFIG_PATH="${HOME}/libressl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/libressl"
./configure ${{ matrix.valgrind.configure }} PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
make -j$(nproc)
- name: Run tests
run: |
@@ -84,13 +97,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: |

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,31 @@
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)
- Fix clearing of password cache on resumed connection (#214)
- Improve detection&implementation of `va_copy` (#213)
- Fix Valgrind CI builds against LibreSSL (#212)
- Fix perf example on platforms where an `rdtsc()` equivalent isn't implemented (#212)
0.12.1
- Fix compilation in buildroot (#207)
- Fixes regarding OpenSSL (#208)
- 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:
- 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.
0.12.0
- Fix potential infinite loop in resolver (#200)
- Prevent potential memory leak in `xmpp_stanza_new_from_string()` (#205)

View File

@@ -874,7 +874,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = ./
INPUT = $(SRCDIR)
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

View File

@@ -14,9 +14,11 @@ if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@
else
if !TLS_WITH_SCHANNEL
SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@
endif
endif
MINGW_LIBS = @MINGW_LIBS@
@@ -86,9 +88,13 @@ else
if TLS_WITH_GNUTLS
libstrophe_la_SOURCES += src/tls_gnutls.c
else
if TLS_WITH_SCHANNEL
libstrophe_la_SOURCES += src/tls_schannel.c
else
libstrophe_la_SOURCES += src/tls_openssl.c
endif
endif
endif
if PARSER_EXPAT
libstrophe_la_SOURCES += src/parser_expat.c
@@ -113,7 +119,6 @@ EXTRA_DIST = \
jni/Android.mk \
jni/Application.mk \
m4/ax_valgrind_check.m4 \
src/tls_schannel.c \
tests/cert.pem \
tests/cert.pfx \
tests/cert.emptypass.pfx \
@@ -122,6 +127,7 @@ EXTRA_DIST = \
tests/key_encrypted.pem \
tests/res_query_dump.c
if EXAMPLES
## Examples
noinst_PROGRAMS = \
examples/active \
@@ -165,6 +171,7 @@ examples_uuid_LDADD = $(STROPHE_LIBS)
examples_vcard_SOURCES = examples/vcard.c
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
examples_vcard_LDADD = $(STROPHE_LIBS)
endif
## Tests
@@ -318,7 +325,7 @@ test-release-all: dist-archives
echo "Success" && popd
docs:
@doxygen -q
@SRCDIR=$(top_srcdir) doxygen -q $(top_srcdir)/Doxyfile
@VALGRIND_CHECK_RULES@

View File

@@ -1,4 +1,4 @@
libstrophe [![Build Status](https://travis-ci.org/strophe/libstrophe.png?branch=master)](https://travis-ci.org/strophe/libstrophe)
libstrophe [![Build Status](https://github.com/strophe/libstrophe/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/strophe/libstrophe/actions/workflows/main.yml?query=branch%3Amaster+++)
==========
libstrophe is a lightweight XMPP client library written in C. It has
@@ -82,4 +82,17 @@ by running:
doxygen
or if you have everything configured properly:
make docs
Then open `docs/html/index.html`.
An online version of the documentation of the latest release is available on http://strophe.im/libstrophe/
Releases
--------
Releases are signed with the GPG key with ID `F8ADC1F9A68A7AFF0E2C89E4391A5EFC2D1709DE`.
It can be found e.g. on https://keys.openpgp.org/

View File

@@ -1,6 +1,6 @@
m4_define([v_maj], [0])
m4_define([v_min], [12])
m4_define([v_patch], [0])
m4_define([v_patch], [3])
m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min))
@@ -35,10 +35,16 @@ AS_CASE([$PLATFORM],
[haiku], [],
[WARNING_FLAGS="$WARNING_FLAGS -Wextra"])
AC_ARG_ENABLE([examples],
[AS_HELP_STRING([--disable-examples], [turn off examples])],
[case "${enableval}" in yes) examples=true ;; no) examples=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --disable-examples]) ;; esac],[examples=true])
AM_CONDITIONAL([EXAMPLES], [test x$examples = xtrue])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_WITH([gnutls],
[AS_HELP_STRING([--with-gnutls], [use GnuTLS for TLS support, OpenSSL is the default])])
AC_ARG_WITH([schannel],
[AS_HELP_STRING([--with-schannel], [use Windows Schannel for TLS support, OpenSSL is the default])])
AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
AC_ARG_ENABLE([cares],
@@ -80,11 +86,44 @@ AX_VALGRIND_DFLT([helgrind], [off])
AX_VALGRIND_DFLT([sgcheck], [off])
AX_VALGRIND_CHECK
AC_SEARCH_LIBS([clock_gettime], [rt], AC_DEFINE(HAVE_CLOCK_GETTIME,1))
AC_SEARCH_LIBS([socket], [network socket])
AC_CHECK_FUNCS([snprintf vsnprintf], [], [have_snprintf=no])
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
dnl Checking for va_copy availability
AC_MSG_CHECKING([for va_copy])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
va_list ap1,ap2;]], [[va_copy(ap1,ap2);]])],
have_va_copy=yes,
have_va_copy=no)
AC_MSG_RESULT($have_va_copy)
if test x"$have_va_copy" = x"yes"; then
AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
else
AC_MSG_CHECKING([for __va_copy])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>
va_list ap1,ap2;]], [[__va_copy(ap1,ap2);]])],
have___va_copy=yes,
have___va_copy=no)
AC_MSG_RESULT($have___va_copy)
if test x"$have___va_copy" = x"yes"; then
AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
fi
fi
if test x"$have_va_copy$have___va_copy" = x"nono"; then
dnl Checking whether va_list is an array type
AC_MSG_CHECKING([whether va_list is an array type])
AC_TRY_COMPILE2([
#include <stdarg.h>
void a(va_list * ap) {}],[
va_list ap1, ap2; a(&ap1); ap2 = (va_list) ap1],[
AC_MSG_RESULT(no)],[
AC_MSG_RESULT(yes)
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
PKG_CHECK_MODULES([gnutls], [gnutls],
[PC_REQUIRES="gnutls ${PC_REQUIRES}"],
[AC_CHECK_HEADER([gnutls/gnutls.h],
@@ -94,6 +133,10 @@ 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
if test "x$PLATFORM" != xwin32; then
AC_MSG_ERROR([schannel is only supported on Windows])
fi
elif test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"],
@@ -215,6 +258,7 @@ AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = 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])
# define while compiling
AC_DEFINE_UNQUOTED(LIBXMPP_VERSION_MAJOR, [v_maj], [Major version])

View File

@@ -21,6 +21,11 @@
#include <string.h>
#include <unistd.h>
#ifdef _WIN32
#include <conio.h>
#include <ctype.h>
#endif
#include <strophe.h>
static int reconnect;
@@ -149,12 +154,34 @@ void conn_handler(xmpp_conn_t *conn,
}
}
#ifdef _WIN32
static char *getpassword(const char *prompt, size_t maxlen)
{
char *b, *buffer = malloc(maxlen);
size_t i = 0;
b = buffer;
fputs(prompt, stderr);
for (i = 0; i < maxlen; i++, b++) {
char c = _getch();
if (c == '\r' || c == '\n')
break;
*b = c;
}
*b = '\0';
fputs("\n", stderr);
return buffer;
}
#else
#define getpassword(prompt, maxlen) getpass(prompt)
#endif
static int
password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
printf("Trying to unlock %s\n", xmpp_conn_get_keyfile(conn));
char *pass = getpass("Please enter password: ");
char *pass = getpassword("Please enter password: ", pw_max);
if (!pass)
return -1;
size_t passlen = strlen(pass);

View File

@@ -15,6 +15,8 @@
#include <unistd.h>
#ifdef _WIN32
#include <conio.h>
#include <ctype.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
@@ -94,12 +96,34 @@ static int certfail_handler(const xmpp_tlscert_t *cert,
return read_char[0] == 'y' || read_char[0] == 'Y';
}
#ifdef _WIN32
static char *getpassword(const char *prompt, size_t maxlen)
{
char *b, *buffer = malloc(maxlen);
size_t i = 0;
b = buffer;
fputs(prompt, stderr);
for (i = 0; i < maxlen; i++, b++) {
char c = _getch();
if (c == '\r' || c == '\n')
break;
*b = c;
}
*b = '\0';
fputs("\n", stderr);
return buffer;
}
#else
#define getpassword(prompt, maxlen) getpass(prompt)
#endif
static int
password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
printf("Trying to unlock %s\n", xmpp_conn_get_keyfile(conn));
char *pass = getpass("Please enter password: ");
char *pass = getpassword("Please enter password: ", pw_max);
if (!pass)
return -1;
size_t passlen = strlen(pass);

View File

@@ -20,16 +20,20 @@
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
static void init_timer(void);
static void t_start(void);
static uint64_t t_read(void);
static const char *perf_time_unit;
#define NUM_SAMPLES 1000u
static void perf_rand(xmpp_ctx_t *ctx)
{
xmpp_rand_t *rng = xmpp_rand_new(ctx);
uint64_t t1, t2;
uint64_t t1, t2, t3 = 0;
unsigned int n;
const size_t alloc_sz = 0x1000u;
size_t sz;
@@ -37,12 +41,12 @@ static void perf_rand(xmpp_ctx_t *ctx)
/* pre-heat */
for (n = 1; n < 4; ++n) {
xmpp_rand_bytes(rng, buf, n * 10);
xmpp_rand_bytes(rng, buf, alloc_sz / n);
}
for (sz = 2; sz <= alloc_sz; sz <<= 1) {
t2 = 0;
for (n = 0; n < 1000u; ++n) {
for (n = 0; n < NUM_SAMPLES; ++n) {
t_start();
t1 = t_read();
@@ -52,10 +56,15 @@ static void perf_rand(xmpp_ctx_t *ctx)
t1 = t_read() - t1;
t2 += t1;
}
t2 /= 1000;
fprintf(stderr,
"Reading %6zu bytes from PRNG took %8" PRIu64 " cycles\n", sz,
t2);
t2 /= NUM_SAMPLES;
fprintf(stderr, "Reading %6zu bytes from PRNG took %8" PRIu64 " %s\n",
sz, t2, perf_time_unit);
if (t3) {
double d3 = (double)t3, d2 = (double)t2;
fprintf(stderr, " +%.2f%%\n",
(d2 - d3) / ((d2 + d3) * 0.5) * 100.);
}
t3 = t2;
}
free(buf);
xmpp_rand_free(ctx, rng);
@@ -90,7 +99,7 @@ static uint64_t rdtsc(void)
unsigned hi, lo;
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
return ((uint64_t)lo) | (((uint64_t)hi) << 32);
#elif defined(LTC_PPC32) || defined(TFM_PPC32)
#elif defined(__POWERPC__)
unsigned long a, b;
__asm__ __volatile__("mftbu %1 \nmftb %0\n" : "=r"(a), "=r"(b));
return (((uint64_t)b) << 32ULL) | ((uint64_t)a);
@@ -116,25 +125,41 @@ static uint64_t rdtsc(void)
uint64_t CNTVCT_EL0;
__asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(CNTVCT_EL0));
return CNTVCT_EL0;
#elif defined HAVE_CLOCK_GETTIME
#define USE_CLOCK_GETTIME
struct timespec result;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &result);
return result.tv_sec * 1000000000 + result.tv_nsec;
#else
return clock();
#endif
#endif /* __GNUC__ */
/* Microsoft and Intel Windows compilers */
#elif defined _M_IX86 && !defined(LTC_NO_ASM)
#elif defined _M_IX86
__asm rdtsc
#elif defined _M_AMD64 && !defined(LTC_NO_ASM)
#elif defined _M_AMD64
return __rdtsc();
#elif defined _M_IA64 && !defined(LTC_NO_ASM)
#elif defined _M_IA64
#if defined __INTEL_COMPILER
#include <ia64intrin.h>
#endif
return __getReg(3116);
#elif defined HAVE_CLOCK_GETTIME
#define USE_CLOCK_GETTIME
struct timespec result;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &result);
return result.tv_sec * 1000000000 + result.tv_nsec;
#else
return clock();
#endif
}
#if defined USE_CLOCK_GETTIME
static const char *perf_time_unit = "ns";
#else
static const char *perf_time_unit = "cycles";
#endif
static void t_start(void)
{
timer = rdtsc();

28
m4/ac_try_compile2.m4 Normal file
View File

@@ -0,0 +1,28 @@
dnl Like AC_TRY_EVAL but also errors out if the compiler generates
dnl _any_ output. Some compilers might issue warnings which we want
dnl to catch.
AC_DEFUN([AC_TRY_EVAL2],
[{ (eval echo configure:__oline__: \"[$]$1\") 1>&AS_MESSAGE_LOG_FD; dnl
(eval [$]$1) 2>&AS_MESSAGE_LOG_FD; _out=`eval [$]$1 2>&1` && test "x$_out" = x; }])
dnl Like AC_TRY_COMPILE but calls AC_TRY_EVAL2 instead of AC_TRY_EVAL
AC_DEFUN([AC_TRY_COMPILE2],
[cat > conftest.$ac_ext <<EOF
[#]line __oline__ "configure"
#include "confdefs.h"
[$1]
int main(void) {
[$2]
; return 0; }
EOF
if AC_TRY_EVAL2(ac_compile); then
ifelse([$3], , :, [rm -rf conftest*
$3])
else
echo "configure: failed program was:" >&AS_MESSAGE_LOG_FD
cat conftest.$ac_ext >&AS_MESSAGE_LOG_FD
ifelse([$4], , , [ rm -rf conftest*
$4
])dnl
fi
rm -f conftest*])

View File

@@ -391,14 +391,12 @@ static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
xmpp_stanza_set_text(authdata, response);
strophe_free(conn->ctx, response);
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(auth, authdata, 0);
handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL,
NULL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
} else {
return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
@@ -432,7 +430,6 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
xmpp_stanza_set_name(auth, "response");
xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
} else {
return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
}
@@ -491,11 +488,9 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
xmpp_stanza_set_text(authdata, response);
strophe_free(conn->ctx, response);
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(auth, authdata, 0);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
rc = 1; /* Keep handler */
} else {
@@ -625,7 +620,6 @@ static void _auth(xmpp_conn_t *conn)
NULL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
/* TLS was tried, unset flag */
conn->tls_support = 0;
@@ -653,7 +647,6 @@ static void _auth(xmpp_conn_t *conn)
"ANONYMOUS");
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
/* SASL ANONYMOUS was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
@@ -689,14 +682,12 @@ static void _auth(xmpp_conn_t *conn)
}
strophe_free(conn->ctx, str);
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(auth, authdata, 0);
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"EXTERNAL");
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
/* SASL EXTERNAL was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_EXTERNAL;
@@ -754,14 +745,12 @@ static void _auth(xmpp_conn_t *conn)
}
xmpp_stanza_set_text(authdata, str);
strophe_free(conn->ctx, str);
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(auth, authdata, 0);
handler_add(conn, _handle_scram_challenge, XMPP_NS_SASL, NULL, NULL,
(void *)scram_ctx);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
/* SASL SCRAM-SHA-1 was tried, unset flag */
conn->sasl_support &= ~scram_ctx->alg->mask;
@@ -776,7 +765,6 @@ static void _auth(xmpp_conn_t *conn)
NULL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
/* SASL DIGEST-MD5 was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_DIGESTMD5;
@@ -805,14 +793,12 @@ static void _auth(xmpp_conn_t *conn)
strophe_free(conn->ctx, str);
strophe_free(conn->ctx, authid);
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(auth, authdata, 0);
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"PLAIN");
send_stanza(conn, auth, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(auth);
/* SASL PLAIN was tried */
conn->sasl_support &= ~SASL_MASK_PLAIN;
@@ -923,19 +909,15 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
return 0;
}
xmpp_stanza_set_text(text, resource);
xmpp_stanza_add_child(res, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(bind, res);
xmpp_stanza_release(res);
xmpp_stanza_add_child_ex(res, text, 0);
xmpp_stanza_add_child_ex(bind, res, 0);
strophe_free(conn->ctx, resource);
}
xmpp_stanza_add_child(iq, bind);
xmpp_stanza_release(bind);
xmpp_stanza_add_child_ex(iq, bind, 0);
/* send bind request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(iq);
return 0;
}
@@ -957,6 +939,13 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (bind) {
ns = xmpp_stanza_get_ns(bind);
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
bind = xmpp_stanza_copy(bind);
if (!bind) {
disconnect_mem_error(conn);
return 0;
}
} else {
conn->bind_required = 0;
}
/* check whether session establishment is required */
@@ -974,12 +963,6 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
conn->sm_state->sm_support = 1;
}
bind = xmpp_stanza_copy(bind);
if (!bind) {
disconnect_mem_error(conn);
return 0;
}
/* we are expecting either <bind/> and <session/> since this is a
XMPP style connection or we <resume/> the previous session */
@@ -999,7 +982,6 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
strophe_snprintf(h, sizeof(h), "%u", conn->sm_state->sm_handled_nr);
xmpp_stanza_set_attribute(resume, "h", h);
send_stanza(conn, resume, XMPP_QUEUE_SM_STROPHE);
xmpp_stanza_release(resume);
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
}
/* if bind is required, go ahead and start it */
@@ -1008,7 +990,9 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
_do_bind(conn, bind);
} else {
/* can't bind, disconnect */
xmpp_stanza_release(bind);
if (bind) {
xmpp_stanza_release(bind);
}
strophe_error(conn->ctx, "xmpp",
"Stream features does not allow "
"resource bind.");
@@ -1080,12 +1064,10 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_set_name(session, "session");
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
xmpp_stanza_add_child(iq, session);
xmpp_stanza_release(session);
xmpp_stanza_add_child_ex(iq, session, 0);
/* send session establishment request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(iq);
}
if (conn->sm_state->sm_support && !conn->sm_disable) {
@@ -1100,7 +1082,6 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_set_attribute(enable, "resume", "true");
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
xmpp_stanza_release(enable);
}
if (!conn->session_required) {
@@ -1239,10 +1220,8 @@ static int _handle_sm(xmpp_conn_t *const conn,
}
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
}
conn->authenticated = 1;
/* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
strophe_debug(conn->ctx, "xmpp", "Session resumed successfully.");
_auth_success(conn);
} else if (strcmp(name, "failed") == 0) {
name = NULL;
@@ -1361,15 +1340,13 @@ static void _auth_legacy(xmpp_conn_t *conn)
goto err_free;
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_stanza_add_child_ex(iq, query, 0);
child = xmpp_stanza_new(conn->ctx);
if (!child)
goto err_free;
xmpp_stanza_set_name(child, "username");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
xmpp_stanza_add_child_ex(query, child, 0);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata)
@@ -1381,29 +1358,25 @@ static void _auth_legacy(xmpp_conn_t *conn)
}
xmpp_stanza_set_text(authdata, str);
strophe_free(conn->ctx, str);
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(child, authdata, 0);
child = xmpp_stanza_new(conn->ctx);
if (!child)
goto err_free;
xmpp_stanza_set_name(child, "password");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
xmpp_stanza_add_child_ex(query, child, 0);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata)
goto err_free;
xmpp_stanza_set_text(authdata, conn->pass);
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(child, authdata, 0);
child = xmpp_stanza_new(conn->ctx);
if (!child)
goto err_free;
xmpp_stanza_set_name(child, "resource");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
xmpp_stanza_add_child_ex(query, child, 0);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata)
@@ -1420,14 +1393,12 @@ static void _auth_legacy(xmpp_conn_t *conn)
xmpp_disconnect(conn);
return;
}
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
xmpp_stanza_add_child_ex(child, authdata, 0);
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(iq);
return;
err_free:

View File

@@ -198,6 +198,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 */

View File

@@ -29,7 +29,6 @@
#include "common.h"
#include "util.h"
#include "parser.h"
#include "resolver.h"
#ifndef DEFAULT_SEND_QUEUE_MAX
/** @def DEFAULT_SEND_QUEUE_MAX
@@ -79,6 +78,7 @@
#endif
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn);
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len);
@@ -102,8 +102,6 @@ static unsigned short _conn_default_port(xmpp_conn_t *conn,
static void _conn_reset(xmpp_conn_t *conn);
static int _conn_connect(xmpp_conn_t *conn,
const char *domain,
const char *host,
unsigned short port,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void *userdata);
@@ -122,8 +120,6 @@ void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text)
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
send_stanza(conn, error, XMPP_QUEUE_STROPHE);
xmpp_stanza_release(error);
}
/** Create a new Strophe connection object.
@@ -149,7 +145,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
conn->type = XMPP_UNKNOWN;
conn->state = XMPP_STATE_DISCONNECTED;
conn->sock = -1;
conn->xsock = NULL;
conn->sock = INVALID_SOCKET;
conn->ka_timeout = KEEPALIVE_TIMEOUT;
conn->ka_interval = KEEPALIVE_INTERVAL;
conn->ka_count = KEEPALIVE_COUNT;
@@ -403,6 +400,7 @@ int xmpp_conn_release(xmpp_conn_t *conn)
if (conn->sm_state)
xmpp_free_sm_state(conn->sm_state);
tls_clear_password_cache(conn);
sock_free(conn->xsock);
strophe_free(ctx, conn);
released = 1;
}
@@ -482,6 +480,8 @@ void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_cafile)
strophe_free(conn->ctx, conn->tls_cafile);
conn->tls_cafile = strophe_strdup(conn->ctx, path);
}
@@ -494,6 +494,8 @@ void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_capath)
strophe_free(conn->ctx, conn->tls_capath);
conn->tls_capath = strophe_strdup(conn->ctx, path);
}
@@ -573,11 +575,12 @@ const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn)
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it must be passed via
* the `key` parameter and `cert` must be NULL.
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup TLS
@@ -589,13 +592,21 @@ void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (conn->tls_client_cert)
strophe_free(conn->ctx, conn->tls_client_cert);
if (cert)
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
else
conn->tls_client_cert = NULL;
conn->tls_client_cert = NULL;
if (conn->tls_client_key)
strophe_free(conn->ctx, conn->tls_client_key);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
conn->tls_client_key = NULL;
if (cert && key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
} else if (cert && !key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
} else if (!cert && key) {
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
conn->tls_client_cert = strophe_strdup(conn->ctx, key);
}
}
/** Get the number of xmppAddr entries in the client certificate.
@@ -693,12 +704,7 @@ int xmpp_connect_client(xmpp_conn_t *conn,
xmpp_conn_handler callback,
void *userdata)
{
resolver_srv_rr_t *srv_rr_list = NULL;
resolver_srv_rr_t *rr;
char *domain;
const char *host = NULL;
unsigned short port = 0;
int found = XMPP_DOMAIN_NOT_FOUND;
int rc;
if (!conn->jid && (conn->tls_client_cert || conn->tls_client_key)) {
@@ -727,48 +733,35 @@ int xmpp_connect_client(xmpp_conn_t *conn,
if (!conn->sm_state) {
conn->sm_state = strophe_alloc(conn->ctx, sizeof(*conn->sm_state));
if (!conn->sm_state)
return XMPP_EMEM;
goto err_mem;
memset(conn->sm_state, 0, sizeof(*conn->sm_state));
conn->sm_state->ctx = conn->ctx;
}
if (altdomain != NULL) {
strophe_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
host = altdomain;
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
found = XMPP_DOMAIN_ALTDOMAIN;
if (altdomain != NULL)
strophe_debug(conn->ctx, "conn", "Connecting via altdomain.");
if (conn->tls_legacy_ssl && !altdomain) {
/* SSL tunneled connection on 5223 port is legacy and doesn't
* have an SRV record. */
} else if (!conn->tls_legacy_ssl) {
found = resolver_srv_lookup(conn->ctx, "xmpp-client", "tcp", domain,
&srv_rr_list);
altdomain = domain;
}
altport = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
if (XMPP_DOMAIN_NOT_FOUND == found) {
strophe_debug(conn->ctx, "xmpp",
"SRV lookup failed, "
"connecting via domain.");
host = domain;
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
found = XMPP_DOMAIN_ALTDOMAIN;
}
rr = srv_rr_list;
do {
if (XMPP_DOMAIN_FOUND == found && rr != NULL) {
host = rr->target;
port = rr->port;
rr = rr->next;
}
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT, callback,
userdata);
} while (rc != 0 && rr != NULL);
if (conn->xsock)
sock_free(conn->xsock);
conn->xsock = sock_new(conn, domain, altdomain, altport);
if (!conn->xsock)
goto err_mem;
rc = _conn_connect(conn, domain, XMPP_CLIENT, callback, userdata);
strophe_free(conn->ctx, domain);
resolver_srv_free(conn->ctx, srv_rr_list);
return rc;
err_mem:
strophe_free(conn->ctx, domain);
return XMPP_EMEM;
}
/** Initiate a component connection to server.
@@ -814,10 +807,15 @@ int xmpp_connect_component(xmpp_conn_t *conn,
}
port = port ? port : _conn_default_port(conn, XMPP_COMPONENT);
if (conn->xsock)
sock_free(conn->xsock);
conn->xsock = sock_new(conn, NULL, server, port);
if (!conn->xsock)
return XMPP_EMEM;
/* JID serves as an identifier here and will be used as "to" attribute
of the stream */
return _conn_connect(conn, conn->jid, server, port, XMPP_COMPONENT,
callback, userdata);
return _conn_connect(conn, conn->jid, XMPP_COMPONENT, callback, userdata);
}
/** Initiate a raw connection to the XMPP server.
@@ -965,7 +963,9 @@ void conn_disconnect(xmpp_conn_t *conn)
tls_free(conn->tls);
conn->tls = NULL;
}
sock_close(conn->sock);
if (conn->sock != INVALID_SOCKET)
sock_close(conn->sock);
_reset_sm_state_for_reconnect(conn);
/* fire off connection handler */
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
@@ -1062,7 +1062,7 @@ void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len)
*/
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
{
send_stanza(conn, stanza, XMPP_QUEUE_USER);
send_stanza(conn, xmpp_stanza_clone(stanza), XMPP_QUEUE_USER);
}
/** Send the opening &lt;stream:stream&gt; tag to the server.
@@ -1168,6 +1168,7 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
* - XMPP_CONN_FLAG_LEGACY_SSL
* - XMPP_CONN_FLAG_TRUST_TLS
* - XMPP_CONN_FLAG_LEGACY_AUTH
* - XMPP_CONN_FLAG_DISABLE_SM
*
* @param conn a Strophe connection object
* @param flags ORed connection flags
@@ -1288,32 +1289,38 @@ xmpp_sm_state_t *xmpp_conn_get_sm_state(xmpp_conn_t *conn)
ret = conn->sm_state;
conn->sm_state = NULL;
if (ret->previd) {
strophe_free(conn->ctx, ret->previd);
ret->previd = NULL;
}
if (ret->can_resume) {
ret->previd = ret->id;
ret->id = NULL;
ret->bound_jid = conn->bound_jid;
conn->bound_jid = NULL;
} else if (ret->id) {
strophe_free(conn->ctx, ret->id);
ret->id = NULL;
}
ret->sm_enabled = ret->sm_support = ret->resume = 0;
if (ret->bind) {
xmpp_stanza_release(ret->bind);
ret->bind = NULL;
}
return ret;
}
static void _reset_sm_state_for_reconnect(xmpp_conn_t *conn)
{
xmpp_sm_state_t *s = conn->sm_state;
if (s->previd) {
strophe_free(conn->ctx, s->previd);
s->previd = NULL;
}
if (s->can_resume) {
s->previd = s->id;
s->id = NULL;
s->bound_jid = conn->bound_jid;
conn->bound_jid = NULL;
} else if (s->id) {
strophe_free(conn->ctx, s->id);
s->id = NULL;
}
s->sm_enabled = s->sm_support = s->resume = 0;
if (s->bind) {
xmpp_stanza_release(s->bind);
s->bind = NULL;
}
}
/**
* @param conn a Strophe connection object
* @param sm_state A Stream Management state returned from a call to
@@ -1720,7 +1727,6 @@ static void _conn_sm_handle_stanza(xmpp_conn_t *const conn,
strophe_snprintf(h, sizeof(h), "%u", conn->sm_state->sm_handled_nr);
xmpp_stanza_set_attribute(a, "h", h);
send_stanza(conn, a, XMPP_QUEUE_SM_STROPHE);
xmpp_stanza_release(a);
} else if (strcmp(name, "a") == 0) {
attr_h = xmpp_stanza_get_attribute(stanza, "h");
if (!attr_h) {
@@ -1826,8 +1832,6 @@ static void _conn_reset(xmpp_conn_t *conn)
static int _conn_connect(xmpp_conn_t *conn,
const char *domain,
const char *host,
unsigned short port,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void *userdata)
@@ -1838,8 +1842,6 @@ static int _conn_connect(xmpp_conn_t *conn,
return XMPP_EINVOP;
if (type != XMPP_CLIENT && type != XMPP_COMPONENT)
return XMPP_EINVOP;
if (host == NULL || port == 0)
return XMPP_EINT;
_conn_reset(conn);
@@ -1848,10 +1850,8 @@ static int _conn_connect(xmpp_conn_t *conn,
if (!conn->domain)
return XMPP_EMEM;
conn->sock = sock_connect(conn, host, port);
strophe_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
host, port, conn->sock);
if (conn->sock == -1)
conn->sock = sock_connect(conn->xsock);
if (conn->sock == INVALID_SOCKET)
return XMPP_EINT;
/* setup handler */
@@ -1870,7 +1870,6 @@ static int _conn_connect(xmpp_conn_t *conn,
conn->state = XMPP_STATE_CONNECTING;
conn->timeout_stamp = time_stamp();
strophe_debug(conn->ctx, "xmpp", "Attempting to connect to %s", host);
return 0;
}
@@ -1954,14 +1953,16 @@ void send_stanza(xmpp_conn_t *conn,
size_t len;
if (conn->state != XMPP_STATE_CONNECTED)
return;
goto out;
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
strophe_error(conn->ctx, "conn", "Failed to stanza_to_text");
return;
goto out;
}
_send_raw(conn, buf, len, owner, NULL);
out:
xmpp_stanza_release(stanza);
}
void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item)

View File

@@ -50,10 +50,22 @@
#include "resolver.h"
#include "util.h"
/* Workaround for systems without va_copy support. */
#if defined(_MSC_VER) && _MSC_VER < 1800 || \
!defined(_MSC_VER) && !defined(HAVE_DECL_VA_COPY)
#define va_copy(d, s) (memcpy(&d, &s, sizeof(va_list)))
#ifndef va_copy
#ifdef HAVE_VA_COPY
#define va_copy(dest, src) va_copy(dest, src)
#else
#ifdef HAVE___VA_COPY
#define va_copy(dest, src) __va_copy(dest, src)
#else
#ifndef VA_LIST_IS_ARRAY
#define va_copy(dest, src) (dest) = (src)
#else
#include <string.h>
#define va_copy(dest, src) \
memcpy((char *)(dest), (char *)(src), sizeof(va_list))
#endif
#endif
#endif
#endif
/** Initialize the Strophe library.

View File

@@ -60,6 +60,18 @@
/** Max buffer size for receiving messages. */
#define STROPE_MESSAGE_BUFFER_SIZE 4096
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
* xmpp_send and related functions and run through the Strophe even
@@ -209,9 +221,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:
@@ -272,7 +289,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;
}

View File

@@ -37,8 +37,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 +48,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 +118,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 +154,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

@@ -152,8 +152,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 +194,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

@@ -164,10 +164,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 +220,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

@@ -23,6 +23,10 @@
#include <string.h> /* memeset */
#include <time.h> /* clock, time */
#if !defined(_WIN32)
#include <unistd.h>
#endif
#if !defined(DONT_USE_GETRANDOM) && defined(__linux__) && \
defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2, 25)

View File

@@ -91,6 +91,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 +177,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);
@@ -322,7 +345,7 @@ static unsigned message_name_get(const unsigned char *buf,
return 0;
pointer = (label_len & 0x3f) << 8 | buf[i++];
/* Prevent infinite looping */
if (pointer == buf_offset)
if (pointer >= buf_offset)
return 0;
if (name != NULL && name_len >= name_max && name_max > 0) {
/* We have filled the name buffer. Don't pass it recursively. */
@@ -434,17 +457,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;
}

View File

@@ -36,6 +36,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

@@ -24,6 +24,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 +35,18 @@
#endif
#include "common.h"
#include "resolver.h"
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)
{
@@ -68,50 +81,164 @@ 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 %d",
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 = 0;
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) {
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())) {
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;
}

View File

@@ -20,6 +20,7 @@
#ifndef _WIN32
typedef int sock_t;
#define INVALID_SOCKET (-1)
#else
#include <winsock2.h>
#include <ws2tcpip.h>
@@ -28,12 +29,19 @@ typedef int sock_t;
typedef SOCKET sock_t;
#endif
typedef struct _xmpp_sock_t xmpp_sock_t;
void sock_initialize(void);
void sock_shutdown(void);
int sock_error(void);
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);

View File

@@ -182,6 +182,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 +1605,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 +1615,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

@@ -21,6 +21,10 @@
#include <stdarg.h>
#include <string.h>
#if !defined(_WIN32)
#include <unistd.h>
#endif
#include "strophe.h"
#include "common.h"
@@ -217,7 +221,7 @@ int tls_caching_password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn)
int ret;
unsigned char hash[XMPP_SHA1_DIGEST_SIZE];
const char *fname = conn->tls_client_key;
const char *fname = conn->tls_client_cert;
size_t fname_len = strlen(fname);
xmpp_sha1_digest((void *)fname, fname_len, hash);
if (fname_len && fname_len == conn->password_cache.fnamelen &&

View File

@@ -95,7 +95,7 @@ static gnutls_x509_crt_t _tls_load_cert_p12(xmpp_conn_t *conn)
int err = -1;
if (gnutls_pkcs12_init(&p12) < 0)
return NULL;
if (gnutls_load_file(conn->tls_client_key, &data) < 0)
if (gnutls_load_file(conn->tls_client_cert, &data) < 0)
goto error_out;
if (gnutls_pkcs12_import(p12, &data, GNUTLS_X509_FMT_DER, 0) < 0)
goto error_out2;
@@ -168,7 +168,7 @@ static gnutls_x509_crt_t _tls_load_cert(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
if (!conn->tls_client_cert && conn->tls_client_key) {
if (conn->tls_client_cert && !conn->tls_client_key) {
return _tls_load_cert_p12(conn);
}
return _tls_load_cert_x509(conn);
@@ -459,7 +459,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
}
strophe_debug(tls->ctx, "tls", "wrong password?");
}
} else if (conn->tls_client_key) {
} else if (conn->tls_client_cert) {
unsigned int retries = 0;
while (retries++ < conn->password_retries) {
@@ -470,7 +470,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
if (passlen < 0)
continue;
int err = gnutls_certificate_set_x509_simple_pkcs12_file(
tls->cred, conn->tls_client_key, GNUTLS_X509_FMT_DER, pass);
tls->cred, conn->tls_client_cert, GNUTLS_X509_FMT_DER,
pass);
memset(pass, 0, sizeof(pass));
if (err == 0)
break;

View File

@@ -616,7 +616,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
ERR_GET_LIB(err), ERR_GET_REASON(err));
goto err_free_ctx;
}
} else if (conn->tls_client_key) {
} else if (conn->tls_client_cert) {
EVP_PKEY *pkey = NULL;
STACK_OF(X509) *ca = NULL;
X509 *cert = _tls_cert_read_p12(conn, &pkey, &ca);
@@ -974,7 +974,7 @@ _tls_cert_read_p12(xmpp_conn_t *conn, EVP_PKEY **pkey, STACK_OF(X509) * *ca)
return conn->tls->client_cert;
X509 *cert = NULL;
PKCS12 *p12 = NULL;
BIO *f = BIO_new_file(conn->tls_client_key, "r");
BIO *f = BIO_new_file(conn->tls_client_cert, "rb");
if (!f) {
strophe_debug(conn->ctx, "tls", "f == NULL");
goto error_out;
@@ -1034,7 +1034,7 @@ static X509 *_tls_cert_read(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
if (!conn->tls_client_cert && conn->tls_client_key) {
if (conn->tls_client_cert && !conn->tls_client_key) {
return _tls_cert_read_p12(conn, NULL, NULL);
}
return _tls_cert_read_x509(conn);

Binary file not shown.

View File

@@ -34,17 +34,19 @@
#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(v1, v2) \
do { \
const char *__v1 = v1; \
const char *__v2 = v2; \
if ((__v1 == NULL) && (__v2 == NULL)) { \
/* noop */ \
} else if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \
printf("Error: %s\n" \
"Expected: %s\n" \
"Got: %s\n", \
#v1 " != " #v2, __v1, __v2); \
exit(1); \
} \
} while (0)
#define COMPARE_BUF(v1, len1, v2, len2) \

View File

@@ -15,114 +15,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 +109,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

@@ -174,10 +174,10 @@ int main()
xmpp_ctx_t *ctx;
xmpp_rand_t *rand;
resolver_srv_rr_t *srv_rr_list;
char *domain;
char *domain, *rnd_b64;
unsigned char *buf;
unsigned short port;
size_t i;
size_t i, slen;
int ret;
ctx = xmpp_ctx_new(NULL, NULL);
@@ -223,10 +223,18 @@ int main()
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
resolver_srv_free(ctx, srv_rr_list);
strophe_free(ctx, buf);
xmpp_rand_free(ctx, rand);
printf("ok\n");
printf("Broken message was:\n");
rnd_b64 = xmpp_base64_encode(ctx, buf, sizeof(data2));
slen = strlen(rnd_b64);
for (i = 0; i < slen; i += 64) {
printf("%.64s\n", &rnd_b64[i]);
}
strophe_free(ctx, buf);
strophe_free(ctx, rnd_b64);
xmpp_ctx_free(ctx);
return 0;

View File

@@ -13,6 +13,7 @@
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include "strophe.h"
@@ -42,8 +43,13 @@ int main()
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
{0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL},
};
const char *srcdir;
char *certbuf, *keybuf;
char xmppaddr_num[] = "0";
unsigned int m, n;
@@ -51,13 +57,29 @@ int main()
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
srcdir = getenv("srcdir");
certbuf = malloc(MAXPATHLEN);
keybuf = malloc(MAXPATHLEN);
for (m = 0; m < sizeof(client_cert) / sizeof(client_cert[0]); ++m) {
char *certfile = certbuf, *keyfile = keybuf;
conn = xmpp_conn_new(ctx);
if (client_cert[m].pem)
snprintf(certfile, MAXPATHLEN, "%s/%s", srcdir, client_cert[m].pem);
else
certfile = NULL;
if (client_cert[m].key)
snprintf(keyfile, MAXPATHLEN, "%s/%s", srcdir, client_cert[m].key);
else
keyfile = NULL;
if (client_cert[m].needs_callback)
xmpp_conn_set_password_callback(conn, password_callback, NULL);
xmpp_conn_set_client_cert(conn, client_cert[m].pem, client_cert[m].key);
xmpp_conn_set_client_cert(conn, certfile, keyfile);
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);
@@ -88,6 +110,8 @@ int main()
}
xmpp_conn_release(conn);
}
free(certbuf);
free(keybuf);
xmpp_ctx_free(ctx);
xmpp_shutdown();

View File

@@ -1,14 +1,26 @@
#!/bin/sh
if [ "x$LIBRESSL_COMMIT" != "x" ]; then
cd "$HOME"
git clone https://github.com/libressl-portable/portable.git libressl-git
cd libressl-git
if [ -n "$LIBRESSL_COMMIT" ]; then
git checkout "$LIBRESSL_COMMIT"
fi
./autogen.sh
./configure --prefix="$HOME/libressl"
make -j"$(nproc)"
make install
set -e
[ "x$XSSL_COMMITISH" != "x" ]
if [ "x$LIBRESSL" = "xtrue" ]; then
REPO_URL="https://github.com/libressl-portable/portable.git"
AUTOGEN_CMD="./autogen.sh"
CONFIG_CMD="./configure --prefix=$HOME/xssl --disable-asm"
MAKE_TARGET="install"
else
REPO_URL="https://github.com/openssl/openssl.git"
AUTOGEN_CMD="true"
CONFIG_CMD="./Configure --prefix=$HOME/xssl --libdir=lib"
MAKE_TARGET="install_sw"
fi
cd "$HOME"
git clone --no-checkout "$REPO_URL" xssl-git
cd xssl-git
git checkout "$XSSL_COMMITISH"
$AUTOGEN_CMD
$CONFIG_CMD
make -j"$(nproc)"
make $MAKE_TARGET