5 Commits

Author SHA1 Message Date
Dmitry Podgorny
06cb1459f1 tls/securetransport: add client cert stub functions 2021-03-30 00:46:13 +03:00
Dmitry Podgorny
82f372fa49 Add tls_securetransport.c to EXTRA_DIST 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
9ddc881102 tls/securetransport: tls_new() accepts xmpp_conn_t object 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
f6ef50d134 tls/securetransport: fix indentation 2021-03-30 00:30:30 +03:00
Chris A. Taylor
bd87653c76 Add Secure Transport implementation of TLS 2021-03-30 00:30:30 +03:00
68 changed files with 1706 additions and 6239 deletions

View File

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

View File

@@ -1,49 +0,0 @@
<!--
Provide a general summary of the issue in the Title above
This is a very generic template, remove items that do not apply. For completed items, change [ ] to [x].
-->
### Prerequisites
* [ ] Checked that your issue isn't already filed: https://github.com/strophe/libstrophe/issues?q=
### Additional Information
<!--- Any additional information, configuration or data that might be necessary to reproduce the issue. -->
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior or even better, provide a functional code example reproducing your issue. -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Steps to Reproduce (for bugs)
<!--- Please either describe your issue in detail or even better, provide a functional code example reproducing your issue. -->
1.
2.
3.
4.
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
## Environment
<!---
Please provide the version of the library you're using.
You can find the version either in the first line of the `configure.ac` file or if you're using the Git repository, please run `git describe --always --tags --dirty`.
Also, please include the compiler, the compiler version, the architecture, the OS and what version of the OS you're experiencing the issue.
-->

View File

@@ -1,131 +0,0 @@
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
linux-tests:
runs-on: ubuntu-20.04
strategy:
matrix:
valgrind:
- { configure: '' , make: 'check' }
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
options:
- { configure: '' }
- { configure: '--without-libxml2' }
- { configure: '--with-libxml2' }
- { configure: '--with-gnutls' }
- { configure: '--disable-tls' }
- { configure: '--enable-cares' }
- { configure: '--disable-getrandom' }
name: Regular Tests
steps:
- uses: actions/checkout@v2
- name: install dependencies
run: |
sudo apt update
sudo apt install -y libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libgnutls28-dev libc-ares-dev valgrind
- name: Build the library
run: |
./bootstrap.sh
./configure ${{ matrix.options.configure }} ${{ matrix.valgrind.configure }} CFLAGS="-Werror -g3"
make -j$(nproc)
- name: Run tests
run: |
make -j$(nproc) ${{ matrix.valgrind.make }}
- name: Error logs
if: ${{ failure() }}
run: |
cat test-suite*.log || true
xssl-tests:
runs-on: ubuntu-22.04
strategy:
matrix:
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: 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 the TLS stack
env:
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}/xssl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
make -j$(nproc)
- name: Run tests
run: |
make -j$(nproc) ${{ matrix.valgrind.make }}
- name: Error logs
if: ${{ failure() }}
run: |
cat test-suite*.log || true
release-test:
runs-on: ubuntu-20.04
name: Check if release would work
steps:
- uses: actions/checkout@v2
- name: install dependencies
run: |
sudo apt update
sudo apt install -y libtool pkg-config libexpat1-dev
- name: Setup the library
run: |
./bootstrap.sh
./configure
- name: Try release & tests
run: |
make test-release
- name: Show logs from release build
if: ${{ !failure() }}
run: |
cat testbuild.log
code-style:
runs-on: ubuntu-20.04
name: Check coding style
continue-on-error: true
steps:
- uses: actions/checkout@v2
- name: install dependencies
run: |
sudo apt update
sudo apt install -y libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libgnutls28-dev libc-ares-dev dos2unix
- name: Configure
run: |
./bootstrap.sh
./configure
- name: Check style
run: |
make format
git diff --exit-code

20
.gitignore vendored
View File

@@ -20,8 +20,6 @@ autom4te.cache
.dirstamp .dirstamp
.deps .deps
.sconsign* .sconsign*
src/*.gcda
src/*.gcno
src/*.o src/*.o
src/*.lo src/*.lo
examples/*.o examples/*.o
@@ -29,8 +27,6 @@ examples/*.o
*.la *.la
*.pc *.pc
*.tar.gz *.tar.gz
*.tar.bz2
*.tar.xz
*.zip *.zip
docs/html docs/html
TAGS TAGS
@@ -38,25 +34,19 @@ tags
examples/active examples/active
examples/basic examples/basic
examples/bot examples/bot
examples/complex
examples/component examples/component
examples/perf
examples/register examples/register
examples/roster examples/roster
examples/uuid examples/uuid
examples/vcard examples/vcard
testbuild*.log
test-release/
test_stamp test_stamp
test-suite*.log test-suite.log
tests/*.o tests/*.o
tests/*.log tests/*.log
tests/*.trs tests/*.trs
tests/check_parser tests/check_parser
tests/test_base64 tests/test_base64
tests/test_ctx tests/test_ctx
tests/test_fuzz_parser
tests/test_fuzz_resolver
tests/test_hash tests/test_hash
tests/test_jid tests/test_jid
tests/test_md5 tests/test_md5
@@ -64,7 +54,6 @@ tests/test_rand
tests/test_resolver tests/test_resolver
tests/test_sasl tests/test_sasl
tests/test_scram tests/test_scram
tests/test_send_queue
tests/test_sha1 tests/test_sha1
tests/test_sha256 tests/test_sha256
tests/test_sha512 tests/test_sha512
@@ -73,8 +62,7 @@ tests/test_sock
tests/test_stanza tests/test_stanza
tests/test_string tests/test_string
tests/test_xmppaddr tests/test_xmppaddr
m4/lt* m4/
m4/libtool*
libstrophe.project libstrophe.project
libs/ libs/
obj/ obj/
@@ -82,7 +70,3 @@ expat/
.settings/ .settings/
.project .project
.cproject .cproject
coverage/
coverage.info
configure~
fuzz-*.log

26
.travis.yml Normal file
View File

@@ -0,0 +1,26 @@
language: c
dist: focal
install:
- sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libgnutls28-dev libc-ares-dev dos2unix
stages:
- style
- test
env:
- CONFIGURE_OPT="--without-libxml2"
- CONFIGURE_OPT="--with-libxml2"
- CONFIGURE_OPT="--with-gnutls"
- CONFIGURE_OPT="--disable-tls"
- CONFIGURE_OPT="--enable-cares"
- CONFIGURE_OPT="PKG_CONFIG_PATH=${HOME}/libressl/lib/pkgconfig" LIBRESSL=yes LIBRESSL_COMMIT="v3.1.4"
- CONFIGURE_OPT="PKG_CONFIG_PATH=${HOME}/libressl/lib/pkgconfig" LIBRESSL=yes LIBRESSL_COMMIT="v2.1.7"
before_script: ./travis/before_script.sh
script: ./bootstrap.sh && ./configure ${CONFIGURE_OPT} CFLAGS="-Werror -g3" && make && make check
jobs:
include:
- stage: style
name: "Check coding style"
env: CONFIGURE_OPT=""
script: ./bootstrap.sh && ./configure && make format && git diff --exit-code
allow_failures:
- stage: style

View File

@@ -1,59 +1,3 @@
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)
- Do proper SO versioning
- Add code coverage support (#188)
- Add support for password-protected TLS key & PKCS#12/PFX files (#195, #205)
- Stream-Management support - XEP-0198 (#184)
- New API:
- xmpp_conn_send_queue_len()
- xmpp_conn_send_queue_drop_element()
- xmpp_conn_get_sm_state()
- xmpp_conn_set_sm_state()
- xmpp_free_sm_state()
- xmpp_conn_get_keyfile()
- xmpp_conn_set_password_callback()
- xmpp_conn_set_password_retries()
- xmpp_stanza_get_child_by_path()
- xmpp_conn_set_sockopt_callback()
- xmpp_sockopt_cb_keepalive()
- The following APIs were public in the shared library, but not in `strophe.h`.
Now they are officially public API:
- xmpp_rand_new()
- xmpp_rand_free()
- xmpp_rand()
- xmpp_rand_bytes()
- xmpp_rand_nonce()
- xmpp_rand_bytes()
- The following APIs were public in the shared library, but not in `strophe.h`.
In a future version of the library they will be private without replacement:
- xmpp_alloc()
- xmpp_realloc()
- xmpp_strdup()
- xmpp_strndup()
- xmpp_strtok_r()
- xmpp_snprintf()
- xmpp_vsnprintf()
- xmpp_log()
- xmpp_error()
- xmpp_warn()
- xmpp_info()
- xmpp_debug()
- xmpp_debug_verbose()
- Deprecated the following API:
- xmpp_conn_set_keepalive() - replaced by xmpp_conn_set_sockopt_callback()
0.11.0 0.11.0
- SASL EXTERNAL support (XEP-0178) - SASL EXTERNAL support (XEP-0178)
- Client certificate can be provided for TLS negotiation. If the - Client certificate can be provided for TLS negotiation. If the
@@ -61,22 +5,10 @@
xmpp_conn_set_jid(), the xmppAddr is chosen as JID xmpp_conn_set_jid(), the xmppAddr is chosen as JID
- <stream> element contains "from" attribute over TLS connections now - <stream> element contains "from" attribute over TLS connections now
- GnuTLS can be selected optionally with configure script - GnuTLS can be selected optionally with configure script
- Support for manual certificate verification
- New API: - New API:
- xmpp_conn_set_client_cert() - xmpp_conn_set_client_cert()
- xmpp_conn_cert_xmppaddr_num() - xmpp_conn_cert_xmppaddr_num()
- xmpp_conn_cert_xmppaddr() - xmpp_conn_cert_xmppaddr()
- xmpp_conn_set_cafile()
- xmpp_conn_set_capath()
- xmpp_conn_set_certfail_handler()
- xmpp_conn_get_peer_cert()
- xmpp_tlscert_get_ctx()
- xmpp_tlscert_get_conn()
- xmpp_tlscert_get_pem()
- xmpp_tlscert_get_dnsname()
- xmpp_tlscert_get_string()
- xmpp_tlscert_get_description()
- xmpp_tlscert_free()
0.10.1 0.10.1
- Fixed compilation error when LibreSSL is used - Fixed compilation error when LibreSSL is used

913
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -2,11 +2,6 @@ AUTOMAKE_OPTIONS = subdir-objects
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
COVERAGE_CFLAGS=@COVERAGE_CFLAGS@
COVERAGE_LDFLAGS=@COVERAGE_LDFLAGS@
COVERAGE_PRE=@COVERAGE_PRE@
COVERAGE_POST=@COVERAGE_POST@
PARSER_CFLAGS=@PARSER_CFLAGS@ PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@ PARSER_LIBS=@PARSER_LIBS@
@@ -14,35 +9,30 @@ if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@ SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@ SSL_LIBS = @gnutls_LIBS@
else else
if !TLS_WITH_SCHANNEL
SSL_CFLAGS = @openssl_CFLAGS@ SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@ SSL_LIBS = @openssl_LIBS@
endif endif
endif
MINGW_LIBS = @MINGW_LIBS@
RESOLV_CFLAGS = @RESOLV_CFLAGS@ RESOLV_CFLAGS = @RESOLV_CFLAGS@
RESOLV_LIBS = @RESOLV_LIBS@ RESOLV_LIBS = @RESOLV_LIBS@
WARNING_FLAGS = @WARNING_FLAGS@ WARNING_FLAGS = @WARNING_FLAGS@
STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS) STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS)
STROPHE_LIBS = $(COVERAGE_PRE) libstrophe.la $(COVERAGE_POST) $(COVERAGE_LDFLAGS) STROPHE_LIBS = libstrophe.la
## Main build targets ## Main build targets
lib_LTLIBRARIES = libstrophe.la lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS) libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) -no-undefined libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
# Export only public API # Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@ libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
libstrophe_la_SOURCES = \ libstrophe_la_SOURCES = \
src/auth.c \ src/auth.c \
src/conn.c \ src/conn.c \
src/crypto.c \ src/crypto.c \
src/ctx.c \ src/ctx.c \
src/deprecated.c \
src/event.c \ src/event.c \
src/handler.c \ src/handler.c \
src/hash.c \ src/hash.c \
@@ -55,9 +45,9 @@ libstrophe_la_SOURCES = \
src/sha1.c \ src/sha1.c \
src/sha256.c \ src/sha256.c \
src/sha512.c \ src/sha512.c \
src/snprintf.c \
src/sock.c \ src/sock.c \
src/stanza.c \ src/stanza.c \
src/tls.c \
src/util.c \ src/util.c \
src/uuid.c src/uuid.c
libstrophe_la_SOURCES += \ libstrophe_la_SOURCES += \
@@ -66,6 +56,7 @@ libstrophe_la_SOURCES += \
src/md5.h \ src/md5.h \
src/ostypes.h \ src/ostypes.h \
src/parser.h \ src/parser.h \
src/rand.h \
src/resolver.h \ src/resolver.h \
src/sasl.h \ src/sasl.h \
src/scram.h \ src/scram.h \
@@ -78,23 +69,15 @@ libstrophe_la_SOURCES += \
src/tls.h \ src/tls.h \
src/util.h src/util.h
if NEED_SNPRINTF
libstrophe_la_SOURCES += src/snprintf.c
endif
if DISABLE_TLS if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c libstrophe_la_SOURCES += src/tls_dummy.c
else else
if TLS_WITH_GNUTLS if TLS_WITH_GNUTLS
libstrophe_la_SOURCES += src/tls_gnutls.c libstrophe_la_SOURCES += src/tls_gnutls.c
else else
if TLS_WITH_SCHANNEL
libstrophe_la_SOURCES += src/tls_schannel.c
else
libstrophe_la_SOURCES += src/tls_openssl.c libstrophe_la_SOURCES += src/tls_openssl.c
endif endif
endif endif
endif
if PARSER_EXPAT if PARSER_EXPAT
libstrophe_la_SOURCES += src/parser_expat.c libstrophe_la_SOURCES += src/parser_expat.c
@@ -114,32 +97,30 @@ EXTRA_DIST = \
MIT-LICENSE.txt \ MIT-LICENSE.txt \
bootstrap.sh \ bootstrap.sh \
build-android.sh \ build-android.sh \
testbuild.sh \ docs/footer.html \
examples/README.md \ examples/README.md \
jni/Android.mk \ jni/Android.mk \
jni/Application.mk \ jni/Application.mk \
m4/ax_valgrind_check.m4 \ src/tls_schannel.c \
tests/cert.pem \ src/tls_securetransport.c \
tests/cert.pfx \
tests/cert.emptypass.pfx \
tests/cert.nopass.pfx \
tests/key.pem \
tests/key_encrypted.pem \
tests/res_query_dump.c tests/res_query_dump.c
if EXAMPLES if TLS_WITH_GNUTLS
EXTRA_DIST += src/tls_openssl.c
else
EXTRA_DIST += src/tls_gnutls.c
endif
## Examples ## Examples
noinst_PROGRAMS = \ noinst_PROGRAMS = \
examples/active \ examples/active \
examples/basic \ examples/basic \
examples/bot \ examples/bot \
examples/complex \
examples/component \ examples/component \
examples/perf \
examples/register \
examples/roster \ examples/roster \
examples/uuid \ examples/uuid \
examples/vcard examples/vcard \
examples/register
examples_active_SOURCES = examples/active.c examples_active_SOURCES = examples/active.c
examples_active_CFLAGS = $(STROPHE_FLAGS) examples_active_CFLAGS = $(STROPHE_FLAGS)
@@ -150,18 +131,9 @@ examples_basic_LDADD = $(STROPHE_LIBS)
examples_bot_SOURCES = examples/bot.c examples_bot_SOURCES = examples/bot.c
examples_bot_CFLAGS = $(STROPHE_FLAGS) examples_bot_CFLAGS = $(STROPHE_FLAGS)
examples_bot_LDADD = $(STROPHE_LIBS) examples_bot_LDADD = $(STROPHE_LIBS)
examples_complex_SOURCES = examples/complex.c
examples_complex_CFLAGS = $(STROPHE_FLAGS)
examples_complex_LDADD = $(STROPHE_LIBS)
examples_component_SOURCES = examples/component.c examples_component_SOURCES = examples/component.c
examples_component_CFLAGS = $(STROPHE_FLAGS) examples_component_CFLAGS = $(STROPHE_FLAGS)
examples_component_LDADD = $(STROPHE_LIBS) examples_component_LDADD = $(STROPHE_LIBS)
examples_perf_SOURCES = examples/perf.c
examples_perf_CFLAGS = $(STROPHE_FLAGS)
examples_perf_LDADD = $(STROPHE_LIBS)
examples_register_SOURCES = examples/register.c
examples_register_CFLAGS = $(STROPHE_FLAGS)
examples_register_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS) examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS) examples_roster_LDADD = $(STROPHE_LIBS)
@@ -171,7 +143,9 @@ examples_uuid_LDADD = $(STROPHE_LIBS)
examples_vcard_SOURCES = examples/vcard.c examples_vcard_SOURCES = examples/vcard.c
examples_vcard_CFLAGS = $(STROPHE_FLAGS) examples_vcard_CFLAGS = $(STROPHE_FLAGS)
examples_vcard_LDADD = $(STROPHE_LIBS) examples_vcard_LDADD = $(STROPHE_LIBS)
endif examples_register_SOURCES = examples/register.c
examples_register_CFLAGS = $(STROPHE_FLAGS)
examples_register_LDADD = $(STROPHE_LIBS)
## Tests ## Tests
@@ -187,7 +161,6 @@ TESTS = \
tests/test_base64 \ tests/test_base64 \
tests/test_hash \ tests/test_hash \
tests/test_jid \ tests/test_jid \
tests/test_send_queue \
tests/test_snprintf \ tests/test_snprintf \
tests/test_string \ tests/test_string \
tests/test_stanza \ tests/test_stanza \
@@ -199,22 +172,6 @@ endif
check_PROGRAMS = $(TESTS) check_PROGRAMS = $(TESTS)
if FUZZ
check_PROGRAMS += tests/test_fuzz_parser tests/test_fuzz_resolver
tests_test_fuzz_parser_SOURCES = tests/test_fuzz_parser.c
tests_test_fuzz_parser_CFLAGS = -fsanitize=fuzzer,address $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
tests_test_fuzz_parser_LDADD = $(STROPHE_LIBS)
tests_test_fuzz_parser_LDFLAGS = -static
tests_test_fuzz_resolver_SOURCES = tests/test_fuzz_resolver.c
tests_test_fuzz_resolver_CFLAGS = -fsanitize=fuzzer,address $(resolver_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src
tests_test_fuzz_resolver_LDADD = $(STROPHE_LIBS)
tests_test_fuzz_resolver_LDFLAGS = -static
endif
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \ tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
-I$(top_srcdir)/src -I$(top_srcdir)/src
@@ -265,11 +222,6 @@ tests_test_sha512_CFLAGS = -I$(top_srcdir)/src
tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c tests_test_md5_SOURCES = tests/test_md5.c tests/test.c src/md5.c
tests_test_md5_CFLAGS = -I$(top_srcdir)/src tests_test_md5_CFLAGS = -I$(top_srcdir)/src
tests_test_send_queue_SOURCES = tests/test_send_queue.c
tests_test_send_queue_CFLAGS = -I$(top_srcdir)/src
tests_test_send_queue_LDADD = $(STROPHE_LIBS)
tests_test_send_queue_LDFLAGS = -static
tests_test_snprintf_SOURCES = tests/test_snprintf.c tests_test_snprintf_SOURCES = tests/test_snprintf.c
tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src tests_test_snprintf_CFLAGS = -I$(top_srcdir)/src
@@ -278,8 +230,8 @@ tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_string_LDADD = $(STROPHE_LIBS) tests_test_string_LDADD = $(STROPHE_LIBS)
tests_test_string_LDFLAGS = -static tests_test_string_LDFLAGS = -static
tests_test_stanza_SOURCES = tests/test_stanza.c tests/test.h tests_test_stanza_SOURCES = tests/test_stanza.c
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src tests_test_stanza_CFLAGS = $(STROPHE_FLAGS)
tests_test_stanza_LDADD = $(STROPHE_LIBS) tests_test_stanza_LDADD = $(STROPHE_LIBS)
tests_test_stanza_LDFLAGS = -static tests_test_stanza_LDFLAGS = -static
@@ -290,43 +242,5 @@ tests_test_xmppaddr_LDFLAGS = -static
format: format:
@echo " * run clang-format on all sources" @echo " * run clang-format on all sources"
@dos2unix -k -q $(top_srcdir)/src/*.[ch] $(top_srcdir)/*.h $(top_srcdir)/tests/*.[ch] $(top_srcdir)/examples/*.c @dos2unix -q src/*.[ch] *.h tests/*.[ch] examples/*.c
@clang-format -i $(top_srcdir)/src/*.[ch] $(top_srcdir)/*.h $(top_srcdir)/tests/*.[ch] $(top_srcdir)/examples/*.c @clang-format -i src/*.[ch] *.h tests/*.[ch] examples/*.c
if COVERAGE
MOSTLYCLEANFILES = src/*.gcno src/*.gcda coverage.info
clean-local:
-rm -rf coverage/
coverage: check
@lcov --capture --no-external --directory src -q --output-file coverage.info
@genhtml coverage.info --output-directory coverage -q
endif
release: test-release-all
dist-archives:
$(MAKE) dist
$(MAKE) dist-bzip2
$(MAKE) dist-xz
test-release: dist
@touch testbuild-$(PACKAGE_VERSION).log && ln -sf testbuild-$(PACKAGE_VERSION).log testbuild.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
test-release-all: dist-archives
@touch testbuild-$(PACKAGE_VERSION).log && ln -sf testbuild-$(PACKAGE_VERSION).log testbuild.log
@mkdir -p test-release && cp $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.* test-release && pushd test-release && \
tar xJf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.xz && pushd $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && ./testbuild.sh && popd && rm -rf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && \
tar xjf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION).tar.bz2 && pushd $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && ./testbuild.sh && popd && rm -rf $(PACKAGE_TARNAME)-$(PACKAGE_VERSION) && \
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
docs:
@SRCDIR=$(top_srcdir) doxygen -q $(top_srcdir)/Doxyfile
@VALGRIND_CHECK_RULES@
.PHONY: docs test-release

View File

@@ -1,4 +1,4 @@
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 [![Build Status](https://travis-ci.org/strophe/libstrophe.png?branch=master)](https://travis-ci.org/strophe/libstrophe)
========== ==========
libstrophe is a lightweight XMPP client library written in C. It has libstrophe is a lightweight XMPP client library written in C. It has
@@ -42,30 +42,17 @@ another path use the `--prefix` option during configure, e.g.:
Run script `build-android.sh` and follow the instructions. You will Run script `build-android.sh` and follow the instructions. You will
need expat sources and android-ndk. need expat sources and android-ndk.
### Code Coverage
If you want to create a code coverage report, run:
./configure --enable-coverage
make coverage
The coverage report can be found in `./coverage/index.html`.
Requirements Requirements
------------ ------------
libstrophe requires: libstrophe requires:
- expat or libxml2 - expat is the default; use `--with-libxml2` to - expat or libxml2 - expat is the default; use --with-libxml2 to
switch switch
- openssl or GnuTLS on UNIX systems - openssl is default; use - openssl on UNIX systems
`--with-gnutls` to switch
To build libstrophe using autotools you will need `autoconf`, To build libstrophe using autotools you will need autoconf, automake,
`automake`, `libtool` and `pkg-config`. libtool and pkg-config.
To run code coverage analysis you will need `gcov` and `lcov`.
Installation Installation
------------ ------------
@@ -82,17 +69,4 @@ by running:
doxygen doxygen
or if you have everything configured properly:
make docs
Then open `docs/html/index.html`. Then open `docs/html/index.html`.
An online version of the documentation of the latest release is available on http://strophe.im/libstrophe/
Releases
--------
Releases are signed with the GPG key with ID `F8ADC1F9A68A7AFF0E2C89E4391A5EFC2D1709DE`.
It can be found e.g. on https://keys.openpgp.org/

View File

@@ -8,7 +8,6 @@ BinPackParameters: 'false'
BreakBeforeBraces: Linux BreakBeforeBraces: Linux
ColumnLimit: '80' ColumnLimit: '80'
DerivePointerAlignment: 'false' DerivePointerAlignment: 'false'
IndentGotoLabels: false
IndentWidth: '4' IndentWidth: '4'
PointerAlignment: Right PointerAlignment: Right
SortIncludes: 'false' SortIncludes: 'false'

View File

@@ -1,13 +1,4 @@
m4_define([v_maj], [0]) AC_INIT([libstrophe], [0.10.1], [jack@metajack.im])
m4_define([v_min], [12])
m4_define([v_patch], [1])
m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min))
m4_define([lt_rev], v_patch)
m4_define([lt_age], v_min)
AC_INIT([libstrophe], [project_version], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen]) LT_INIT([dlopen])
@@ -25,8 +16,6 @@ AS_CASE([$host_os],
[*solaris*], [PLATFORM="solaris"], [*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"], [*android*], [PLATFORM="android"],
[*haiku*], [PLATFORM="haiku"], [*haiku*], [PLATFORM="haiku"],
[*mingw*], [PLATFORM="win32"
MINGW_LIBS="-lws2_32"],
[PLATFORM="nix"]) [PLATFORM="nix"])
WARNING_FLAGS="-Wall" WARNING_FLAGS="-Wall"
@@ -35,59 +24,17 @@ AS_CASE([$PLATFORM],
[haiku], [], [haiku], [],
[WARNING_FLAGS="$WARNING_FLAGS -Wextra"]) [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], AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])]) [AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_WITH([gnutls], AC_ARG_WITH([gnutls],
[AS_HELP_STRING([--with-gnutls], [use GnuTLS for TLS support, OpenSSL is the default])]) [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], AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])]) [AS_HELP_STRING([--disable-tls], [disable TLS support])])
AC_ARG_ENABLE([cares], AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])]) [AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([getrandom],
[AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])])
AC_ARG_ENABLE([fuzzing],
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
[case "${enableval}" in yes) fuzzing=true ;; no) fuzzing=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-fuzzing]) ;; esac],[fuzzing=false])
AM_CONDITIONAL([FUZZ], [test x$fuzzing = xtrue])
if test "x$enable_fuzzing" = "xyes" ; then
if test "x$CC" != "xclang" ; then
AC_MSG_ERROR(["You need to set CC=clang to use --enable-fuzzing, used $CC"])
fi
fi
AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage], [turn on coverage for tests])],
[case "${enableval}" in yes) coverage=true ;; no) coverage=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-coverage]) ;; esac],[coverage=false])
AM_CONDITIONAL([COVERAGE], [test x$coverage = xtrue])
if test "$enable_coverage" = "yes"; then
COVERAGE_CFLAGS="--coverage -g"
COVERAGE_LDFLAGS="--coverage -lgcov"
COVERAGE_PRE="-Wl,--whole-archive"
COVERAGE_POST="-Wl,--no-whole-archive"
else
COVERAGE_CFLAGS=""
COVERAGE_LDFLAGS=""
COVERAGE_PRE=""
COVERAGE_POST=""
fi
m4_include([m4/ax_valgrind_check.m4])
AX_VALGRIND_DFLT([drd], [off])
AX_VALGRIND_DFLT([helgrind], [off])
AX_VALGRIND_DFLT([sgcheck], [off])
AX_VALGRIND_CHECK
AC_SEARCH_LIBS([socket], [network socket]) AC_SEARCH_LIBS([socket], [network socket])
AC_CHECK_FUNCS([snprintf vsnprintf], [], [have_snprintf=no]) AC_CHECK_FUNCS([snprintf vsnprintf])
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>]) AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
@@ -100,10 +47,6 @@ if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
], ],
[AC_MSG_ERROR([gnutls not found; gnutls required])] [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 elif test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl], PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"], [PC_REQUIRES="openssl ${PC_REQUIRES}"],
@@ -116,12 +59,6 @@ elif test "x$enable_tls" != xno; then
)]) )])
fi fi
AC_CHECK_FUNCS([getrandom], [], [enable_getrandom=no])
if test "$enable_getrandom" = "no"; then
AC_DEFINE(DONT_USE_GETRANDOM)
AC_MSG_NOTICE([libstrophe will not use the getrandom() system call])
fi
with_parser="" with_parser=""
if test "x$with_libxml2" != xyes; then if test "x$with_libxml2" != xyes; then
PKG_CHECK_MODULES([expat], [expat >= 2.0.0], PKG_CHECK_MODULES([expat], [expat >= 2.0.0],
@@ -188,10 +125,8 @@ AS_CASE([$PLATFORM],
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"], [solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
[android], [RESOLV_LIBS=""], [android], [RESOLV_LIBS=""],
[haiku], [RESOLV_LIBS="-lnetwork"], [haiku], [RESOLV_LIBS="-lnetwork"],
[win32], [RESOLV_LIBS=""],
[RESOLV_LIBS="-lresolv"]) [RESOLV_LIBS="-lresolv"])
if test "x$PLATFORM" != xwin32; then
LIBS_TMP="${LIBS}" LIBS_TMP="${LIBS}"
LIBS="${RESOLV_LIBS}" LIBS="${RESOLV_LIBS}"
AC_LINK_IFELSE([AC_LANG_SOURCE([ AC_LINK_IFELSE([AC_LANG_SOURCE([
@@ -210,7 +145,6 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
[AC_MSG_ERROR([res_query() not found with LIBS="${LIBS}"])]) [AC_MSG_ERROR([res_query() not found with LIBS="${LIBS}"])])
LIBS="${LIBS_TMP}" LIBS="${LIBS_TMP}"
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}" PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
fi
fi fi
@@ -223,34 +157,12 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2]) AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno]) 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_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])
AC_DEFINE_UNQUOTED(LIBXMPP_VERSION_MINOR, [v_min], [Minor version])
VMAJ=v_maj
VMIN=v_min
AC_SUBST(VMAJ)
AC_SUBST(VMIN)
# define in package-config file
PC_CFLAGS="${PC_CFLAGS} -DLIBXMPP_VERSION_MAJOR=${VMAJ} -DLIBXMPP_VERSION_MINOR=${VMIN}"
# set the SO version of the installed library
VERSION_INFO="lt_cur:lt_rev:lt_age"
AC_SUBST([VERSION_INFO])
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}]) AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}])
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}]) AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}])
AC_SUBST([PC_LIBS], [${PC_LIBS}]) AC_SUBST([PC_LIBS], [${PC_LIBS}])
AC_SUBST(COVERAGE_CFLAGS)
AC_SUBST(COVERAGE_LDFLAGS)
AC_SUBST(COVERAGE_PRE)
AC_SUBST(COVERAGE_POST)
AC_SUBST(MINGW_LIBS)
AC_SUBST(PARSER_CFLAGS) AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS) AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS) AC_SUBST(RESOLV_CFLAGS)

View File

@@ -15,20 +15,28 @@
#include <strophe.h> #include <strophe.h>
/* hardcoded TCP keepalive timeout and interval */
#define KA_TIMEOUT 60
#define KA_INTERVAL 1
/* define a handler for connection events */ /* define a handler for connection events */
static void conn_handler(xmpp_conn_t *conn, void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status, xmpp_conn_event_t status,
int error, int error,
xmpp_stream_error_t *stream_error, xmpp_stream_error_t *stream_error,
void *userdata) void *userdata)
{ {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata; xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
int secured;
(void)error; (void)error;
(void)stream_error; (void)stream_error;
if (status == XMPP_CONN_CONNECT) { if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n"); fprintf(stderr, "DEBUG: connected\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else { } else {
fprintf(stderr, "DEBUG: disconnected\n"); fprintf(stderr, "DEBUG: disconnected\n");
@@ -43,11 +51,14 @@ static void usage(int exit_code)
"Options:\n" "Options:\n"
" --jid <jid> The JID to use to authenticate.\n" " --jid <jid> The JID to use to authenticate.\n"
" --pass <pass> The password of the JID.\n" " --pass <pass> The password of the JID.\n"
" --tls-cert <cert> Path to client certificate.\n"
" --tls-key <key> Path to private key.\n\n"
" --disable-tls Disable TLS.\n" " --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n" " --mandatory-tls Deny plaintext connection.\n"
" --trust-tls Trust TLS certificate.\n" " --trust-tls Trust TLS certificate.\n"
" --legacy-ssl Use old style SSL.\n" " --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n" " --legacy-auth Allow legacy authentication.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or " "Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n"); "--legacy-ssl\n");
@@ -59,8 +70,9 @@ int main(int argc, char **argv)
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_log_t *log; xmpp_log_t *log;
char *jid = NULL, *password = NULL, *host = NULL; char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL;
long flags = 0; long flags = 0;
int tcp_keepalive = 0;
int i; int i;
unsigned long port = 0; unsigned long port = 0;
@@ -78,14 +90,20 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL; flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0) else if (strcmp(argv[i], "--legacy-auth") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH; flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc)) else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i]; jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc)) else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
password = argv[i]; password = argv[i];
else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc))
cert = argv[i];
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
key = argv[i];
else else
break; break;
} }
if ((!jid) || (argc - i) > 2) { if ((!jid && (!cert || !key)) || (argc - i) > 2) {
usage(1); usage(1);
} }
@@ -112,8 +130,14 @@ int main(int argc, char **argv)
/* configure connection properties (optional) */ /* configure connection properties (optional) */
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */
if (tcp_keepalive)
xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
/* setup authentication information */ /* setup authentication information */
if (cert && key) {
xmpp_conn_set_client_cert(conn, cert, key);
}
if (jid) if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_jid(conn, jid);
if (password) if (password)

View File

@@ -19,17 +19,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#ifdef _WIN32
#include <conio.h>
#include <ctype.h>
#endif
#include <strophe.h> #include <strophe.h>
static int reconnect;
int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t *reply, *query, *name, *version, *text; xmpp_stanza_t *reply, *query, *name, *version, *text;
@@ -103,10 +95,6 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (strcmp(intext, "quit") == 0) { if (strcmp(intext, "quit") == 0) {
replytext = strdup("bye!"); replytext = strdup("bye!");
quit = 1; quit = 1;
} else if (strcmp(intext, "reconnect") == 0) {
replytext = strdup("alright, let's see what happens!");
reconnect = 1;
quit = 1;
} else { } else {
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1); replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext); strcpy(replytext, intext);
@@ -154,116 +142,21 @@ 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 = getpassword("Please enter password: ", pw_max);
if (!pass)
return -1;
size_t passlen = strlen(pass);
int ret;
if (passlen >= pw_max) {
ret = -1;
goto out;
}
ret = passlen + 1;
memcpy(pw, pass, ret);
out:
memset(pass, 0, passlen);
return ret;
}
static void usage(int exit_code)
{
fprintf(stderr,
"Usage: bot [options] <jid> <pass>\n\n"
"Options:\n"
" --jid <jid> The JID to use to authenticate.\n"
" --pass <pass> The password of the JID.\n"
" --tls-cert <cert> Path to client certificate.\n"
" --tls-key <key> Path to private key or P12 file.\n\n"
" --tcp-keepalive Configure TCP keepalive.\n"
" --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n"
" --trust-tls Trust TLS certificate.\n"
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
exit(exit_code);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_log_t *log; xmpp_log_t *log;
xmpp_sm_state_t *sm_state = NULL; char *jid, *pass;
char *jid = NULL, *password = NULL, *host = NULL, *cert = NULL, *key = NULL;
long flags = 0;
int i, tcp_keepalive = 0;
unsigned long port = 0;
/* take a jid and password on the command line */ /* take a jid and password on the command line */
for (i = 1; i < argc; ++i) { if (argc != 3) {
if (strcmp(argv[i], "--help") == 0) fprintf(stderr, "Usage: bot <jid> <pass>\n\n");
usage(0); return 1;
else if (strcmp(argv[i], "--disable-tls") == 0)
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
else if (strcmp(argv[i], "--mandatory-tls") == 0)
flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
else if (strcmp(argv[i], "--trust-tls") == 0)
flags |= XMPP_CONN_FLAG_TRUST_TLS;
else if (strcmp(argv[i], "--legacy-ssl") == 0)
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], "--jid") == 0) && (++i < argc))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
password = argv[i];
else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc))
cert = argv[i];
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
key = argv[i];
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1;
else
break;
}
if ((!jid && !key) || (argc - i) > 2) {
usage(1);
} }
if (i < argc) jid = argv[1];
host = argv[i]; pass = argv[2];
if (i + 1 < argc)
port = strtoul(argv[i + 1], NULL, 0);
/* init library */ /* init library */
xmpp_initialize(); xmpp_initialize();
@@ -273,55 +166,29 @@ int main(int argc, char **argv)
/* create a context */ /* create a context */
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
create_connection:
reconnect = 0;
/* create a connection */ /* create a connection */
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
/* configure connection properties (optional) */ /*
xmpp_conn_set_flags(conn, flags); * also you can disable TLS support or force legacy SSL
* connection without STARTTLS
*
* see xmpp_conn_set_flags() or examples/basic.c
*/
/* ask for a password if key is protected */
xmpp_conn_set_password_callback(conn, password_callback, NULL);
/* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_password_retries(conn, 3);
/* setup authentication information */ /* setup authentication information */
if (key)
xmpp_conn_set_client_cert(conn, cert, key);
if (jid)
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_jid(conn, jid);
if (password) xmpp_conn_set_pass(conn, pass);
xmpp_conn_set_pass(conn, password);
/* enable TCP keepalive, using canned callback function */
if (tcp_keepalive)
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
/* set Stream-Mangement state if available */
if (sm_state) {
xmpp_conn_set_sm_state(conn, sm_state);
sm_state = NULL;
}
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);
/* enter the event loop - /* enter the event loop -
our connect handler will trigger an exit */ our connect handler will trigger an exit */
xmpp_run(ctx); xmpp_run(ctx);
}
/* save the Stream-Mangement state if we should re-connect */ /* release our connection and context */
if (reconnect)
sm_state = xmpp_conn_get_sm_state(conn);
/* release our connection */
xmpp_conn_release(conn); xmpp_conn_release(conn);
if (reconnect)
goto create_connection;
/* release our context */
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
/* final shutdown of the library */ /* final shutdown of the library */

View File

@@ -1,364 +0,0 @@
/* complex.c
** libstrophe XMPP client library -- more complex usage example
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef _WIN32
#include <conio.h>
#include <ctype.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <mstcpip.h> /* tcp_keepalive */
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#include <strophe.h>
/* hardcoded TCP keepalive timeout and interval */
#define KA_TIMEOUT 60
#define KA_INTERVAL 30
#define KA_COUNT 3
#define USER_TIMEOUT 150
static void print_tlscert(const xmpp_tlscert_t *cert)
{
const char *name;
size_t n;
for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) {
printf("\t%32s: %s\n", xmpp_tlscert_get_description(n),
xmpp_tlscert_get_string(cert, n));
}
n = 0;
while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL)
printf("\t%32s: %s\n", "dnsName", name);
printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert));
}
/* define a handler for connection events */
static void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
int secured;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
if (secured) {
xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn);
print_tlscert(cert);
xmpp_tlscert_free(cert);
}
xmpp_disconnect(conn);
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
}
static int certfail_handler(const xmpp_tlscert_t *cert,
const char *const errormsg)
{
char read_char[16] = {0};
printf("Received certificate can't be validated!\n");
printf("Reason: %s\n", errormsg);
print_tlscert(cert);
printf("Do you agree to connect?\n[y(es)|n(o)]: ");
fflush(stdout);
if (fgets(read_char, sizeof(read_char), stdin) == NULL) {
printf("fgets() failed\n");
return 0;
}
printf("\n");
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 = getpassword("Please enter password: ", pw_max);
if (!pass)
return -1;
size_t passlen = strlen(pass);
int ret;
if (passlen >= pw_max) {
ret = -1;
goto out;
}
ret = passlen + 1;
memcpy(pw, pass, ret);
out:
memset(pass, 0, passlen);
return ret;
}
static int sockopt_cb(xmpp_conn_t *conn, void *socket)
{
int timeout = KA_TIMEOUT;
int interval = KA_INTERVAL;
int count = KA_COUNT;
unsigned int user_timeout = USER_TIMEOUT;
int ret;
int optval = (timeout && interval) ? 1 : 0;
(void)conn;
#ifdef _WIN32
(void)count;
(void)user_timeout;
SOCKET sock = *((SOCKET *)socket);
struct tcp_keepalive ka;
DWORD dw = 0;
ka.onoff = optval;
ka.keepalivetime = timeout * 1000;
ka.keepaliveinterval = interval * 1000;
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw,
NULL, NULL);
#else
int sock = *((int *)socket);
fprintf(stderr, "DEBUG: setting socket options\n");
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
if (ret < 0)
return ret;
if (optval) {
#ifdef TCP_KEEPIDLE
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout,
sizeof(timeout));
#elif defined(TCP_KEEPALIVE)
/* QNX receives `struct timeval' as argument, but it seems OSX does int
*/
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &timeout,
sizeof(timeout));
#endif /* TCP_KEEPIDLE */
if (ret < 0)
return ret;
#ifdef TCP_KEEPINTVL
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval,
sizeof(interval));
if (ret < 0)
return ret;
#endif /* TCP_KEEPINTVL */
}
if (count) {
#ifdef TCP_KEEPCNT
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count));
if (ret < 0)
return ret;
#endif /* TCP_KEEPCNT */
}
if (user_timeout) {
#ifdef TCP_USER_TIMEOUT
ret = setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout,
sizeof(user_timeout));
if (ret < 0)
return ret;
#elif defined(TCP_RXT_CONNDROPTIME)
int rxt = user_timeout / 1000;
ret = setsockopt(sock, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, &rxt,
sizeof(rxt));
if (ret < 0)
return ret;
#endif /* TCP_USER_TIMEOUT */
}
#endif /* _WIN32 */
return ret;
}
static void usage(int exit_code)
{
fprintf(stderr,
"Usage: complex [options] [<host> [<port>]]\n\n"
"Options:\n"
" --jid <jid> The JID to use to authenticate.\n"
" --pass <pass> The password of the JID.\n"
" --tls-cert <cert> Path to client certificate.\n"
" --tls-key <key> Path to private key or P12 file.\n\n"
" --capath <path> Path to an additional CA trust store "
"(directory).\n"
" --cafile <path> Path to an additional CA trust store "
"(single file).\n"
" --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n"
" --trust-tls Trust TLS certificate.\n"
" --enable-certfail Enable certfail handler.\n"
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
" --verbose Increase the verbosity level.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
exit(exit_code);
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL,
*capath = NULL, *cafile = NULL;
long flags = 0;
int tcp_keepalive = 0, verbosity = 0, certfail = 0;
int i;
unsigned long port = 0;
/* take a jid and password on the command line */
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--help") == 0)
usage(0);
else if (strcmp(argv[i], "--disable-tls") == 0)
flags |= XMPP_CONN_FLAG_DISABLE_TLS;
else if (strcmp(argv[i], "--mandatory-tls") == 0)
flags |= XMPP_CONN_FLAG_MANDATORY_TLS;
else if (strcmp(argv[i], "--trust-tls") == 0)
flags |= XMPP_CONN_FLAG_TRUST_TLS;
else if (strcmp(argv[i], "--legacy-ssl") == 0)
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], "--verbose") == 0)
verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1;
else if (strcmp(argv[i], "--enable-certfail") == 0)
certfail = 1;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
password = argv[i];
else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc))
cert = argv[i];
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
key = argv[i];
else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc))
capath = argv[i];
else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc))
cafile = argv[i];
else
break;
}
if ((!jid && !key) || (argc - i) > 2) {
usage(1);
}
if (i < argc)
host = argv[i];
if (i + 1 < argc)
port = strtoul(argv[i + 1], NULL, 0);
/*
* Note, this example doesn't handle errors. Applications should check
* return values of non-void functions.
*/
/* init library */
xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */
ctx = xmpp_ctx_new(NULL, log);
xmpp_ctx_set_verbosity(ctx, verbosity);
/* create a connection */
conn = xmpp_conn_new(ctx);
/* configure connection properties (optional) */
xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */
if (tcp_keepalive)
xmpp_conn_set_sockopt_callback(conn, sockopt_cb);
/* ask for a password if key is protected */
xmpp_conn_set_password_callback(conn, password_callback, NULL);
/* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_password_retries(conn, 3);
/* setup authentication information */
if (key) {
xmpp_conn_set_client_cert(conn, cert, key);
}
if (jid)
xmpp_conn_set_jid(conn, jid);
if (password)
xmpp_conn_set_pass(conn, password);
if (certfail)
xmpp_conn_set_certfail_handler(conn, certfail_handler);
if (capath)
xmpp_conn_set_capath(conn, capath);
if (cafile)
xmpp_conn_set_cafile(conn, cafile);
/* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {
/* enter the event loop -
our connect handler will trigger an exit */
xmpp_run(ctx);
}
/* release our connection and context */
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
/* final shutdown of the library */
xmpp_shutdown();
return 0;
}

View File

@@ -1,164 +0,0 @@
/* perf.c
* strophe XMPP client library -- performance measure
*
* Copyright (C) 2022 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 and GPLv3 licenses.
*/
/** @file
* performance measure
*
* Timing code shamelessly borrowed from libtomcrypt/demos/timing.c
*/
#include <strophe.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
static void init_timer(void);
static void t_start(void);
static uint64_t t_read(void);
static void perf_rand(xmpp_ctx_t *ctx)
{
xmpp_rand_t *rng = xmpp_rand_new(ctx);
uint64_t t1, t2;
unsigned int n;
const size_t alloc_sz = 0x1000u;
size_t sz;
unsigned char *buf = malloc(alloc_sz);
/* pre-heat */
for (n = 1; n < 4; ++n) {
xmpp_rand_bytes(rng, buf, n * 10);
}
for (sz = 2; sz <= alloc_sz; sz <<= 1) {
t2 = 0;
for (n = 0; n < 1000u; ++n) {
t_start();
t1 = t_read();
xmpp_rand_bytes(rng, buf, sz);
t1 = t_read() - t1;
t2 += t1;
}
t2 /= 1000;
fprintf(stderr,
"Reading %6zu bytes from PRNG took %8" PRIu64 " cycles\n", sz,
t2);
}
free(buf);
xmpp_rand_free(ctx, rng);
}
int main()
{
/* pass NULL instead to silence output */
xmpp_log_t *log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */
xmpp_ctx_t *ctx = xmpp_ctx_new(NULL, log);
init_timer();
perf_rand(ctx);
return 0;
}
#define TIMES 100000
static uint64_t timer, skew = 0;
/* RDTSC from Scott Duplichan */
static uint64_t rdtsc(void)
{
#if defined __GNUC__
#if defined(__i386__) || defined(__x86_64__)
/* version from http://www.mcs.anl.gov/~kazutomo/rdtsc.html
* the old code always got a warning issued by gcc, clang did not
* complain...
*/
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)
unsigned long a, b;
__asm__ __volatile__("mftbu %1 \nmftb %0\n" : "=r"(a), "=r"(b));
return (((uint64_t)b) << 32ULL) | ((uint64_t)a);
#elif defined(__ia64__) /* gcc-IA64 version */
unsigned long result;
__asm__ __volatile__("mov %0=ar.itc" : "=r"(result)::"memory");
while (__builtin_expect((int)result == -1, 0))
__asm__ __volatile__("mov %0=ar.itc" : "=r"(result)::"memory");
return result;
#elif defined(__sparc__)
#if defined(__arch64__)
uint64_t a;
asm volatile("rd %%tick,%0" : "=r"(a));
return a;
#else
register unsigned long x, y;
__asm__ __volatile__("rd %%tick, %0; clruw %0, %1; srlx %0, 32, %0"
: "=r"(x), "=r"(y)
: "0"(x), "1"(y));
return ((unsigned long long)x << 32) | y;
#endif
#elif defined(__aarch64__)
uint64_t CNTVCT_EL0;
__asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(CNTVCT_EL0));
return CNTVCT_EL0;
#else
return clock();
#endif
/* Microsoft and Intel Windows compilers */
#elif defined _M_IX86 && !defined(LTC_NO_ASM)
__asm rdtsc
#elif defined _M_AMD64 && !defined(LTC_NO_ASM)
return __rdtsc();
#elif defined _M_IA64 && !defined(LTC_NO_ASM)
#if defined __INTEL_COMPILER
#include <ia64intrin.h>
#endif
return __getReg(3116);
#else
return clock();
#endif
}
static void t_start(void)
{
timer = rdtsc();
}
static uint64_t t_read(void)
{
return rdtsc() - timer;
}
static void init_timer(void)
{
uint64_t c1, c2, t1, t2;
unsigned long y1;
c1 = c2 = (uint64_t)-1;
for (y1 = 0; y1 < TIMES * 100; y1++) {
t_start();
t1 = t_read();
t2 = (t_read() - t1) >> 1;
c1 = (t1 > c1) ? t1 : c1;
c2 = (t2 > c2) ? t2 : c2;
}
skew = c2 - c1;
fprintf(stderr, "Clock Skew: %lu\n", (unsigned long)skew);
}

View File

@@ -1,239 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_VALGRIND_DFLT(memcheck|helgrind|drd|sgcheck, on|off)
# AX_VALGRIND_CHECK()
#
# DESCRIPTION
#
# AX_VALGRIND_CHECK checks whether Valgrind is present and, if so, allows
# running `make check` under a variety of Valgrind tools to check for
# memory and threading errors.
#
# Defines VALGRIND_CHECK_RULES which should be substituted in your
# Makefile; and $enable_valgrind which can be used in subsequent configure
# output. VALGRIND_ENABLED is defined and substituted, and corresponds to
# the value of the --enable-valgrind option, which defaults to being
# enabled if Valgrind is installed and disabled otherwise. Individual
# Valgrind tools can be disabled via --disable-valgrind-<tool>, the
# default is configurable via the AX_VALGRIND_DFLT command or is to use
# all commands not disabled via AX_VALGRIND_DFLT. All AX_VALGRIND_DFLT
# calls must be made before the call to AX_VALGRIND_CHECK.
#
# If unit tests are written using a shell script and automake's
# LOG_COMPILER system, the $(VALGRIND) variable can be used within the
# shell scripts to enable Valgrind, as described here:
#
# https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html
#
# Usage example:
#
# configure.ac:
#
# AX_VALGRIND_DFLT([sgcheck], [off])
# AX_VALGRIND_CHECK
#
# in each Makefile.am with tests:
#
# @VALGRIND_CHECK_RULES@
# VALGRIND_SUPPRESSIONS_FILES = my-project.supp
# EXTRA_DIST = my-project.supp
#
# This results in a "check-valgrind" rule being added. Running `make
# check-valgrind` in that directory will recursively run the module's test
# suite (`make check`) once for each of the available Valgrind tools (out
# of memcheck, helgrind and drd) while the sgcheck will be skipped unless
# enabled again on the commandline with --enable-valgrind-sgcheck. The
# results for each check will be output to test-suite-$toolname.log. The
# target will succeed if there are zero errors and fail otherwise.
#
# Alternatively, a "check-valgrind-$TOOL" rule will be added, for $TOOL in
# memcheck, helgrind, drd and sgcheck. These are useful because often only
# some of those tools can be ran cleanly on a codebase.
#
# The macro supports running with and without libtool.
#
# LICENSE
#
# Copyright (c) 2014, 2015, 2016 Philip Withnall <philip.withnall@collabora.co.uk>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 23
dnl Configured tools
m4_define([valgrind_tool_list], [[memcheck], [helgrind], [drd], [sgcheck]])
m4_set_add_all([valgrind_exp_tool_set], [sgcheck])
m4_foreach([vgtool], [valgrind_tool_list],
[m4_define([en_dflt_valgrind_]vgtool, [on])])
AC_DEFUN([AX_VALGRIND_DFLT],[
m4_define([en_dflt_valgrind_$1], [$2])
])dnl
AC_DEFUN([AX_VALGRIND_CHECK],[
AM_EXTRA_RECURSIVE_TARGETS([check-valgrind])
m4_foreach([vgtool], [valgrind_tool_list],
[AM_EXTRA_RECURSIVE_TARGETS([check-valgrind-]vgtool)])
dnl Check for --enable-valgrind
AC_ARG_ENABLE([valgrind],
[AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])],
[enable_valgrind=$enableval],[enable_valgrind=])
AS_IF([test "$enable_valgrind" != "no"],[
# Check for Valgrind.
AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind])
AS_IF([test "$VALGRIND" = ""],[
AS_IF([test "$enable_valgrind" = "yes"],[
AC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind])
],[
enable_valgrind=no
])
],[
enable_valgrind=yes
])
])
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
AC_SUBST([VALGRIND_ENABLED],[$enable_valgrind])
# Check for Valgrind tools we care about.
[valgrind_enabled_tools=]
m4_foreach([vgtool],[valgrind_tool_list],[
AC_ARG_ENABLE([valgrind-]vgtool,
m4_if(m4_defn([en_dflt_valgrind_]vgtool),[off],dnl
[AS_HELP_STRING([--enable-valgrind-]vgtool, [Whether to use ]vgtool[ during the Valgrind tests])],dnl
[AS_HELP_STRING([--disable-valgrind-]vgtool, [Whether to skip ]vgtool[ during the Valgrind tests])]),
[enable_valgrind_]vgtool[=$enableval],
[enable_valgrind_]vgtool[=])
AS_IF([test "$enable_valgrind" = "no"],[
enable_valgrind_]vgtool[=no],
[test "$enable_valgrind_]vgtool[" ]dnl
m4_if(m4_defn([en_dflt_valgrind_]vgtool), [off], [= "yes"], [!= "no"]),[
AC_CACHE_CHECK([for Valgrind tool ]vgtool,
[ax_cv_valgrind_tool_]vgtool,[
ax_cv_valgrind_tool_]vgtool[=no
m4_set_contains([valgrind_exp_tool_set],vgtool,
[m4_define([vgtoolx],[exp-]vgtool)],
[m4_define([vgtoolx],vgtool)])
AS_IF([`$VALGRIND --tool=]vgtoolx[ --help >/dev/null 2>&1`],[
ax_cv_valgrind_tool_]vgtool[=yes
])
])
AS_IF([test "$ax_cv_valgrind_tool_]vgtool[" = "no"],[
AS_IF([test "$enable_valgrind_]vgtool[" = "yes"],[
AC_MSG_ERROR([Valgrind does not support ]vgtool[; reconfigure with --disable-valgrind-]vgtool)
],[
enable_valgrind_]vgtool[=no
])
],[
enable_valgrind_]vgtool[=yes
])
])
AS_IF([test "$enable_valgrind_]vgtool[" = "yes"],[
valgrind_enabled_tools="$valgrind_enabled_tools ]m4_bpatsubst(vgtool,[^exp-])["
])
AC_SUBST([ENABLE_VALGRIND_]vgtool,[$enable_valgrind_]vgtool)
])
AC_SUBST([valgrind_tools],["]m4_join([ ], valgrind_tool_list)["])
AC_SUBST([valgrind_enabled_tools],[$valgrind_enabled_tools])
[VALGRIND_CHECK_RULES='
# Valgrind check
#
# Optional:
# - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions
# files to load. (Default: empty)
# - VALGRIND_FLAGS: General flags to pass to all Valgrind tools.
# (Default: --num-callers=30)
# - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of:
# memcheck, helgrind, drd, sgcheck). (Default: various)
# Optional variables
VALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES))
VALGRIND_FLAGS ?= --num-callers=30
VALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no
VALGRIND_helgrind_FLAGS ?= --history-level=approx
VALGRIND_drd_FLAGS ?=
VALGRIND_sgcheck_FLAGS ?=
# Internal use
valgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools)))
valgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS)
valgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS)
valgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS)
valgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS)
valgrind_quiet = $(valgrind_quiet_$(V))
valgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY))
valgrind_quiet_0 = --quiet
valgrind_v_use = $(valgrind_v_use_$(V))
valgrind_v_use_ = $(valgrind_v_use_$(AM_DEFAULT_VERBOSITY))
valgrind_v_use_0 = @echo " USE " $(patsubst check-valgrind-%-local,%,$''@):;
# Support running with and without libtool.
ifneq ($(LIBTOOL),)
valgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute
else
valgrind_lt =
endif
# Use recursive makes in order to ignore errors during check
check-valgrind-local:
ifeq ($(VALGRIND_ENABLED),yes)
$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k \
$(foreach tool, $(valgrind_enabled_tools), check-valgrind-$(tool))
else
@echo "Need to reconfigure with --enable-valgrind"
endif
# Valgrind running
VALGRIND_TESTS_ENVIRONMENT = \
$(TESTS_ENVIRONMENT) \
env VALGRIND=$(VALGRIND) \
G_SLICE=always-malloc,debug-blocks \
G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly
VALGRIND_LOG_COMPILER = \
$(valgrind_lt) \
$(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS)
define valgrind_tool_rule
check-valgrind-$(1)-local:
ifeq ($$(VALGRIND_ENABLED)-$$(ENABLE_VALGRIND_$(1)),yes-yes)
ifneq ($$(TESTS),)
$$(valgrind_v_use)$$(MAKE) check-TESTS \
TESTS_ENVIRONMENT="$$(VALGRIND_TESTS_ENVIRONMENT)" \
LOG_COMPILER="$$(VALGRIND_LOG_COMPILER)" \
LOG_FLAGS="$$(valgrind_$(1)_flags)" \
TEST_SUITE_LOG=test-suite-$(1).log
endif
else ifeq ($$(VALGRIND_ENABLED),yes)
@echo "Need to reconfigure with --enable-valgrind-$(1)"
else
@echo "Need to reconfigure with --enable-valgrind"
endif
endef
$(foreach tool,$(valgrind_tools),$(eval $(call valgrind_tool_rule,$(tool))))
A''M_DISTCHECK_CONFIGURE_FLAGS ?=
A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind
MOSTLYCLEANFILES ?=
MOSTLYCLEANFILES += $(valgrind_log_files)
.PHONY: check-valgrind $(addprefix check-valgrind-,$(valgrind_tools))
']
AC_SUBST([VALGRIND_CHECK_RULES])
m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])])
])

View File

@@ -21,6 +21,7 @@
#include "common.h" #include "common.h"
#include "sasl.h" #include "sasl.h"
#include "sha1.h" #include "sha1.h"
#include "rand.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define strcasecmp _stricmp #define strcasecmp _stricmp
@@ -92,9 +93,6 @@ static int
_handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata); _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_missing_session(xmpp_conn_t *conn, void *userdata); static int _handle_missing_session(xmpp_conn_t *conn, void *userdata);
static int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata); static int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata);
static int _handle_sm(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata);
/* stream:error handler */ /* stream:error handler */
static int static int
@@ -109,12 +107,12 @@ _handle_error(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (conn->stream_error) { if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza); xmpp_stanza_release(conn->stream_error->stanza);
if (conn->stream_error->text) if (conn->stream_error->text)
strophe_free(conn->ctx, conn->stream_error->text); xmpp_free(conn->ctx, conn->stream_error->text);
strophe_free(conn->ctx, conn->stream_error); xmpp_free(conn->ctx, conn->stream_error);
} }
/* create stream error structure */ /* create stream error structure */
conn->stream_error = (xmpp_stream_error_t *)strophe_alloc( conn->stream_error = (xmpp_stream_error_t *)xmpp_alloc(
conn->ctx, sizeof(xmpp_stream_error_t)); conn->ctx, sizeof(xmpp_stream_error_t));
conn->stream_error->text = NULL; conn->stream_error->text = NULL;
@@ -133,7 +131,7 @@ _handle_error(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
name = xmpp_stanza_get_name(child); name = xmpp_stanza_get_name(child);
if (strcmp(name, "text") == 0) { if (strcmp(name, "text") == 0) {
if (conn->stream_error->text) if (conn->stream_error->text)
strophe_free(conn->ctx, conn->stream_error->text); xmpp_free(conn->ctx, conn->stream_error->text);
conn->stream_error->text = xmpp_stanza_get_text(child); conn->stream_error->text = xmpp_stanza_get_text(child);
} else if (strcmp(name, "bad-format") == 0) } else if (strcmp(name, "bad-format") == 0)
conn->stream_error->type = XMPP_SE_BAD_FORMAT; conn->stream_error->type = XMPP_SE_BAD_FORMAT;
@@ -197,7 +195,7 @@ static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
{ {
UNUSED(userdata); UNUSED(userdata);
strophe_debug(conn->ctx, "xmpp", "didn't get stream features"); xmpp_debug(conn->ctx, "xmpp", "didn't get stream features");
/* legacy auth will be attempted */ /* legacy auth will be attempted */
_auth(conn); _auth(conn);
@@ -245,7 +243,7 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (strcasecmp(text, "PLAIN") == 0) if (strcasecmp(text, "PLAIN") == 0)
conn->sasl_support |= SASL_MASK_PLAIN; conn->sasl_support |= SASL_MASK_PLAIN;
else if (strcasecmp(text, "EXTERNAL") == 0 && else if (strcasecmp(text, "EXTERNAL") == 0 &&
(conn->tls_client_cert || conn->tls_client_key)) conn->tls_client_cert)
conn->sasl_support |= SASL_MASK_EXTERNAL; conn->sasl_support |= SASL_MASK_EXTERNAL;
else if (strcasecmp(text, "DIGEST-MD5") == 0) else if (strcasecmp(text, "DIGEST-MD5") == 0)
conn->sasl_support |= SASL_MASK_DIGESTMD5; conn->sasl_support |= SASL_MASK_DIGESTMD5;
@@ -258,7 +256,7 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
else if (strcasecmp(text, "ANONYMOUS") == 0) else if (strcasecmp(text, "ANONYMOUS") == 0)
conn->sasl_support |= SASL_MASK_ANONYMOUS; conn->sasl_support |= SASL_MASK_ANONYMOUS;
strophe_free(conn->ctx, text); xmpp_free(conn->ctx, text);
} }
} }
} }
@@ -297,10 +295,10 @@ static int _handle_proceedtls_default(xmpp_conn_t *conn,
UNUSED(userdata); UNUSED(userdata);
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
strophe_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name); xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name);
if (strcmp(name, "proceed") == 0) { if (strcmp(name, "proceed") == 0) {
strophe_debug(conn->ctx, "xmpp", "proceeding with TLS"); xmpp_debug(conn->ctx, "xmpp", "proceeding with TLS");
if (conn_tls_start(conn) == 0) { if (conn_tls_start(conn) == 0) {
conn_prepare_reset(conn, _handle_open_tls); conn_prepare_reset(conn, _handle_open_tls);
@@ -323,14 +321,13 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* the server should send a <success> or <failure> stanza */ /* the server should send a <success> or <failure> stanza */
if (strcmp(name, "failure") == 0) { if (strcmp(name, "failure") == 0) {
strophe_debug(conn->ctx, "xmpp", "SASL %s auth failed", xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed", (char *)userdata);
(char *)userdata);
/* fall back to next auth method */ /* fall back to next auth method */
_auth(conn); _auth(conn);
} else if (strcmp(name, "success") == 0) { } else if (strcmp(name, "success") == 0) {
/* SASL auth successful, we need to restart the stream */ /* SASL auth successful, we need to restart the stream */
strophe_debug(conn->ctx, "xmpp", "SASL %s auth successful", xmpp_debug(conn->ctx, "xmpp", "SASL %s auth successful",
(char *)userdata); (char *)userdata);
/* reset parser */ /* reset parser */
@@ -340,7 +337,7 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
conn_open_stream(conn); conn_open_stream(conn);
} else { } else {
/* got unexpected reply */ /* got unexpected reply */
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Got unexpected reply to SASL %s authentication.", "Got unexpected reply to SASL %s authentication.",
(char *)userdata); (char *)userdata);
xmpp_disconnect(conn); xmpp_disconnect(conn);
@@ -362,8 +359,8 @@ static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
UNUSED(userdata); UNUSED(userdata);
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
strophe_debug(conn->ctx, "xmpp", xmpp_debug(conn->ctx, "xmpp", "handle digest-md5 (challenge) called for %s",
"handle digest-md5 (challenge) called for %s", name); name);
if (strcmp(name, "challenge") == 0) { if (strcmp(name, "challenge") == 0) {
text = xmpp_stanza_get_text(stanza); text = xmpp_stanza_get_text(stanza);
@@ -372,7 +369,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0; return 0;
} }
strophe_free(conn->ctx, text); xmpp_free(conn->ctx, text);
auth = xmpp_stanza_new(conn->ctx); auth = xmpp_stanza_new(conn->ctx);
if (!auth) { if (!auth) {
@@ -389,7 +386,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
} }
xmpp_stanza_set_text(authdata, response); xmpp_stanza_set_text(authdata, response);
strophe_free(conn->ctx, response); xmpp_free(conn->ctx, response);
xmpp_stanza_add_child(auth, authdata); xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
@@ -397,7 +394,7 @@ static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL, handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL,
NULL); NULL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
} else { } else {
@@ -419,8 +416,8 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
UNUSED(userdata); UNUSED(userdata);
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
strophe_debug(conn->ctx, "xmpp", xmpp_debug(conn->ctx, "xmpp", "handle digest-md5 (rspauth) called for %s",
"handle digest-md5 (rspauth) called for %s", name); name);
if (strcmp(name, "challenge") == 0) { if (strcmp(name, "challenge") == 0) {
/* assume it's an rspauth response */ /* assume it's an rspauth response */
@@ -431,7 +428,7 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
} }
xmpp_stanza_set_name(auth, "response"); xmpp_stanza_set_name(auth, "response");
xmpp_stanza_set_ns(auth, XMPP_NS_SASL); xmpp_stanza_set_ns(auth, XMPP_NS_SASL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
} else { } else {
return _handle_sasl_result(conn, stanza, "DIGEST-MD5"); return _handle_sasl_result(conn, stanza, "DIGEST-MD5");
@@ -460,7 +457,7 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
int rc; int rc;
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
strophe_debug(conn->ctx, "xmpp", "handle %s (challenge) called for %s", xmpp_debug(conn->ctx, "xmpp", "handle %s (challenge) called for %s",
scram_ctx->alg->scram_name, name); scram_ctx->alg->scram_name, name);
if (strcmp(name, "challenge") == 0) { if (strcmp(name, "challenge") == 0) {
@@ -469,13 +466,13 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
goto err; goto err;
challenge = xmpp_base64_decode_str(conn->ctx, text, strlen(text)); challenge = xmpp_base64_decode_str(conn->ctx, text, strlen(text));
strophe_free(conn->ctx, text); xmpp_free(conn->ctx, text);
if (!challenge) if (!challenge)
goto err; goto err;
response = sasl_scram(conn->ctx, scram_ctx->alg, challenge, response = sasl_scram(conn->ctx, scram_ctx->alg, challenge,
scram_ctx->scram_init, conn->jid, conn->pass); scram_ctx->scram_init, conn->jid, conn->pass);
strophe_free(conn->ctx, challenge); xmpp_free(conn->ctx, challenge);
if (!response) if (!response)
goto err; goto err;
@@ -489,12 +486,12 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
if (!authdata) if (!authdata)
goto err_release_auth; goto err_release_auth;
xmpp_stanza_set_text(authdata, response); xmpp_stanza_set_text(authdata, response);
strophe_free(conn->ctx, response); xmpp_free(conn->ctx, response);
xmpp_stanza_add_child(auth, authdata); xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
rc = 1; /* Keep handler */ rc = 1; /* Keep handler */
@@ -510,8 +507,8 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
*/ */
rc = _handle_sasl_result(conn, stanza, rc = _handle_sasl_result(conn, stanza,
(void *)scram_ctx->alg->scram_name); (void *)scram_ctx->alg->scram_name);
strophe_free(conn->ctx, scram_ctx->scram_init); xmpp_free(conn->ctx, scram_ctx->scram_init);
strophe_free(conn->ctx, scram_ctx); xmpp_free(conn->ctx, scram_ctx);
} }
return rc; return rc;
@@ -519,10 +516,10 @@ static int _handle_scram_challenge(xmpp_conn_t *conn,
err_release_auth: err_release_auth:
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
err_free_response: err_free_response:
strophe_free(conn->ctx, response); xmpp_free(conn->ctx, response);
err: err:
strophe_free(conn->ctx, scram_ctx->scram_init); xmpp_free(conn->ctx, scram_ctx->scram_init);
strophe_free(conn->ctx, scram_ctx); xmpp_free(conn->ctx, scram_ctx);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return 0; return 0;
} }
@@ -541,11 +538,11 @@ static char *_make_scram_init_msg(xmpp_conn_t *conn)
} }
xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce)); xmpp_rand_nonce(ctx->rand, nonce, sizeof(nonce));
message_len = strlen(node) + strlen(nonce) + 8 + 1; message_len = strlen(node) + strlen(nonce) + 8 + 1;
message = strophe_alloc(ctx, message_len); message = xmpp_alloc(ctx, message_len);
if (message) { if (message) {
strophe_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce); xmpp_snprintf(message, message_len, "n,,n=%s,r=%s", node, nonce);
} }
strophe_free(ctx, node); xmpp_free(ctx, node);
return message; return message;
} }
@@ -598,7 +595,7 @@ static void _auth(xmpp_conn_t *conn)
if (str == NULL) { if (str == NULL) {
anonjid = 1; anonjid = 1;
} else { } else {
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
anonjid = 0; anonjid = 0;
} }
@@ -624,7 +621,7 @@ static void _auth(xmpp_conn_t *conn)
handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL, NULL, handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL, NULL,
NULL); NULL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
/* TLS was tried, unset flag */ /* TLS was tried, unset flag */
@@ -634,7 +631,7 @@ static void _auth(xmpp_conn_t *conn)
} }
if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) { if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) {
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"TLS is not supported, but set as " "TLS is not supported, but set as "
"mandatory for this connection"); "mandatory for this connection");
conn_disconnect(conn); conn_disconnect(conn);
@@ -652,7 +649,7 @@ static void _auth(xmpp_conn_t *conn)
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL, handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"ANONYMOUS"); "ANONYMOUS");
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
/* SASL ANONYMOUS was tried, unset flag */ /* SASL ANONYMOUS was tried, unset flag */
@@ -676,7 +673,7 @@ static void _auth(xmpp_conn_t *conn)
strcmp(str, conn->jid) == 0)) { strcmp(str, conn->jid) == 0)) {
xmpp_stanza_set_text(authdata, "="); xmpp_stanza_set_text(authdata, "=");
} else { } else {
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
str = xmpp_base64_encode(conn->ctx, (void *)conn->jid, str = xmpp_base64_encode(conn->ctx, (void *)conn->jid,
strlen(conn->jid)); strlen(conn->jid));
if (!str) { if (!str) {
@@ -687,7 +684,7 @@ static void _auth(xmpp_conn_t *conn)
} }
xmpp_stanza_set_text(authdata, str); xmpp_stanza_set_text(authdata, str);
} }
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
xmpp_stanza_add_child(auth, authdata); xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
@@ -695,22 +692,21 @@ static void _auth(xmpp_conn_t *conn)
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL, handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"EXTERNAL"); "EXTERNAL");
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
/* SASL EXTERNAL was tried, unset flag */ /* SASL EXTERNAL was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_EXTERNAL; conn->sasl_support &= ~SASL_MASK_EXTERNAL;
} else if (anonjid) { } else if (anonjid) {
strophe_error(conn->ctx, "auth", xmpp_error(conn->ctx, "auth",
"No node in JID, and SASL ANONYMOUS unsupported."); "No node in JID, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (conn->pass == NULL) { } else if (conn->pass == NULL) {
strophe_error( xmpp_error(conn->ctx, "auth",
conn->ctx, "auth",
"Password hasn't been set, and SASL ANONYMOUS unsupported."); "Password hasn't been set, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAM) { } else if (conn->sasl_support & SASL_MASK_SCRAM) {
scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx)); scram_ctx = xmpp_alloc(conn->ctx, sizeof(*scram_ctx));
if (conn->sasl_support & SASL_MASK_SCRAMSHA512) if (conn->sasl_support & SASL_MASK_SCRAMSHA512)
scram_ctx->alg = &scram_sha512; scram_ctx->alg = &scram_sha512;
else if (conn->sasl_support & SASL_MASK_SCRAMSHA256) else if (conn->sasl_support & SASL_MASK_SCRAMSHA256)
@@ -726,7 +722,7 @@ static void _auth(xmpp_conn_t *conn)
/* don't free scram_init on success */ /* don't free scram_init on success */
scram_ctx->scram_init = _make_scram_init_msg(conn); scram_ctx->scram_init = _make_scram_init_msg(conn);
if (!scram_ctx->scram_init) { if (!scram_ctx->scram_init) {
strophe_free(conn->ctx, scram_ctx); xmpp_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return; return;
@@ -736,8 +732,8 @@ static void _auth(xmpp_conn_t *conn)
(unsigned char *)scram_ctx->scram_init, (unsigned char *)scram_ctx->scram_init,
strlen(scram_ctx->scram_init)); strlen(scram_ctx->scram_init));
if (!str) { if (!str) {
strophe_free(conn->ctx, scram_ctx->scram_init); xmpp_free(conn->ctx, scram_ctx->scram_init);
strophe_free(conn->ctx, scram_ctx); xmpp_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return; return;
@@ -745,22 +741,22 @@ static void _auth(xmpp_conn_t *conn)
authdata = xmpp_stanza_new(conn->ctx); authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) { if (!authdata) {
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
strophe_free(conn->ctx, scram_ctx->scram_init); xmpp_free(conn->ctx, scram_ctx->scram_init);
strophe_free(conn->ctx, scram_ctx); xmpp_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
disconnect_mem_error(conn); disconnect_mem_error(conn);
return; return;
} }
xmpp_stanza_set_text(authdata, str); xmpp_stanza_set_text(authdata, str);
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
xmpp_stanza_add_child(auth, authdata); xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
handler_add(conn, _handle_scram_challenge, XMPP_NS_SASL, NULL, NULL, handler_add(conn, _handle_scram_challenge, XMPP_NS_SASL, NULL, NULL,
(void *)scram_ctx); (void *)scram_ctx);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
/* SASL SCRAM-SHA-1 was tried, unset flag */ /* SASL SCRAM-SHA-1 was tried, unset flag */
@@ -775,7 +771,7 @@ static void _auth(xmpp_conn_t *conn)
handler_add(conn, _handle_digestmd5_challenge, XMPP_NS_SASL, NULL, NULL, handler_add(conn, _handle_digestmd5_challenge, XMPP_NS_SASL, NULL, NULL,
NULL); NULL);
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
/* SASL DIGEST-MD5 was tried, unset flag */ /* SASL DIGEST-MD5 was tried, unset flag */
@@ -802,8 +798,8 @@ static void _auth(xmpp_conn_t *conn)
return; return;
} }
xmpp_stanza_set_text(authdata, str); xmpp_stanza_set_text(authdata, str);
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
strophe_free(conn->ctx, authid); xmpp_free(conn->ctx, authid);
xmpp_stanza_add_child(auth, authdata); xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
@@ -811,7 +807,7 @@ static void _auth(xmpp_conn_t *conn)
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL, handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"PLAIN"); "PLAIN");
send_stanza(conn, auth, XMPP_QUEUE_STROPHE); xmpp_send(conn, auth);
xmpp_stanza_release(auth); xmpp_stanza_release(auth);
/* SASL PLAIN was tried */ /* SASL PLAIN was tried */
@@ -820,20 +816,11 @@ static void _auth(xmpp_conn_t *conn)
/* legacy client authentication */ /* legacy client authentication */
_auth_legacy(conn); _auth_legacy(conn);
} else { } else {
strophe_error(conn->ctx, "auth", xmpp_error(conn->ctx, "auth", "Cannot authenticate with known methods");
"Cannot authenticate with known methods");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
} }
static void _auth_success(xmpp_conn_t *conn)
{
tls_clear_password_cache(conn);
conn->authenticated = 1;
/* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
}
/** Set up handlers at stream start. /** Set up handlers at stream start.
* This function is called internally to Strophe for handling the opening * This function is called internally to Strophe for handling the opening
* of an XMPP stream. It's called by the parser when a stream is opened * of an XMPP stream. It's called by the parser when a stream is opened
@@ -870,7 +857,7 @@ static void _handle_open_tls(xmpp_conn_t *conn)
/* called when stream:stream tag received after SASL auth */ /* called when stream:stream tag received after SASL auth */
static void _handle_open_sasl(xmpp_conn_t *conn) static void _handle_open_sasl(xmpp_conn_t *conn)
{ {
strophe_debug(conn->ctx, "xmpp", "Reopened stream successfully."); xmpp_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
/* setup stream:features handlers */ /* setup stream:features handlers */
handler_add(conn, _handle_features_sasl, XMPP_NS_STREAMS, "features", NULL, handler_add(conn, _handle_features_sasl, XMPP_NS_STREAMS, "features", NULL,
@@ -879,11 +866,42 @@ static void _handle_open_sasl(xmpp_conn_t *conn)
NULL); NULL);
} }
static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind) static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t *iq, *res, *text; xmpp_stanza_t *bind, *session, *iq, *res, *text, *opt;
const char *ns;
char *resource; char *resource;
UNUSED(userdata);
/* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
/* we are expecting <bind/> and <session/> since this is a
XMPP style connection */
/* check whether resource binding is required */
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
if (bind) {
ns = xmpp_stanza_get_ns(bind);
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
}
/* check whether session establishment is required */
session = xmpp_stanza_get_child_by_name(stanza, "session");
if (session) {
ns = xmpp_stanza_get_ns(session);
opt = xmpp_stanza_get_child_by_name(session, "optional");
if (!opt)
conn->session_required =
ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
}
/* if bind is required, go ahead and start it */
if (conn->bind_required) {
/* bind resource */
/* setup response handlers */ /* setup response handlers */
handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL); handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL);
handler_add_timed(conn, _handle_missing_bind, BIND_TIMEOUT, NULL); handler_add_timed(conn, _handle_missing_bind, BIND_TIMEOUT, NULL);
@@ -895,11 +913,18 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
return 0; return 0;
} }
bind = xmpp_stanza_copy(bind);
if (!bind) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return 0;
}
/* request a specific resource if we have one */ /* request a specific resource if we have one */
resource = xmpp_jid_resource(conn->ctx, conn->jid); resource = xmpp_jid_resource(conn->ctx, conn->jid);
if ((resource != NULL) && (strlen(resource) == 0)) { if ((resource != NULL) && (strlen(resource) == 0)) {
/* jabberd2 doesn't handle an empty resource */ /* jabberd2 doesn't handle an empty resource */
strophe_free(conn->ctx, resource); xmpp_free(conn->ctx, resource);
resource = NULL; resource = NULL;
} }
@@ -927,89 +952,18 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
xmpp_stanza_release(text); xmpp_stanza_release(text);
xmpp_stanza_add_child(bind, res); xmpp_stanza_add_child(bind, res);
xmpp_stanza_release(res); xmpp_stanza_release(res);
strophe_free(conn->ctx, resource); xmpp_free(conn->ctx, resource);
} }
xmpp_stanza_add_child(iq, bind); xmpp_stanza_add_child(iq, bind);
xmpp_stanza_release(bind); xmpp_stanza_release(bind);
/* send bind request */ /* send bind request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE); xmpp_send(conn, iq);
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
return 0;
}
static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *bind, *session, *opt;
xmpp_stanza_t *resume;
const char *ns;
char h[11];
UNUSED(userdata);
/* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
/* check whether resource binding is required */
bind = xmpp_stanza_get_child_by_name(stanza, "bind");
if (bind) {
ns = xmpp_stanza_get_ns(bind);
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
}
/* check whether session establishment is required */
session = xmpp_stanza_get_child_by_name(stanza, "session");
if (session) {
ns = xmpp_stanza_get_ns(session);
opt = xmpp_stanza_get_child_by_name(session, "optional");
if (!opt)
conn->session_required =
ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
}
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
/* stream management supported */
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 */
/* check whether we can <resume/> the previous session */
if (!conn->sm_disable && conn->sm_state->can_resume &&
conn->sm_state->previd && conn->sm_state->bound_jid) {
resume = xmpp_stanza_new(conn->ctx);
if (!resume) {
disconnect_mem_error(conn);
return 0;
}
conn->sm_state->bind = bind;
conn->sm_state->resume = 1;
xmpp_stanza_set_name(resume, "resume");
xmpp_stanza_set_ns(resume, XMPP_NS_SM);
xmpp_stanza_set_attribute(resume, "previd", conn->sm_state->previd);
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 */
else if (conn->bind_required) {
/* bind resource */
_do_bind(conn, bind);
} else { } else {
/* can't bind, disconnect */ /* can't bind, disconnect */
xmpp_stanza_release(bind); xmpp_error(conn->ctx, "xmpp",
strophe_error(conn->ctx, "xmpp",
"Stream features does not allow " "Stream features does not allow "
"resource bind."); "resource bind.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
@@ -1022,7 +976,7 @@ static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
{ {
UNUSED(userdata); UNUSED(userdata);
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Did not receive stream features " "Did not receive stream features "
"after SASL authentication."); "after SASL authentication.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
@@ -1033,7 +987,7 @@ static int
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
const char *type; const char *type;
xmpp_stanza_t *iq, *enable, *session, *binding, *jid_stanza; xmpp_stanza_t *iq, *session;
UNUSED(userdata); UNUSED(userdata);
@@ -1043,14 +997,15 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* server has replied to bind request */ /* server has replied to bind request */
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (type && strcmp(type, "error") == 0) { if (type && strcmp(type, "error") == 0) {
strophe_error(conn->ctx, "xmpp", "Binding failed."); xmpp_error(conn->ctx, "xmpp", "Binding failed.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (type && strcmp(type, "result") == 0) { } else if (type && strcmp(type, "result") == 0) {
binding = xmpp_stanza_get_child_by_name(stanza, "bind"); xmpp_stanza_t *binding = xmpp_stanza_get_child_by_name(stanza, "bind");
strophe_debug(conn->ctx, "xmpp", "Bind successful."); xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
if (binding) { if (binding) {
jid_stanza = xmpp_stanza_get_child_by_name(binding, "jid"); xmpp_stanza_t *jid_stanza =
xmpp_stanza_get_child_by_name(binding, "jid");
if (jid_stanza) { if (jid_stanza) {
conn->bound_jid = xmpp_stanza_get_text(jid_stanza); conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
} }
@@ -1084,30 +1039,17 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_release(session); xmpp_stanza_release(session);
/* send session establishment request */ /* send session establishment request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE); xmpp_send(conn, iq);
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
} } else {
conn->authenticated = 1;
if (conn->sm_state->sm_support && !conn->sm_disable) { /* call connection handler */
enable = xmpp_stanza_new(conn->ctx); conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL,
if (!enable) { conn->userdata);
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(enable, "enable");
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
if (!conn->sm_state->dont_request_resume)
xmpp_stanza_set_attribute(enable, "resume", "true");
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
xmpp_stanza_release(enable);
}
if (!conn->session_required) {
_auth_success(conn);
} }
} else { } else {
strophe_error(conn->ctx, "xmpp", "Server sent malformed bind reply."); xmpp_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
@@ -1118,7 +1060,7 @@ static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata)
{ {
UNUSED(userdata); UNUSED(userdata);
strophe_error(conn->ctx, "xmpp", "Server did not reply to bind request."); xmpp_error(conn->ctx, "xmpp", "Server did not reply to bind request.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
return 0; return 0;
} }
@@ -1136,15 +1078,17 @@ _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* server has replied to the session request */ /* server has replied to the session request */
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (type && strcmp(type, "error") == 0) { if (type && strcmp(type, "error") == 0) {
strophe_error(conn->ctx, "xmpp", "Session establishment failed."); xmpp_error(conn->ctx, "xmpp", "Session establishment failed.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (type && strcmp(type, "result") == 0) { } else if (type && strcmp(type, "result") == 0) {
strophe_debug(conn->ctx, "xmpp", "Session establishment successful."); xmpp_debug(conn->ctx, "xmpp", "Session establishment successful.");
_auth_success(conn); conn->authenticated = 1;
/* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} else { } else {
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp", "Server sent malformed session reply.");
"Server sent malformed session reply.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
@@ -1155,8 +1099,7 @@ static int _handle_missing_session(xmpp_conn_t *conn, void *userdata)
{ {
UNUSED(userdata); UNUSED(userdata);
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp", "Server did not reply to session request.");
"Server did not reply to session request.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
return 0; return 0;
} }
@@ -1165,144 +1108,13 @@ static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
{ {
UNUSED(userdata); UNUSED(userdata);
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Server did not reply to legacy " "Server did not reply to legacy "
"authentication request."); "authentication request.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
return 0; return 0;
} }
static int _handle_sm(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata)
{
xmpp_stanza_t *failed_cause;
const char *name, *id, *previd, *resume, *h, *cause;
xmpp_send_queue_t *e;
unsigned long ul_h = 0;
UNUSED(userdata);
name = xmpp_stanza_get_name(stanza);
if (!name)
goto LBL_ERR;
if (strcmp(name, "enabled") == 0) {
conn->sm_state->sm_enabled = 1;
conn->sm_state->sm_handled_nr = 0;
resume = xmpp_stanza_get_attribute(stanza, "resume");
if (resume && (strcasecmp(resume, "true") || strcmp(resume, "1"))) {
id = xmpp_stanza_get_attribute(stanza, "id");
if (!id) {
strophe_error(conn->ctx, "xmpp",
"SM error: server said it can resume, but "
"didn't provide an ID.");
name = NULL;
goto LBL_ERR;
}
conn->sm_state->can_resume = 1;
conn->sm_state->id = strophe_strdup(conn->ctx, id);
}
} else if (strcmp(name, "resumed") == 0) {
previd = xmpp_stanza_get_attribute(stanza, "previd");
if (!previd || strcmp(previd, conn->sm_state->previd)) {
strophe_error(conn->ctx, "xmpp",
"SM error: previd didn't match, ours is \"%s\".",
conn->sm_state->previd);
name = NULL;
goto LBL_ERR;
}
h = xmpp_stanza_get_attribute(stanza, "h");
if (!h || string_to_ul(h, &ul_h)) {
strophe_error(conn->ctx, "xmpp",
"SM error: failed parsing 'h', it got converted "
"to %llu.",
ul_h);
name = NULL;
goto LBL_ERR;
}
conn->sm_state->sm_enabled = 1;
conn->sm_state->id = conn->sm_state->previd;
conn->sm_state->previd = NULL;
conn->bound_jid = conn->sm_state->bound_jid;
conn->sm_state->bound_jid = NULL;
if (conn->sm_state->sm_queue.head)
conn->sm_state->sm_sent_nr = conn->sm_state->sm_queue.head->sm_h;
else
conn->sm_state->sm_sent_nr = ul_h;
while ((e = pop_queue_front(&conn->sm_state->sm_queue))) {
if (e->sm_h >= ul_h) {
/* Re-send what was already sent out and is still in the
* SM queue (i.e. it hasn't been ACK'ed by the server)
*/
send_raw(conn, e->data, e->len, e->owner, NULL);
}
strophe_free(conn->ctx, queue_element_free(conn->ctx, e));
}
conn->authenticated = 1;
/* call connection handler */
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} else if (strcmp(name, "failed") == 0) {
name = NULL;
failed_cause =
xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_STANZAS_IETF);
if (!failed_cause)
goto LBL_ERR;
cause = xmpp_stanza_get_name(failed_cause);
if (!cause)
goto LBL_ERR;
if (!strcmp(cause, "item-not-found") ||
!strcmp(cause, "feature-not-implemented")) {
if (conn->sm_state->resume) {
conn->sm_state->resume = 0;
conn->sm_state->can_resume = 0;
/* remember that the server reports having support
* for resumption, but actually it doesn't ...
*/
conn->sm_state->dont_request_resume =
!strcmp(cause, "feature-not-implemented");
strophe_free(conn->ctx, conn->sm_state->previd);
conn->sm_state->previd = NULL;
strophe_free(conn->ctx, conn->sm_state->bound_jid);
conn->sm_state->bound_jid = NULL;
_do_bind(conn, conn->sm_state->bind);
conn->sm_state->bind = NULL;
}
}
conn->sm_state->sm_handled_nr = 0;
} else {
/* unknown stanza received */
name = NULL;
}
LBL_ERR:
if (!name) {
char *err = "Couldn't convert stanza to text!";
char *buf;
size_t buflen;
switch (xmpp_stanza_to_text(stanza, &buf, &buflen)) {
case XMPP_EOK:
break;
case XMPP_EMEM:
disconnect_mem_error(conn);
return 0;
default:
buf = err;
break;
}
strophe_warn(conn->ctx, "xmpp", "SM error: Stanza received was: %s",
buf);
if (buf != err)
strophe_free(conn->ctx, buf);
conn->sm_state->sm_enabled = 0;
}
return 0;
}
static int static int
_handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
@@ -1318,22 +1130,22 @@ _handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
if (!type || strcmp(name, "iq") != 0) { if (!type || strcmp(name, "iq") != 0) {
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Server sent us an unexpected response " "Server sent us an unexpected response "
"to legacy authentication request."); "to legacy authentication request.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (strcmp(type, "error") == 0) { } else if (strcmp(type, "error") == 0) {
/* legacy client auth failed, no more fallbacks */ /* legacy client auth failed, no more fallbacks */
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp", "Legacy client authentication failed.");
"Legacy client authentication failed.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (strcmp(type, "result") == 0) { } else if (strcmp(type, "result") == 0) {
/* auth succeeded */ /* auth succeeded */
strophe_debug(conn->ctx, "xmpp", "Legacy auth succeeded."); xmpp_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
_auth_success(conn); conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} else { } else {
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Server sent us a legacy authentication " "Server sent us a legacy authentication "
"response with a bad type."); "response with a bad type.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
@@ -1350,7 +1162,7 @@ static void _auth_legacy(xmpp_conn_t *conn)
xmpp_stanza_t *child; xmpp_stanza_t *child;
char *str; char *str;
strophe_debug(conn->ctx, "auth", "Legacy authentication request"); xmpp_debug(conn->ctx, "auth", "Legacy authentication request");
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1"); iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
if (!iq) if (!iq)
@@ -1380,7 +1192,7 @@ static void _auth_legacy(xmpp_conn_t *conn)
goto err_free; goto err_free;
} }
xmpp_stanza_set_text(authdata, str); xmpp_stanza_set_text(authdata, str);
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
xmpp_stanza_add_child(child, authdata); xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
@@ -1411,12 +1223,11 @@ static void _auth_legacy(xmpp_conn_t *conn)
str = xmpp_jid_resource(conn->ctx, conn->jid); str = xmpp_jid_resource(conn->ctx, conn->jid);
if (str) { if (str) {
xmpp_stanza_set_text(authdata, str); xmpp_stanza_set_text(authdata, str);
strophe_free(conn->ctx, str); xmpp_free(conn->ctx, str);
} else { } else {
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
strophe_error(conn->ctx, "auth", xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource");
"Cannot authenticate without resource");
xmpp_disconnect(conn); xmpp_disconnect(conn);
return; return;
} }
@@ -1426,7 +1237,7 @@ static void _auth_legacy(xmpp_conn_t *conn)
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL); handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL); handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
send_stanza(conn, iq, XMPP_QUEUE_STROPHE); xmpp_send(conn, iq);
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
return; return;
@@ -1450,7 +1261,7 @@ void auth_handle_component_open(xmpp_conn_t *conn)
rc = _handle_component_auth(conn); rc = _handle_component_auth(conn);
if (rc != 0) { if (rc != 0) {
strophe_error(conn->ctx, "auth", "Component authentication failed."); xmpp_error(conn->ctx, "auth", "Component authentication failed.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
} }
@@ -1464,12 +1275,11 @@ int _handle_component_auth(xmpp_conn_t *conn)
size_t i; size_t i;
if (conn->stream_id == NULL) { if (conn->stream_id == NULL) {
strophe_error(conn->ctx, "auth", xmpp_error(conn->ctx, "auth", "Received no stream id from the server.");
"Received no stream id from the server.");
return XMPP_EINT; return XMPP_EINT;
} }
/* Feed the session id and passphrase to the algorithm. /* Feed the session id and passphrase to the algorithm.
* We need to compute SHA1(session_id + passphrase) * We need to compute SHA1(session_id + passphrase)
*/ */
crypto_SHA1_Init(&mdctx); crypto_SHA1_Init(&mdctx);
@@ -1478,24 +1288,24 @@ int _handle_component_auth(xmpp_conn_t *conn)
crypto_SHA1_Update(&mdctx, (uint8_t *)conn->pass, strlen(conn->pass)); crypto_SHA1_Update(&mdctx, (uint8_t *)conn->pass, strlen(conn->pass));
crypto_SHA1_Final(&mdctx, md_value); crypto_SHA1_Final(&mdctx, md_value);
digest = strophe_alloc(conn->ctx, 2 * sizeof(md_value) + 1); digest = xmpp_alloc(conn->ctx, 2 * sizeof(md_value) + 1);
if (digest) { if (digest) {
/* convert the digest into string representation */ /* convert the digest into string representation */
for (i = 0; i < sizeof(md_value); i++) for (i = 0; i < sizeof(md_value); i++)
strophe_snprintf(digest + i * 2, 3, "%02x", md_value[i]); xmpp_snprintf(digest + i * 2, 3, "%02x", md_value[i]);
digest[2 * sizeof(md_value)] = '\0'; digest[2 * sizeof(md_value)] = '\0';
strophe_debug(conn->ctx, "auth", "Digest: %s, len: %d", digest, xmpp_debug(conn->ctx, "auth", "Digest: %s, len: %d", digest,
strlen(digest)); strlen(digest));
/* Send the digest to the server */ /* Send the digest to the server */
send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>", xmpp_send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>",
XMPP_NS_COMPONENT, digest); XMPP_NS_COMPONENT, digest);
strophe_debug(conn->ctx, "auth", xmpp_debug(conn->ctx, "auth",
"Sent component handshake to the server."); "Sent component handshake to the server.");
strophe_free(conn->ctx, digest); xmpp_free(conn->ctx, digest);
} else { } else {
strophe_debug(conn->ctx, "auth", xmpp_debug(conn->ctx, "auth",
"Couldn't allocate memory for component " "Couldn't allocate memory for component "
"handshake digest."); "handshake digest.");
return XMPP_EMEM; return XMPP_EMEM;
@@ -1523,13 +1333,14 @@ int _handle_component_hs_response(xmpp_conn_t *conn,
size_t msg_size; size_t msg_size;
xmpp_stanza_to_text(stanza, &msg, &msg_size); xmpp_stanza_to_text(stanza, &msg, &msg_size);
if (msg) { if (msg) {
strophe_debug(conn->ctx, "auth", "Handshake failed: %s", msg); xmpp_debug(conn->ctx, "auth", "Handshake failed: %s", msg);
strophe_free(conn->ctx, msg); xmpp_free(conn->ctx, msg);
} }
xmpp_disconnect(conn); xmpp_disconnect(conn);
return XMPP_EINT; return XMPP_EINT;
} else { } else {
_auth_success(conn); conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} }
/* We don't need this handler anymore, return 0 so it can be deleted /* We don't need this handler anymore, return 0 so it can be deleted
@@ -1542,8 +1353,7 @@ int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata)
{ {
UNUSED(userdata); UNUSED(userdata);
strophe_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp", "Server did not reply to handshake request.");
"Server did not reply to handshake request.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
return 0; return 0;
} }
@@ -1552,10 +1362,11 @@ void auth_handle_open_raw(xmpp_conn_t *conn)
{ {
handler_reset_timed(conn, 0); handler_reset_timed(conn, 0);
/* user handlers are not called before authentication is completed. */ /* user handlers are not called before authentication is completed. */
_auth_success(conn); conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} }
void auth_handle_open_stub(xmpp_conn_t *conn) void auth_handle_open_stub(xmpp_conn_t *conn)
{ {
strophe_warn(conn->ctx, "auth", "Stub callback is called."); xmpp_warn(conn->ctx, "auth", "Stub callback is called.");
} }

View File

@@ -26,6 +26,7 @@
#include "hash.h" #include "hash.h"
#include "util.h" #include "util.h"
#include "parser.h" #include "parser.h"
#include "rand.h"
#include "snprintf.h" #include "snprintf.h"
/** handlers **/ /** handlers **/
@@ -76,7 +77,6 @@ typedef struct _xmpp_connlist_t {
struct _xmpp_ctx_t { struct _xmpp_ctx_t {
const xmpp_mem_t *mem; const xmpp_mem_t *mem;
const xmpp_log_t *log; const xmpp_log_t *log;
int verbosity;
xmpp_rand_t *rand; xmpp_rand_t *rand;
xmpp_loop_status_t loop_status; xmpp_loop_status_t loop_status;
@@ -87,38 +87,22 @@ struct _xmpp_ctx_t {
}; };
/* convenience functions for accessing the context */ /* convenience functions for accessing the context */
void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size); void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size); void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s); char *xmpp_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);
/* wrappers for xmpp_log at specific levels */ void xmpp_log(const xmpp_ctx_t *ctx,
void strophe_error(const xmpp_ctx_t *ctx, const xmpp_log_level_t level,
const char *area,
const char *fmt,
...);
void strophe_warn(const xmpp_ctx_t *ctx,
const char *area,
const char *fmt,
...);
void strophe_info(const xmpp_ctx_t *ctx,
const char *area,
const char *fmt,
...);
void strophe_debug(const xmpp_ctx_t *ctx,
const char *area,
const char *fmt,
...);
void strophe_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void strophe_log_internal(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area, const char *area,
const char *fmt, const char *fmt,
va_list ap); va_list ap);
/* wrappers for xmpp_log at specific levels */
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
/** connection **/ /** connection **/
/* opaque connection object */ /* opaque connection object */
@@ -128,24 +112,13 @@ typedef enum {
XMPP_STATE_CONNECTED XMPP_STATE_CONNECTED
} xmpp_conn_state_t; } xmpp_conn_state_t;
typedef enum {
XMPP_QUEUE_STROPHE = 0x1,
XMPP_QUEUE_USER = 0x2,
XMPP_QUEUE_SM = 0x800,
XMPP_QUEUE_SM_STROPHE = XMPP_QUEUE_SM | XMPP_QUEUE_STROPHE,
} xmpp_send_queue_owner_t;
typedef struct _xmpp_send_queue_t xmpp_send_queue_t; typedef struct _xmpp_send_queue_t xmpp_send_queue_t;
struct _xmpp_send_queue_t { struct _xmpp_send_queue_t {
char *data; char *data;
size_t len; size_t len;
size_t written; size_t written;
int wip;
xmpp_send_queue_owner_t owner;
void *userdata;
uint32_t sm_h;
xmpp_send_queue_t *prev, *next; xmpp_send_queue_t *next;
}; };
#define UNUSED(x) ((void)(x)) #define UNUSED(x) ((void)(x))
@@ -171,22 +144,6 @@ enum {
typedef void (*xmpp_open_handler)(xmpp_conn_t *conn); typedef void (*xmpp_open_handler)(xmpp_conn_t *conn);
typedef struct {
xmpp_send_queue_t *head, *tail;
} xmpp_queue_t;
struct _xmpp_sm_t {
xmpp_ctx_t *ctx;
int sm_support;
int sm_enabled;
int can_resume, resume, dont_request_resume;
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 _xmpp_conn_t { struct _xmpp_conn_t {
unsigned int ref; unsigned int ref;
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
@@ -201,7 +158,6 @@ struct _xmpp_conn_t {
sock_t sock; sock_t sock;
int ka_timeout; /* TCP keepalive timeout */ int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */ int ka_interval; /* TCP keepalive interval */
int ka_count; /* TCP keepalive count */
tls_t *tls; tls_t *tls;
int tls_support; int tls_support;
@@ -209,8 +165,6 @@ struct _xmpp_conn_t {
int tls_mandatory; int tls_mandatory;
int tls_legacy_ssl; int tls_legacy_ssl;
int tls_trust; int tls_trust;
char *tls_cafile;
char *tls_capath;
char *tls_client_cert; char *tls_client_cert;
char *tls_client_key; char *tls_client_key;
int tls_failed; /* set when tls fails, so we don't try again */ int tls_failed; /* set when tls fails, so we don't try again */
@@ -218,21 +172,10 @@ struct _xmpp_conn_t {
mechanisms */ mechanisms */
int auth_legacy_enabled; int auth_legacy_enabled;
int secured; /* set when stream is secured with TLS */ int secured; /* set when stream is secured with TLS */
xmpp_certfail_handler certfail_handler;
xmpp_password_callback password_callback;
void *password_callback_userdata;
struct {
char pass[1024];
unsigned char fname_hash[XMPP_SHA1_DIGEST_SIZE];
size_t passlen, fnamelen;
} password_cache;
unsigned int password_retries;
/* if server returns <bind/> or <session/> we must do them */ /* if server returns <bind/> or <session/> we must do them */
int bind_required; int bind_required;
int session_required; int session_required;
int sm_disable;
xmpp_sm_state_t *sm_state;
char *lang; char *lang;
char *domain; char *domain;
@@ -245,7 +188,6 @@ struct _xmpp_conn_t {
int blocking_send; int blocking_send;
int send_queue_max; int send_queue_max;
int send_queue_len; int send_queue_len;
int send_queue_user_len;
xmpp_send_queue_t *send_queue_head; xmpp_send_queue_t *send_queue_head;
xmpp_send_queue_t *send_queue_tail; xmpp_send_queue_t *send_queue_tail;
@@ -272,7 +214,6 @@ struct _xmpp_conn_t {
xmpp_handlist_t *timed_handlers; xmpp_handlist_t *timed_handlers;
hash_t *id_handlers; hash_t *id_handlers;
xmpp_handlist_t *handlers; xmpp_handlist_t *handlers;
xmpp_sockopt_callback sockopt_cb;
}; };
void conn_disconnect(xmpp_conn_t *conn); void conn_disconnect(xmpp_conn_t *conn);
@@ -334,23 +275,4 @@ void auth_handle_component_open(xmpp_conn_t *conn);
void auth_handle_open_raw(xmpp_conn_t *conn); void auth_handle_open_raw(xmpp_conn_t *conn);
void auth_handle_open_stub(xmpp_conn_t *conn); 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 *pop_queue_front(xmpp_queue_t *queue);
char *queue_element_free(xmpp_ctx_t *ctx, xmpp_send_queue_t *e);
/* send functions */
void send_raw(xmpp_conn_t *conn,
const char *data,
size_t len,
xmpp_send_queue_owner_t owner,
void *userdata);
/* this is a bit special as it will always mark the sent string as
* owned by libstrophe
*/
void send_raw_string(xmpp_conn_t *conn, const char *fmt, ...);
void send_stanza(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
xmpp_send_queue_owner_t owner);
#endif /* __LIBSTROPHE_COMMON_H__ */ #endif /* __LIBSTROPHE_COMMON_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -22,11 +22,11 @@
#include <assert.h> #include <assert.h>
#include <string.h> /* memset, memcpy */ #include <string.h> /* memset, memcpy */
#include "common.h" /* strophe_alloc */ #include "common.h" /* xmpp_alloc */
#include "ostypes.h" /* uint8_t, size_t */ #include "ostypes.h" /* uint8_t, size_t */
#include "sha1.h" #include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */ #include "snprintf.h" /* xmpp_snprintf */
#include "strophe.h" /* xmpp_ctx_t, strophe_free */ #include "strophe.h" /* xmpp_ctx_t, xmpp_free */
struct _xmpp_sha1_t { struct _xmpp_sha1_t {
xmpp_ctx_t *xmpp_ctx; xmpp_ctx_t *xmpp_ctx;
@@ -42,7 +42,7 @@ static char *digest_to_string(const uint8_t *digest, char *s, size_t len)
return NULL; return NULL;
for (i = 0; i < SHA1_DIGEST_SIZE; ++i) for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
strophe_snprintf(s + i * 2, 3, "%02x", digest[i]); xmpp_snprintf(s + i * 2, 3, "%02x", digest[i]);
return s; return s;
} }
@@ -53,7 +53,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
size_t slen; size_t slen;
slen = SHA1_DIGEST_SIZE * 2 + 1; slen = SHA1_DIGEST_SIZE * 2 + 1;
s = strophe_alloc(ctx, slen); s = xmpp_alloc(ctx, slen);
if (s) { if (s) {
s = digest_to_string(digest, s, slen); s = digest_to_string(digest, s, slen);
assert(s != NULL); assert(s != NULL);
@@ -122,7 +122,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
{ {
xmpp_sha1_t *sha1; xmpp_sha1_t *sha1;
sha1 = strophe_alloc(ctx, sizeof(*sha1)); sha1 = xmpp_alloc(ctx, sizeof(*sha1));
if (sha1) { if (sha1) {
memset(sha1, 0, sizeof(*sha1)); memset(sha1, 0, sizeof(*sha1));
crypto_SHA1_Init(&sha1->ctx); crypto_SHA1_Init(&sha1->ctx);
@@ -139,7 +139,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
*/ */
void xmpp_sha1_free(xmpp_sha1_t *sha1) void xmpp_sha1_free(xmpp_sha1_t *sha1)
{ {
strophe_free(sha1->xmpp_ctx, sha1); xmpp_free(sha1->xmpp_ctx, sha1);
} }
/** Update SHA1 context with the next portion of data. /** Update SHA1 context with the next portion of data.
@@ -187,9 +187,9 @@ char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string.
* Returns an allocated string. Free the string by calling xmpp_free() using * Returns an allocated string. Free the string using the Strophe context
* the Strophe context which is passed to xmpp_sha1_new(). Call this function * which is passed to xmpp_sha1_new(). Call this function after
* after xmpp_sha1_final(). * xmpp_sha1_final().
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* *
@@ -259,7 +259,7 @@ base64_encode(xmpp_ctx_t *ctx, const unsigned char *buffer, size_t len)
size_t i; size_t i;
clen = base64_encoded_len(len); clen = base64_encoded_len(len);
cbuf = strophe_alloc(ctx, clen + 1); cbuf = xmpp_alloc(ctx, clen + 1);
if (cbuf != NULL) { if (cbuf != NULL) {
c = cbuf; c = cbuf;
/* loop over data, turning every 3 bytes into 4 characters */ /* loop over data, turning every 3 bytes into 4 characters */
@@ -348,7 +348,7 @@ static void base64_decode(xmpp_ctx_t *ctx,
if (dlen == 0) if (dlen == 0)
goto _base64_error; goto _base64_error;
dbuf = strophe_alloc(ctx, dlen + 1); dbuf = xmpp_alloc(ctx, dlen + 1);
if (dbuf != NULL) { if (dbuf != NULL) {
d = dbuf; d = dbuf;
/* loop over each set of 4 characters, decoding 3 bytes */ /* loop over each set of 4 characters, decoding 3 bytes */
@@ -427,7 +427,7 @@ static void base64_decode(xmpp_ctx_t *ctx,
_base64_decode_error: _base64_decode_error:
/* invalid character; abort decoding! */ /* invalid character; abort decoding! */
strophe_free(ctx, dbuf); xmpp_free(ctx, dbuf);
_base64_error: _base64_error:
*out = NULL; *out = NULL;
*outlen = 0; *outlen = 0;
@@ -469,7 +469,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
if (len == 0) { if (len == 0) {
/* handle empty string */ /* handle empty string */
buf = strophe_alloc(ctx, 1); buf = xmpp_alloc(ctx, 1);
if (buf) if (buf)
buf[0] = '\0'; buf[0] = '\0';
buflen = 0; buflen = 0;
@@ -478,7 +478,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
} }
if (buf) { if (buf) {
if (buflen != strlen((char *)buf)) { if (buflen != strlen((char *)buf)) {
strophe_free(ctx, buf); xmpp_free(ctx, buf);
buf = NULL; buf = NULL;
} }
} }

114
src/ctx.c
View File

@@ -211,7 +211,7 @@ static xmpp_log_t xmpp_default_log = {NULL, NULL};
* *
* @return a pointer to the allocated memory or NULL on an error * @return a pointer to the allocated memory or NULL on an error
*/ */
void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
{ {
return ctx->mem->alloc(size, ctx->mem->userdata); return ctx->mem->alloc(size, ctx->mem->userdata);
} }
@@ -222,19 +222,9 @@ void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size)
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param p a pointer referencing memory to be freed * @param p a pointer referencing memory to be freed
*/ */
void strophe_free(const xmpp_ctx_t *ctx, void *p)
{
ctx->mem->free(p, ctx->mem->userdata);
}
/** Trampoline to \ref strophe_free
*
* @param ctx \ref strophe_free
* @param p \ref strophe_free
*/
void xmpp_free(const xmpp_ctx_t *ctx, void *p) void xmpp_free(const xmpp_ctx_t *ctx, void *p)
{ {
strophe_free(ctx, p); ctx->mem->free(p, ctx->mem->userdata);
} }
/** Reallocate memory in a Strophe context. /** Reallocate memory in a Strophe context.
@@ -246,7 +236,7 @@ void xmpp_free(const xmpp_ctx_t *ctx, void *p)
* *
* @return a pointer to the reallocated memory or NULL on an error * @return a pointer to the reallocated memory or NULL on an error
*/ */
void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size) void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
{ {
return ctx->mem->realloc(p, size, ctx->mem->userdata); return ctx->mem->realloc(p, size, ctx->mem->userdata);
} }
@@ -255,8 +245,8 @@ void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
* Write a log message to the logger for the context for the specified * Write a log message to the logger for the context for the specified
* level and area. This function takes a printf-style format string and a * level and area. This function takes a printf-style format string and a
* variable argument list (in va_list) format. This function is not meant * variable argument list (in va_list) format. This function is not meant
* to be called directly, but is used via strophe_error, strophe_warn, * to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
* strophe_info, and strophe_debug. * and xmpp_debug.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param level the level at which to log * @param level the level at which to log
@@ -264,7 +254,7 @@ void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
* @param fmt a printf-style format string for the message * @param fmt a printf-style format string for the message
* @param ap variable argument list supplied for the format string * @param ap variable argument list supplied for the format string
*/ */
static void _strophe_log(const xmpp_ctx_t *ctx, void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level, xmpp_log_level_t level,
const char *area, const char *area,
const char *fmt, const char *fmt,
@@ -275,29 +265,21 @@ static void _strophe_log(const xmpp_ctx_t *ctx,
char *buf; char *buf;
va_list copy; va_list copy;
if (!ctx->log->handler)
return;
if (ctx->log->handler == xmpp_default_logger &&
level < *(xmpp_log_level_t *)ctx->log->userdata)
return;
va_copy(copy, ap); va_copy(copy, ap);
ret = strophe_vsnprintf(smbuf, sizeof(smbuf), fmt, ap); ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
if (ret >= (int)sizeof(smbuf)) { if (ret >= (int)sizeof(smbuf)) {
buf = (char *)strophe_alloc(ctx, ret + 1); buf = (char *)xmpp_alloc(ctx, ret + 1);
if (!buf) { if (!buf) {
buf = NULL; buf = NULL;
strophe_error(ctx, "log", xmpp_error(ctx, "log", "Failed allocating memory for log message.");
"Failed allocating memory for log message.");
va_end(copy); va_end(copy);
return; return;
} }
oldret = ret; oldret = ret;
ret = strophe_vsnprintf(buf, ret + 1, fmt, copy); ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
if (ret > oldret) { if (ret > oldret) {
strophe_error(ctx, "log", "Unexpected error"); xmpp_error(ctx, "log", "Unexpected error");
strophe_free(ctx, buf); xmpp_free(ctx, buf);
va_end(copy); va_end(copy);
return; return;
} }
@@ -306,20 +288,11 @@ static void _strophe_log(const xmpp_ctx_t *ctx,
} }
va_end(copy); va_end(copy);
if (ctx->log->handler)
ctx->log->handler(ctx->log->userdata, level, area, buf); ctx->log->handler(ctx->log->userdata, level, area, buf);
if (buf != smbuf) if (buf != smbuf)
strophe_free(ctx, buf); xmpp_free(ctx, buf);
}
/* Dummy trampoline, will be removed when deprecated.c is deleted */
void strophe_log_internal(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap)
{
_strophe_log(ctx, level, area, fmt, ap);
} }
/** Write to the log at the ERROR level. /** Write to the log at the ERROR level.
@@ -332,15 +305,12 @@ void strophe_log_internal(const xmpp_ctx_t *ctx,
* @param fmt a printf-style format string followed by a variable list of * @param fmt a printf-style format string followed by a variable list of
* arguments to format * arguments to format
*/ */
void strophe_error(const xmpp_ctx_t *ctx, void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
const char *area,
const char *fmt,
...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
_strophe_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap); xmpp_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
va_end(ap); va_end(ap);
} }
@@ -354,12 +324,12 @@ void strophe_error(const xmpp_ctx_t *ctx,
* @param fmt a printf-style format string followed by a variable list of * @param fmt a printf-style format string followed by a variable list of
* arguments to format * arguments to format
*/ */
void strophe_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...) void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
_strophe_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap); xmpp_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
va_end(ap); va_end(ap);
} }
@@ -373,12 +343,12 @@ void strophe_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @param fmt a printf-style format string followed by a variable list of * @param fmt a printf-style format string followed by a variable list of
* arguments to format * arguments to format
*/ */
void strophe_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...) void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
_strophe_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap); xmpp_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
va_end(ap); va_end(ap);
} }
@@ -392,39 +362,12 @@ void strophe_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @param fmt a printf-style format string followed by a variable list of * @param fmt a printf-style format string followed by a variable list of
* arguments to format * arguments to format
*/ */
void strophe_debug(const xmpp_ctx_t *ctx, void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
const char *area,
const char *fmt,
...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
_strophe_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap); xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
/** Write to the log at the DEBUG level if verbosity is enabled.
* This is a convenience function for writing to the log at the DEBUG level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param level the verbosity level
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void strophe_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
if (ctx->verbosity < level)
return;
va_start(ap, fmt);
_strophe_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap); va_end(ap);
} }
@@ -467,9 +410,8 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
ctx->loop_status = XMPP_LOOP_NOTSTARTED; ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx); ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT; ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
ctx->verbosity = 0;
if (ctx->rand == NULL) { if (ctx->rand == NULL) {
strophe_free(ctx, ctx); xmpp_free(ctx, ctx);
ctx = NULL; ctx = NULL;
} }
} }
@@ -487,17 +429,17 @@ void xmpp_ctx_free(xmpp_ctx_t *ctx)
{ {
/* mem and log are owned by their suppliers */ /* mem and log are owned by their suppliers */
xmpp_rand_free(ctx, ctx->rand); xmpp_rand_free(ctx, ctx->rand);
strophe_free(ctx, ctx); /* pull the hole in after us */ xmpp_free(ctx, ctx); /* pull the hole in after us */
} }
/** Set the verbosity level of a Strophe context. /** Set the timeout to use when calling xmpp_run().
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param level the verbosity level * @param timeout the time to wait for events in milliseconds
* *
* @ingroup Context * @ingroup Context
*/ */
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level) void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout)
{ {
ctx->verbosity = level; ctx->timeout = timeout;
} }

View File

@@ -1,256 +0,0 @@
/* deprecated.c
** strophe XMPP client library -- File with deprecated API functions.
**
** Copyright (C) 2022 Steffen Jaeckel
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* File with deprecated API functions.
*/
/** @defgroup Deprecated All deprecated functions
* These functions will be removed in the next release.
*/
#include "common.h"
/** Allocate memory in a Strophe context.
* All Strophe functions will use this to allocate memory.
*
* @param ctx a Strophe context object
* @param size the number of bytes to allocate
*
* @return a pointer to the allocated memory or NULL on an error
*
* @ingroup Deprecated
*/
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
{
return strophe_alloc(ctx, size);
}
/** Reallocate memory in a Strophe context.
* All Strophe functions will use this to reallocate memory.
*
* @param ctx a Strophe context object
* @param p a pointer to previously allocated memory
* @param size the new size in bytes to allocate
*
* @return a pointer to the reallocated memory or NULL on an error
*
* @ingroup Deprecated
*/
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
{
return strophe_realloc(ctx, p, size);
}
/** implement our own strdup that uses the ctx allocator */
/** Duplicate a string.
* This function replaces the standard strdup library call with a version
* that uses the Strophe context object's allocator.
*
* @param ctx a Strophe context object
* @param s a string
*
* @return a newly allocated string with the same data as s or NULL on error
*
* @ingroup Deprecated
*/
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s)
{
return strophe_strdup(ctx, s);
}
/** Duplicate a string with a maximum length.
* This function replaces the standard strndup library call with a version
* that uses the Strophe context object's allocator.
*
* @param ctx a Strophe context object
* @param s a string
* @param len the maximum length of the string to copy
*
* @return a newly allocated string that contains at most `len` symbols
* of the original string or NULL on error
*
* @ingroup Deprecated
*/
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
{
return strophe_strndup(ctx, s, len);
}
void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap)
{
strophe_log_internal(ctx, level, area, fmt, ap);
}
/** Write to the log at the ERROR level.
* This is a convenience function for writing to the log at the
* ERROR level. It takes a printf-style format string followed by a
* variable list of arguments for formatting.
*
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*
* @ingroup Deprecated
*/
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
strophe_log_internal(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
va_end(ap);
}
/** Write to the log at the WARN level.
* This is a convenience function for writing to the log at the WARN level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*
* @ingroup Deprecated
*/
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
strophe_log_internal(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
va_end(ap);
}
/** Write to the log at the INFO level.
* This is a convenience function for writing to the log at the INFO level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*
* @ingroup Deprecated
*/
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
strophe_log_internal(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
va_end(ap);
}
/** Write to the log at the DEBUG level.
* This is a convenience function for writing to the log at the DEBUG level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*
* @ingroup Deprecated
*/
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
strophe_log_internal(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
/** Write to the log at the DEBUG level if verbosity is enabled.
* This is a convenience function for writing to the log at the DEBUG level.
* It takes a printf-style format string followed by a variable list of
* arguments for formatting.
*
* @param level the verbosity level
* @param ctx a Strophe context object
* @param area the area to log for
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*
* @ingroup Deprecated
*/
void xmpp_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
if (ctx->verbosity < level)
return;
va_start(ap, fmt);
strophe_log_internal(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
/** strtok_r(3) implementation.
* This function has appeared in POSIX.1-2001, but not in C standard.
* For example, visual studio older than 2005 doesn't provide strtok_r()
* nor strtok_s().
*
* @ingroup Deprecated
*/
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
{
return strophe_strtok_r(s, delim, saveptr);
}
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = strophe_vsnprintf(str, count, fmt, ap);
va_end(ap);
return ret;
}
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg)
{
return strophe_vsnprintf(str, count, fmt, arg);
}
/** Set TCP keepalive parameters
* Turn on TCP keepalive and set timeout and interval. Zero timeout
* disables TCP keepalives. The parameters are applied immediately for
* a non disconnected object. Also, they are applied when the connection
* object connects successfully.
*
* @param conn a Strophe connection object
* @param timeout TCP keepalive timeout in seconds
* @param interval TCP keepalive interval in seconds
*
* @note this function is deprecated
* @see xmpp_conn_set_sockopt_callback()
*
* @ingroup Deprecated
*/
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
{
conn->ka_timeout = timeout;
conn->ka_interval = interval;
conn->ka_count = 0;
xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
}

View File

@@ -107,11 +107,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occurred */ /* an error occurred */
strophe_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
"Send error occurred, disconnecting.");
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
goto next_item;
} }
} }
@@ -131,32 +129,15 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
} }
if (ret > 0 && ret < towrite) if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */ sq->written += ret; /* not all data could be sent now */
sq->wip = 1;
if (ret != towrite) if (ret != towrite)
break; /* partial write or an error */ break; /* partial write or an error */
/* all data for this queue item written, delete and move on */ /* all data for this queue item written, delete and move on */
strophe_debug(conn->ctx, "conn", "SENT: %s", sq->data); xmpp_free(ctx, sq->data);
strophe_debug_verbose(1, ctx, "xmpp", "Q_SENT: %p", sq);
tsq = sq; tsq = sq;
sq = sq->next; sq = sq->next;
conn->send_queue_len--; conn->send_queue_len--;
if (tsq->owner & XMPP_QUEUE_USER) xmpp_free(ctx, tsq);
conn->send_queue_user_len--;
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);
add_queue_back(&conn->sm_state->sm_queue, tsq);
tsq = NULL;
}
if (tsq) {
strophe_debug_verbose(2, ctx, "xmpp", "Q_FREE: %p", tsq);
strophe_debug_verbose(3, ctx, "conn", "Q_CONTENT: %s",
tsq->data);
strophe_free(ctx, tsq->data);
strophe_free(ctx, tsq);
}
/* pop the top item */ /* pop the top item */
conn->send_queue_head = sq; conn->send_queue_head = sq;
@@ -169,11 +150,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (conn->error) { if (conn->error) {
/* FIXME: need to tear down send queues and random other things /* FIXME: need to tear down send queues and random other things
* maybe this should be abstracted */ * maybe this should be abstracted */
strophe_debug(ctx, "xmpp", "Send error occurred, disconnecting."); xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED; conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
} }
next_item:
connitem = connitem->next; connitem = connitem->next;
} }
@@ -210,7 +191,7 @@ next_item:
FD_SET(conn->sock, &wfds); FD_SET(conn->sock, &wfds);
else { else {
conn->error = ETIMEDOUT; conn->error = ETIMEDOUT;
strophe_info(ctx, "xmpp", "Connection attempt timed out."); xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn); conn_disconnect(conn);
} }
break; break;
@@ -247,7 +228,7 @@ next_item:
/* select errored */ /* select errored */
if (ret < 0) { if (ret < 0) {
if (!sock_is_recoverable(sock_error())) if (!sock_is_recoverable(sock_error()))
strophe_error(ctx, "xmpp", "event watcher internal error %d", xmpp_error(ctx, "xmpp", "event watcher internal error %d",
sock_error()); sock_error());
return; return;
} }
@@ -270,14 +251,13 @@ next_item:
ret = sock_connect_error(conn->sock); ret = sock_connect_error(conn->sock);
if (ret != 0) { if (ret != 0) {
/* connection failed */ /* connection failed */
strophe_debug(ctx, "xmpp", "connection failed, error %d", xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
ret);
conn_disconnect(conn); conn_disconnect(conn);
break; break;
} }
conn->state = XMPP_STATE_CONNECTED; conn->state = XMPP_STATE_CONNECTED;
strophe_debug(ctx, "xmpp", "connection successful"); xmpp_debug(ctx, "xmpp", "connection successful");
conn_established(conn); conn_established(conn);
} }
@@ -295,14 +275,14 @@ next_item:
if (ret > 0) { if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret); ret = parser_feed(conn->parser, buf, ret);
if (!ret) { if (!ret) {
strophe_debug(ctx, "xmpp", "parse error [%s]", buf); xmpp_debug(ctx, "xmpp", "parse error [%s]", buf);
xmpp_send_error(conn, XMPP_SE_INVALID_XML, xmpp_send_error(conn, XMPP_SE_INVALID_XML,
"parse error"); "parse error");
} }
} else { } else {
if (conn->tls) { if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) { if (!tls_is_recoverable(tls_error(conn->tls))) {
strophe_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp",
"Unrecoverable TLS error, %d.", "Unrecoverable TLS error, %d.",
tls_error(conn->tls)); tls_error(conn->tls));
conn->error = tls_error(conn->tls); conn->error = tls_error(conn->tls);
@@ -310,7 +290,7 @@ next_item:
} }
} else { } else {
/* return of 0 means socket closed by server */ /* return of 0 means socket closed by server */
strophe_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp",
"Socket closed by remote host."); "Socket closed by remote host.");
conn->error = ECONNRESET; conn->error = ECONNRESET;
conn_disconnect(conn); conn_disconnect(conn);
@@ -353,7 +333,7 @@ void xmpp_run(xmpp_ctx_t *ctx)
/* make it possible to start event loop again */ /* make it possible to start event loop again */
ctx->loop_status = XMPP_LOOP_NOTSTARTED; ctx->loop_status = XMPP_LOOP_NOTSTARTED;
strophe_debug(ctx, "event", "Event loop completed."); xmpp_debug(ctx, "event", "Event loop completed.");
} }
/** Stop the event loop. /** Stop the event loop.
@@ -366,20 +346,8 @@ void xmpp_run(xmpp_ctx_t *ctx)
*/ */
void xmpp_stop(xmpp_ctx_t *ctx) void xmpp_stop(xmpp_ctx_t *ctx)
{ {
strophe_debug(ctx, "event", "Stopping event loop."); xmpp_debug(ctx, "event", "Stopping event loop.");
if (ctx->loop_status == XMPP_LOOP_RUNNING) if (ctx->loop_status == XMPP_LOOP_RUNNING)
ctx->loop_status = XMPP_LOOP_QUIT; ctx->loop_status = XMPP_LOOP_QUIT;
} }
/** Set the timeout to use when calling xmpp_run().
*
* @param ctx a Strophe context object
* @param timeout the time to wait for events in milliseconds
*
* @ingroup EventLoop
*/
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout)
{
ctx->timeout = timeout;
}

View File

@@ -46,17 +46,6 @@ static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
} }
} }
static void _free_handlist_item(xmpp_ctx_t *ctx, xmpp_handlist_t *item)
{
if (item->u.ns)
strophe_free(ctx, item->u.ns);
if (item->u.name)
strophe_free(ctx, item->u.name);
if (item->u.type)
strophe_free(ctx, item->u.type);
strophe_free(ctx, item);
}
/** Fire off all stanza handlers that match. /** Fire off all stanza handlers that match.
* This function is called internally by the event loop whenever stanzas * This function is called internally by the event loop whenever stanzas
* are received from the XMPP server. * are received from the XMPP server.
@@ -98,8 +87,8 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
/* replace old value */ /* replace old value */
hash_add(conn->id_handlers, id, head); hash_add(conn->id_handlers, id, head);
} }
strophe_free(conn->ctx, item->u.id); xmpp_free(conn->ctx, item->u.id);
strophe_free(conn->ctx, item); xmpp_free(conn->ctx, item);
} }
item = next; item = next;
} }
@@ -135,7 +124,13 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
if (!ret) { if (!ret) {
/* handler is one-shot, so delete it */ /* handler is one-shot, so delete it */
_handler_item_remove(&conn->handlers, item); _handler_item_remove(&conn->handlers, item);
_free_handlist_item(conn->ctx, item); if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item);
} }
} }
item = next; item = next;
@@ -194,7 +189,7 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
if (!ret) { if (!ret) {
/* delete handler if it returned false */ /* delete handler if it returned false */
_handler_item_remove(&conn->timed_handlers, item); _handler_item_remove(&conn->timed_handlers, item);
strophe_free(ctx, item); xmpp_free(ctx, item);
} }
} else if (min > (item->u.period - elapsed)) } else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed; min = item->u.period - elapsed;
@@ -225,7 +220,7 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
if (!ret) { if (!ret) {
/* delete handler if it returned false */ /* delete handler if it returned false */
_handler_item_remove(&ctx->timed_handlers, item); _handler_item_remove(&ctx->timed_handlers, item);
strophe_free(ctx, item); xmpp_free(ctx, item);
} }
} else if (min > (item->u.period - elapsed)) } else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed; min = item->u.period - elapsed;
@@ -267,7 +262,7 @@ static void _timed_handler_add(xmpp_ctx_t *ctx,
/* check if handler is already in the list */ /* check if handler is already in the list */
for (item = *handlers_list; item; item = item->next) { for (item = *handlers_list; item; item = item->next) {
if (item->handler == handler && item->userdata == userdata) { if (item->handler == handler && item->userdata == userdata) {
strophe_warn(ctx, "xmpp", "Timed handler already exists."); xmpp_warn(ctx, "xmpp", "Timed handler already exists.");
break; break;
} }
} }
@@ -275,7 +270,7 @@ static void _timed_handler_add(xmpp_ctx_t *ctx,
return; return;
/* build new item */ /* build new item */
item = strophe_alloc(ctx, sizeof(xmpp_handlist_t)); item = xmpp_alloc(ctx, sizeof(xmpp_handlist_t));
if (!item) if (!item)
return; return;
@@ -302,7 +297,7 @@ static void _timed_handler_delete(xmpp_ctx_t *ctx,
item = *handlers_list; item = *handlers_list;
if (item->handler == handler) { if (item->handler == handler) {
*handlers_list = item->next; *handlers_list = item->next;
strophe_free(ctx, item); xmpp_free(ctx, item);
} else { } else {
handlers_list = &item->next; handlers_list = &item->next;
} }
@@ -333,7 +328,7 @@ static void _id_handler_add(xmpp_conn_t *conn,
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) { while (item) {
if (item->handler == handler && item->userdata == userdata) { if (item->handler == handler && item->userdata == userdata) {
strophe_warn(conn->ctx, "xmpp", "Id handler already exists."); xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
break; break;
} }
item = item->next; item = item->next;
@@ -342,7 +337,7 @@ static void _id_handler_add(xmpp_conn_t *conn,
return; return;
/* build new item */ /* build new item */
item = strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t)); item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) if (!item)
return; return;
@@ -352,9 +347,9 @@ static void _id_handler_add(xmpp_conn_t *conn,
item->enabled = 0; item->enabled = 0;
item->next = NULL; item->next = NULL;
item->u.id = strophe_strdup(conn->ctx, id); item->u.id = xmpp_strdup(conn->ctx, id);
if (!item->u.id) { if (!item->u.id) {
strophe_free(conn->ctx, item); xmpp_free(conn->ctx, item);
return; return;
} }
@@ -399,8 +394,8 @@ void xmpp_id_handler_delete(xmpp_conn_t *conn,
hash_add(conn->id_handlers, id, next); hash_add(conn->id_handlers, id, next);
} }
strophe_free(conn->ctx, item->u.id); xmpp_free(conn->ctx, item->u.id);
strophe_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next; item = next;
} else { } else {
prev = item; prev = item;
@@ -409,16 +404,6 @@ void xmpp_id_handler_delete(xmpp_conn_t *conn,
} }
} }
static int _dup_string(xmpp_ctx_t *ctx, const char *src, char **dest)
{
if (src) {
*dest = strophe_strdup(ctx, src);
if (!(*dest))
return 1;
}
return 0;
}
/* add a stanza handler */ /* add a stanza handler */
static void _handler_add(xmpp_conn_t *conn, static void _handler_add(xmpp_conn_t *conn,
xmpp_handler handler, xmpp_handler handler,
@@ -435,7 +420,7 @@ static void _handler_add(xmpp_conn_t *conn,
/* same handler function can process different stanzas and /* same handler function can process different stanzas and
distinguish them according to userdata. */ distinguish them according to userdata. */
if (item->handler == handler && item->userdata == userdata) { if (item->handler == handler && item->userdata == userdata) {
strophe_warn(conn->ctx, "xmpp", "Stanza handler already exists."); xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
break; break;
} }
} }
@@ -443,21 +428,47 @@ static void _handler_add(xmpp_conn_t *conn,
return; return;
/* build new item */ /* build new item */
item = (xmpp_handlist_t *)strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t)); item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) if (!item)
return; return;
memset(item, 0, sizeof(*item));
item->user_handler = user_handler; item->user_handler = user_handler;
item->handler = handler; item->handler = handler;
item->userdata = userdata; item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
if (_dup_string(conn->ctx, ns, &item->u.ns)) if (ns) {
goto error_out; item->u.ns = xmpp_strdup(conn->ctx, ns);
if (_dup_string(conn->ctx, name, &item->u.name)) if (!item->u.ns) {
goto error_out; xmpp_free(conn->ctx, item);
if (_dup_string(conn->ctx, type, &item->u.type)) return;
goto error_out; }
} else
item->u.ns = NULL;
if (name) {
item->u.name = xmpp_strdup(conn->ctx, name);
if (!item->u.name) {
if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
xmpp_free(conn->ctx, item);
return;
}
} else
item->u.name = NULL;
if (type) {
item->u.type = xmpp_strdup(conn->ctx, type);
if (!item->u.type) {
if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
xmpp_free(conn->ctx, item);
}
} else
item->u.type = NULL;
/* append to list */ /* append to list */
if (!conn->handlers) if (!conn->handlers)
@@ -468,11 +479,6 @@ static void _handler_add(xmpp_conn_t *conn,
tail = tail->next; tail = tail->next;
tail->next = item; tail->next = item;
} }
return;
error_out:
_free_handlist_item(conn->ctx, item);
} }
/** Delete a stanza handler. /** Delete a stanza handler.
@@ -498,7 +504,13 @@ void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler)
else else
conn->handlers = item->next; conn->handlers = item->next;
_free_handlist_item(conn->ctx, item); if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->handlers; item = prev ? prev->next : conn->handlers;
} else { } else {
prev = item; prev = item;
@@ -653,7 +665,8 @@ void handler_system_delete_all(xmpp_conn_t *conn)
{ {
xmpp_handlist_t *item, *next, *head, *head_old; xmpp_handlist_t *item, *next, *head, *head_old;
hash_iterator_t *iter; hash_iterator_t *iter;
const char *key, *key2; const char *key;
char *key2 = NULL;
/* TODO unify all kinds of handlers and avoid copy-paste below */ /* TODO unify all kinds of handlers and avoid copy-paste below */
@@ -662,7 +675,13 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) { if (!item->user_handler) {
next = item->next; next = item->next;
_handler_item_remove(&conn->handlers, item); _handler_item_remove(&conn->handlers, item);
_free_handlist_item(conn->ctx, item); if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item);
item = next; item = next;
} else } else
item = item->next; item = item->next;
@@ -673,7 +692,7 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) { if (!item->user_handler) {
next = item->next; next = item->next;
_handler_item_remove(&conn->timed_handlers, item); _handler_item_remove(&conn->timed_handlers, item);
strophe_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next; item = next;
} else } else
item = item->next; item = item->next;
@@ -688,24 +707,26 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) { if (!item->user_handler) {
next = item->next; next = item->next;
_handler_item_remove(&head, item); _handler_item_remove(&head, item);
strophe_free(conn->ctx, item->u.id); xmpp_free(conn->ctx, item->u.id);
strophe_free(conn->ctx, item); xmpp_free(conn->ctx, item);
item = next; item = next;
} else } else
item = item->next; item = item->next;
} }
if (head != head_old)
key2 = xmpp_strdup(conn->ctx, key);
/* Hash table implementation is not perfect, so we need to find next /* Hash table implementation is not perfect, so we need to find next
key before dropping current one. Otherwise, we will get access to key before dropping current one. Otherwise, we will get access to
freed memory. */ freed memory. */
key2 = hash_iter_next(iter); key = hash_iter_next(iter);
if (head != head_old) { if (head != head_old) {
/* hash_add() replaces value if the key exists */ /* hash_add() replaces value if the key exists */
if (head != NULL) if (head != NULL)
hash_add(conn->id_handlers, key, head); hash_add(conn->id_handlers, key2, head);
else else
hash_drop(conn->id_handlers, key); hash_drop(conn->id_handlers, key2);
xmpp_free(conn->ctx, key2);
} }
key = key2;
} }
if (iter) if (iter)
hash_iter_release(iter); hash_iter_release(iter);

View File

@@ -50,11 +50,11 @@ hash_t *hash_new(xmpp_ctx_t *ctx, int size, hash_free_func free_func)
{ {
hash_t *result = NULL; hash_t *result = NULL;
result = strophe_alloc(ctx, sizeof(hash_t)); result = xmpp_alloc(ctx, sizeof(hash_t));
if (result != NULL) { if (result != NULL) {
result->entries = strophe_alloc(ctx, size * sizeof(hashentry_t *)); result->entries = xmpp_alloc(ctx, size * sizeof(hashentry_t *));
if (result->entries == NULL) { if (result->entries == NULL) {
strophe_free(ctx, result); xmpp_free(ctx, result);
return NULL; return NULL;
} }
memset(result->entries, 0, size * sizeof(hashentry_t *)); memset(result->entries, 0, size * sizeof(hashentry_t *));
@@ -91,15 +91,15 @@ void hash_release(hash_t *table)
entry = table->entries[i]; entry = table->entries[i];
while (entry != NULL) { while (entry != NULL) {
next = entry->next; next = entry->next;
strophe_free(ctx, entry->key); xmpp_free(ctx, entry->key);
if (table->free) if (table->free)
table->free(ctx, entry->value); table->free(ctx, entry->value);
strophe_free(ctx, entry); xmpp_free(ctx, entry);
entry = next; entry = next;
} }
} }
strophe_free(ctx, table->entries); xmpp_free(ctx, table->entries);
strophe_free(ctx, table); xmpp_free(ctx, table);
} }
} }
@@ -153,12 +153,12 @@ int hash_add(hash_t *table, const char *key, void *data)
if (entry == NULL) { if (entry == NULL) {
/* allocate and fill a new entry */ /* allocate and fill a new entry */
entry = strophe_alloc(ctx, sizeof(hashentry_t)); entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) if (!entry)
return -1; return -1;
entry->key = strophe_strdup(ctx, key); entry->key = xmpp_strdup(ctx, key);
if (!entry->key) { if (!entry->key) {
strophe_free(ctx, entry); xmpp_free(ctx, entry);
return -1; return -1;
} }
/* insert ourselves in the linked list */ /* insert ourselves in the linked list */
@@ -198,7 +198,7 @@ int hash_drop(hash_t *table, const char *key)
/* traverse the linked list looking for the key */ /* traverse the linked list looking for the key */
if (!strcmp(key, entry->key)) { if (!strcmp(key, entry->key)) {
/* match, remove the entry */ /* match, remove the entry */
strophe_free(ctx, entry->key); xmpp_free(ctx, entry->key);
if (table->free) if (table->free)
table->free(ctx, entry->value); table->free(ctx, entry->value);
if (prev == NULL) { if (prev == NULL) {
@@ -206,7 +206,7 @@ int hash_drop(hash_t *table, const char *key)
} else { } else {
prev->next = entry->next; prev->next = entry->next;
} }
strophe_free(ctx, entry); xmpp_free(ctx, entry);
table->num_keys--; table->num_keys--;
return 0; return 0;
} }
@@ -228,7 +228,7 @@ hash_iterator_t *hash_iter_new(hash_t *table)
xmpp_ctx_t *ctx = table->ctx; xmpp_ctx_t *ctx = table->ctx;
hash_iterator_t *iter; hash_iterator_t *iter;
iter = strophe_alloc(ctx, sizeof(*iter)); iter = xmpp_alloc(ctx, sizeof(*iter));
if (iter != NULL) { if (iter != NULL) {
iter->ref = 1; iter->ref = 1;
iter->table = hash_clone(table); iter->table = hash_clone(table);
@@ -248,7 +248,7 @@ void hash_iter_release(hash_iterator_t *iter)
if (iter->ref == 0) { // ref is unsigned!!! if (iter->ref == 0) { // ref is unsigned!!!
hash_release(iter->table); hash_release(iter->table);
strophe_free(ctx, iter); xmpp_free(ctx, iter);
} }
} }

View File

@@ -47,7 +47,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
len = nlen + dlen + rlen; len = nlen + dlen + rlen;
/* concat components */ /* concat components */
result = strophe_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
if (node != NULL) { if (node != NULL) {
memcpy(result, node, nlen - 1); memcpy(result, node, nlen - 1);
@@ -77,7 +77,7 @@ char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
size_t len; size_t len;
len = strcspn(jid, "/"); len = strcspn(jid, "/");
result = strophe_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, jid, len); memcpy(result, jid, len);
result[len] = '\0'; result[len] = '\0';
@@ -101,7 +101,7 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
c = strchr(jid, '@'); c = strchr(jid, '@');
if (c != NULL) { if (c != NULL) {
result = strophe_alloc(ctx, (c - jid) + 1); result = xmpp_alloc(ctx, (c - jid) + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, jid, (c - jid)); memcpy(result, jid, (c - jid));
result[c - jid] = '\0'; result[c - jid] = '\0';
@@ -133,7 +133,7 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
c++; c++;
} }
dlen = strcspn(c, "/"); /* do not include resource */ dlen = strcspn(c, "/"); /* do not include resource */
result = strophe_alloc(ctx, dlen + 1); result = xmpp_alloc(ctx, dlen + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, c, dlen); memcpy(result, c, dlen);
result[dlen] = '\0'; result[dlen] = '\0';
@@ -155,5 +155,5 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
const char *c; const char *c;
c = strchr(jid, '/'); c = strchr(jid, '/');
return c != NULL ? strophe_strdup(ctx, c + 1) : NULL; return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL;
} }

View File

@@ -60,7 +60,7 @@ static xmpp_ctx_t *mem_ctx = NULL;
static void *parser_mem_malloc(size_t size) static void *parser_mem_malloc(size_t size)
{ {
if (mem_ctx != NULL) if (mem_ctx != NULL)
return strophe_alloc(mem_ctx, size); return xmpp_alloc(mem_ctx, size);
else else
return NULL; return NULL;
} }
@@ -68,7 +68,7 @@ static void *parser_mem_malloc(size_t size)
static void *parser_mem_realloc(void *ptr, size_t size) static void *parser_mem_realloc(void *ptr, size_t size)
{ {
if (mem_ctx != NULL) if (mem_ctx != NULL)
return strophe_realloc(mem_ctx, ptr, size); return xmpp_realloc(mem_ctx, ptr, size);
else else
return NULL; return NULL;
} }
@@ -76,7 +76,7 @@ static void *parser_mem_realloc(void *ptr, size_t size)
static void parser_mem_free(void *ptr) static void parser_mem_free(void *ptr)
{ {
if (mem_ctx != NULL) if (mem_ctx != NULL)
strophe_free(mem_ctx, ptr); xmpp_free(mem_ctx, ptr);
} }
static const XML_Memory_Handling_Suite parser_mem_suite = { static const XML_Memory_Handling_Suite parser_mem_suite = {
@@ -95,11 +95,11 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
c = strchr(nsname, namespace_sep); c = strchr(nsname, namespace_sep);
if (c == NULL) if (c == NULL)
return strophe_strdup(ctx, nsname); return xmpp_strdup(ctx, nsname);
c++; c++;
len = strlen(c); len = strlen(c);
result = strophe_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, c, len); memcpy(result, c, len);
result[len] = '\0'; result[len] = '\0';
@@ -116,7 +116,7 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
c = strchr(nsname, namespace_sep); c = strchr(nsname, namespace_sep);
if (c != NULL) { if (c != NULL) {
result = strophe_alloc(ctx, (c - nsname) + 1); result = xmpp_alloc(ctx, (c - nsname) + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, nsname, (c - nsname)); memcpy(result, nsname, (c - nsname));
result[c - nsname] = '\0'; result[c - nsname] = '\0';
@@ -138,7 +138,7 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
/* namespaced attributes aren't used in xmpp, discard namespace */ /* namespaced attributes aren't used in xmpp, discard namespace */
attr = _xml_name(stanza->ctx, attrs[i]); attr = _xml_name(stanza->ctx, attrs[i]);
xmpp_stanza_set_attribute(stanza, attr, attrs[i + 1]); xmpp_stanza_set_attribute(stanza, attr, attrs[i + 1]);
strophe_free(stanza->ctx, attr); xmpp_free(stanza->ctx, attr);
} }
} }
@@ -155,7 +155,7 @@ static void complete_inner_text(parser_t *parser)
xmpp_stanza_add_child(parser->stanza, stanza); xmpp_stanza_add_child(parser->stanza, stanza);
xmpp_stanza_release(stanza); xmpp_stanza_release(stanza);
} }
strophe_free(parser->ctx, parser->inner_text); xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL; parser->inner_text = NULL;
parser->inner_text_size = 0; parser->inner_text_size = 0;
parser->inner_text_used = 0; parser->inner_text_used = 0;
@@ -181,8 +181,7 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
if (!parser->stanza && parser->depth != 1) { if (!parser->stanza && parser->depth != 1) {
/* something terrible happened */ /* something terrible happened */
/* FIXME: shutdown disconnect */ /* FIXME: shutdown disconnect */
strophe_error(parser->ctx, "parser", xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
"oops, where did our stanza go?");
} else { } else {
child = xmpp_stanza_new(parser->ctx); child = xmpp_stanza_new(parser->ctx);
if (!child) { if (!child) {
@@ -203,9 +202,9 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
} }
if (ns) if (ns)
strophe_free(parser->ctx, ns); xmpp_free(parser->ctx, ns);
if (name) if (name)
strophe_free(parser->ctx, name); xmpp_free(parser->ctx, name);
parser->depth++; parser->depth++;
} }
@@ -247,10 +246,10 @@ static void _characters(void *userdata, const XML_Char *s, int len)
if (parser->inner_text_used + len >= parser->inner_text_size) { if (parser->inner_text_used + len >= parser->inner_text_size) {
parser->inner_text_size = parser->inner_text_size =
parser->inner_text_used + len + 1 + INNER_TEXT_PADDING; parser->inner_text_used + len + 1 + INNER_TEXT_PADDING;
p = strophe_realloc(parser->ctx, parser->inner_text, p = xmpp_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size); parser->inner_text_size);
if (p == NULL) { if (p == NULL) {
strophe_free(parser->ctx, parser->inner_text); xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL; parser->inner_text = NULL;
parser->inner_text_used = 0; parser->inner_text_used = 0;
parser->inner_text_size = 0; parser->inner_text_size = 0;
@@ -271,7 +270,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
{ {
parser_t *parser; parser_t *parser;
parser = strophe_alloc(ctx, sizeof(parser_t)); parser = xmpp_alloc(ctx, sizeof(parser_t));
if (parser != NULL) { if (parser != NULL) {
parser->ctx = ctx; parser->ctx = ctx;
parser->expat = NULL; parser->expat = NULL;
@@ -296,32 +295,18 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
return _xml_name(ctx, nsname); return _xml_name(ctx, nsname);
} }
static void _free_parent_stanza(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *parent;
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
;
xmpp_stanza_release(parent);
}
/* free a parser */ /* free a parser */
void parser_free(parser_t *parser) void parser_free(parser_t *parser)
{ {
if (parser->expat) if (parser->expat)
XML_ParserFree(parser->expat); XML_ParserFree(parser->expat);
if (parser->stanza) {
_free_parent_stanza(parser->stanza);
parser->stanza = NULL;
}
if (parser->inner_text) { if (parser->inner_text) {
strophe_free(parser->ctx, parser->inner_text); xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL; parser->inner_text = NULL;
} }
strophe_free(parser->ctx, parser); xmpp_free(parser->ctx, parser);
} }
/* shuts down and restarts XML parser. true on success */ /* shuts down and restarts XML parser. true on success */
@@ -345,12 +330,12 @@ int parser_reset(parser_t *parser)
} }
if (parser->stanza) { if (parser->stanza) {
_free_parent_stanza(parser->stanza); xmpp_stanza_release(parser->stanza);
parser->stanza = NULL; parser->stanza = NULL;
} }
if (parser->inner_text) { if (parser->inner_text) {
strophe_free(parser->ctx, parser->inner_text); xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL; parser->inner_text = NULL;
} }

View File

@@ -48,12 +48,12 @@ _set_attributes(xmpp_stanza_t *stanza, int nattrs, const xmlChar **attrs)
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */ /* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
for (i = 0; i < nattrs * 5; i += 5) { for (i = 0; i < nattrs * 5; i += 5) {
len = attrs[i + 4] - attrs[i + 3]; len = attrs[i + 4] - attrs[i + 3];
value = strophe_alloc(stanza->ctx, len + 1); value = xmpp_alloc(stanza->ctx, len + 1);
if (value) { if (value) {
memcpy(value, attrs[i + 3], len); memcpy(value, attrs[i + 3], len);
value[len] = '\0'; value[len] = '\0';
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value); xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value);
strophe_free(stanza->ctx, value); xmpp_free(stanza->ctx, value);
} }
} }
} }
@@ -70,7 +70,7 @@ _convert_attrs(parser_t *parser, int nattrs, const xmlChar **attrs)
if (!attrs) if (!attrs)
return NULL; return NULL;
ret = strophe_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *)); ret = xmpp_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *));
if (!ret) if (!ret)
return NULL; return NULL;
memset(ret, 0, (nattrs + 1) * 2 * sizeof(char *)); memset(ret, 0, (nattrs + 1) * 2 * sizeof(char *));
@@ -80,11 +80,11 @@ _convert_attrs(parser_t *parser, int nattrs, const xmlChar **attrs)
o = c * 2; o = c * 2;
len = attrs[i + 4] - attrs[i + 3]; len = attrs[i + 4] - attrs[i + 3];
value = strophe_alloc(parser->ctx, len + 1); value = xmpp_alloc(parser->ctx, len + 1);
if (value) { if (value) {
memcpy(value, attrs[i + 3], len); memcpy(value, attrs[i + 3], len);
value[len] = '\0'; value[len] = '\0';
ret[o] = strophe_strdup(parser->ctx, (char *)attrs[i]); ret[o] = xmpp_strdup(parser->ctx, (char *)attrs[i]);
ret[o + 1] = value; ret[o + 1] = value;
} }
} }
@@ -101,12 +101,12 @@ static void _free_cbattrs(parser_t *parser, char **attrs)
for (i = 0; attrs[i]; i += 2) { for (i = 0; attrs[i]; i += 2) {
if (attrs[i]) if (attrs[i])
strophe_free(parser->ctx, attrs[i]); xmpp_free(parser->ctx, attrs[i]);
if (attrs[i + 1]) if (attrs[i + 1])
strophe_free(parser->ctx, attrs[i + 1]); xmpp_free(parser->ctx, attrs[i + 1]);
} }
strophe_free(parser->ctx, attrs); xmpp_free(parser->ctx, attrs);
} }
static void _start_element(void *userdata, static void _start_element(void *userdata,
@@ -140,8 +140,7 @@ static void _start_element(void *userdata,
if (!parser->stanza && parser->depth != 1) { if (!parser->stanza && parser->depth != 1) {
/* something terrible happened */ /* something terrible happened */
/* FIXME: we should probably trigger a disconnect */ /* FIXME: we should probably trigger a disconnect */
strophe_error(parser->ctx, "parser", xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
"oops, where did our stanza go?");
} else if (!parser->stanza) { } else if (!parser->stanza) {
/* starting a new toplevel stanza */ /* starting a new toplevel stanza */
parser->stanza = xmpp_stanza_new(parser->ctx); parser->stanza = xmpp_stanza_new(parser->ctx);
@@ -236,7 +235,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
{ {
parser_t *parser; parser_t *parser;
parser = strophe_alloc(ctx, sizeof(parser_t)); parser = xmpp_alloc(ctx, sizeof(parser_t));
if (parser != NULL) { if (parser != NULL) {
parser->ctx = ctx; parser->ctx = ctx;
parser->xmlctx = NULL; parser->xmlctx = NULL;
@@ -260,16 +259,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname) char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{ {
return strophe_strdup(ctx, nsname); return xmpp_strdup(ctx, nsname);
}
static void _free_parent_stanza(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *parent;
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
;
xmpp_stanza_release(parent);
} }
/* free a parser */ /* free a parser */
@@ -278,8 +268,8 @@ void parser_free(parser_t *parser)
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza) if (parser->stanza)
_free_parent_stanza(parser->stanza); xmpp_stanza_release(parser->stanza);
strophe_free(parser->ctx, parser); xmpp_free(parser->ctx, parser);
} }
/* shuts down and restarts XML parser. true on success */ /* shuts down and restarts XML parser. true on success */
@@ -288,7 +278,7 @@ int parser_reset(parser_t *parser)
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza) if (parser->stanza)
_free_parent_stanza(parser->stanza); xmpp_stanza_release(parser->stanza);
parser->stanza = NULL; parser->stanza = NULL;
parser->depth = 0; parser->depth = 0;

View File

@@ -23,24 +23,12 @@
#include <string.h> /* memeset */ #include <string.h> /* memeset */
#include <time.h> /* clock, time */ #include <time.h> /* clock, time */
#if !defined(_WIN32) #include "common.h" /* xmpp_alloc, xmpp_free */
#include <unistd.h>
#endif
#if !defined(DONT_USE_GETRANDOM) && defined(__linux__) && \
defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2, 25)
#define USE_GETRANDOM
#include <sys/random.h>
#include <errno.h>
#endif
#endif
#include "common.h" /* strophe_alloc, strophe_free */
#include "ostypes.h" /* uint8_t, uint32_t, size_t */ #include "ostypes.h" /* uint8_t, uint32_t, size_t */
#ifndef USE_GETRANDOM
#include "sha1.h" #include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */
#include "rand.h" /* xmpp_rand_t */
#define outlen SHA1_DIGEST_SIZE #define outlen SHA1_DIGEST_SIZE
#define seedlen (440 / 8) #define seedlen (440 / 8)
@@ -273,7 +261,7 @@ static void xmpp_rand_reseed(xmpp_rand_t *rand)
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx) xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
{ {
xmpp_rand_t *out = strophe_alloc(ctx, sizeof(*out)); xmpp_rand_t *out = xmpp_alloc(ctx, sizeof(*out));
if (out != NULL) { if (out != NULL) {
memset(out, 0, sizeof(*out)); memset(out, 0, sizeof(*out));
} }
@@ -282,71 +270,20 @@ xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand) void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand)
{ {
strophe_free(ctx, rand); xmpp_free(ctx, rand);
} }
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len) void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len)
{ {
int rc; int rc;
size_t gen, tot = 0;
while (tot < len) { rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
gen = len - tot;
if (gen > GENERATE_MAX)
gen = GENERATE_MAX;
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output + tot, gen);
if (rc == RESEED_NEEDED) { if (rc == RESEED_NEEDED) {
xmpp_rand_reseed(rand); xmpp_rand_reseed(rand);
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output + tot, gen); rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
assert(rc == 0); assert(rc == 0);
} }
tot += gen;
} }
}
#else
static int _read_getrandom(void *p, size_t n)
{
unsigned char *q = (unsigned char *)p;
while (n > 0u) {
ssize_t ret = getrandom(q, n, 0);
if (ret < 0) {
if (errno == EINTR) {
continue;
}
return 1;
}
q += ret;
n -= (size_t)ret;
}
return 0;
}
struct _xmpp_rand_t {
char nothing;
};
static xmpp_rand_t _xmpp_rand;
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
{
UNUSED(ctx);
return &_xmpp_rand;
}
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand)
{
UNUSED(ctx);
assert(rand == &_xmpp_rand);
}
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len)
{
assert(rand == &_xmpp_rand);
assert(_read_getrandom(output, len) == 0);
}
#endif
int xmpp_rand(xmpp_rand_t *rand) int xmpp_rand(xmpp_rand_t *rand)
{ {

65
src/rand.h Normal file
View File

@@ -0,0 +1,65 @@
/* rand.h
* strophe XMPP client library -- pseudo-random number generator
*
* Copyright (C) 2014 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
/** @file
* Pseudo-random number generator.
*/
#ifndef __LIBSTROPHE_RAND_H__
#define __LIBSTROPHE_RAND_H__
#include <stddef.h> /* size_t */
#include "strophe.h" /* xmpp_ctx_t */
typedef struct _xmpp_rand_t xmpp_rand_t;
/** Create new xmpp_rand_t object.
*
* @param ctx A Strophe context object
*
* @ingroup Random
*/
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
/** Destroy an xmpp_rand_t object.
*
* @param ctx A Strophe context object
*
* @ingroup Random
*/
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
/** Generate random integer.
* Analogue of rand(3).
*
* @ingroup Random
*/
int xmpp_rand(xmpp_rand_t *rand);
/** Generate random bytes.
* Generates len bytes and stores them to the output buffer.
*
* @ingroup Random
*/
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
/** Generate a nonce that is printable randomized string.
* This function doesn't allocate memory and doesn't fail.
*
* @param output A buffer where a NULL-terminated string will be placed.
* The string will contain len-1 printable symbols.
* @param len Number of bytes reserved for the output string, including
* end of line '\0'.
*
* @ingroup Random
*/
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
#endif /* __LIBSTROPHE_RAND_H__ */

View File

@@ -179,8 +179,8 @@ int resolver_srv_lookup(xmpp_ctx_t *ctx,
(void)buf; (void)buf;
(void)len; (void)len;
strophe_snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service, xmpp_snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service, proto,
proto, domain); domain);
*srv_rr_list = NULL; *srv_rr_list = NULL;
@@ -196,7 +196,7 @@ int resolver_srv_lookup(xmpp_ctx_t *ctx,
return set; return set;
#endif /* _WIN32 */ #endif /* _WIN32 */
buf = strophe_alloc(ctx, RESOLVER_BUF_MAX); buf = xmpp_alloc(ctx, RESOLVER_BUF_MAX);
if (buf == NULL) if (buf == NULL)
return XMPP_DOMAIN_NOT_FOUND; return XMPP_DOMAIN_NOT_FOUND;
@@ -210,7 +210,7 @@ int resolver_srv_lookup(xmpp_ctx_t *ctx,
if (len > 0) if (len > 0)
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list); set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
strophe_free(ctx, buf); xmpp_free(ctx, buf);
#endif /* HAVE_CARES */ #endif /* HAVE_CARES */
@@ -223,7 +223,7 @@ void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
while (srv_rr_list != NULL) { while (srv_rr_list != NULL) {
rr = srv_rr_list->next; rr = srv_rr_list->next;
strophe_free(ctx, srv_rr_list); xmpp_free(ctx, srv_rr_list);
srv_rr_list = rr; srv_rr_list = rr;
} }
} }
@@ -321,9 +321,6 @@ static unsigned message_name_get(const unsigned char *buf,
if (i >= buf_len) if (i >= buf_len)
return 0; return 0;
pointer = (label_len & 0x3f) << 8 | buf[i++]; pointer = (label_len & 0x3f) << 8 | buf[i++];
/* Prevent infinite looping */
if (pointer == buf_offset)
return 0;
if (name != NULL && name_len >= name_max && name_max > 0) { if (name != NULL && name_len >= name_max && name_max > 0) {
/* We have filled the name buffer. Don't pass it recursively. */ /* We have filled the name buffer. Don't pass it recursively. */
name[name_max - 1] = '\0'; name[name_max - 1] = '\0';
@@ -434,7 +431,7 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
rdlength = xmpp_ntohs_ptr(&buf[j + 8]); rdlength = xmpp_ntohs_ptr(&buf[j + 8]);
j += 10; j += 10;
if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) { if (type == MESSAGE_T_SRV && class == MESSAGE_C_IN) {
rr = strophe_alloc(ctx, sizeof(*rr)); rr = xmpp_alloc(ctx, sizeof(*rr));
rr->next = *srv_rr_list; rr->next = *srv_rr_list;
rr->priority = xmpp_ntohs_ptr(&buf[j]); rr->priority = xmpp_ntohs_ptr(&buf[j]);
rr->weight = xmpp_ntohs_ptr(&buf[j + 2]); rr->weight = xmpp_ntohs_ptr(&buf[j + 2]);
@@ -444,7 +441,7 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
if (name_len > 0) if (name_len > 0)
*srv_rr_list = rr; *srv_rr_list = rr;
else else
strophe_free(ctx, rr); /* skip broken record */ xmpp_free(ctx, rr); /* skip broken record */
} }
j += rdlength; j += rdlength;
} }
@@ -483,7 +480,7 @@ static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
item = srv; item = srv;
while (item != NULL) { while (item != NULL) {
rr = strophe_alloc(ctx, sizeof(*rr)); rr = xmpp_alloc(ctx, sizeof(*rr));
if (rr == NULL) if (rr == NULL)
break; break;
rr->next = *srv_rr_list; rr->next = *srv_rr_list;
@@ -708,14 +705,14 @@ static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx,
while (current) { while (current) {
if (current->wType == DNS_TYPE_SRV) { if (current->wType == DNS_TYPE_SRV) {
rr = strophe_alloc(ctx, sizeof(*rr)); rr = xmpp_alloc(ctx, sizeof(*rr));
if (rr == NULL) if (rr == NULL)
break; break;
rr->next = *srv_rr_list; rr->next = *srv_rr_list;
rr->port = current->Data.Srv.wPort; rr->port = current->Data.Srv.wPort;
rr->priority = current->Data.Srv.wPriority; rr->priority = current->Data.Srv.wPriority;
rr->weight = current->Data.Srv.wWeight; rr->weight = current->Data.Srv.wWeight;
strophe_snprintf(rr->target, sizeof(rr->target), "%s", xmpp_snprintf(rr->target, sizeof(rr->target), "%s",
current->Data.Srv.pNameTarget); current->Data.Srv.pNameTarget);
*srv_rr_list = rr; *srv_rr_list = rr;
} }

View File

@@ -22,6 +22,7 @@
#include "sasl.h" #include "sasl.h"
#include "md5.h" #include "md5.h"
#include "scram.h" #include "scram.h"
#include "rand.h"
#include "util.h" #include "util.h"
/* strtok_s() has appeared in visual studio 2005. /* strtok_s() has appeared in visual studio 2005.
@@ -48,14 +49,14 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password)
idlen = strlen(authid); idlen = strlen(authid);
passlen = strlen(password); passlen = strlen(password);
msglen = 2 + idlen + passlen; msglen = 2 + idlen + passlen;
msg = strophe_alloc(ctx, msglen); msg = xmpp_alloc(ctx, msglen);
if (msg != NULL) { if (msg != NULL) {
msg[0] = '\0'; msg[0] = '\0';
memcpy(msg + 1, authid, idlen); memcpy(msg + 1, authid, idlen);
msg[1 + idlen] = '\0'; msg[1 + idlen] = '\0';
memcpy(msg + 1 + idlen + 1, password, passlen); memcpy(msg + 1 + idlen + 1, password, passlen);
result = xmpp_base64_encode(ctx, (unsigned char *)msg, msglen); result = xmpp_base64_encode(ctx, (unsigned char *)msg, msglen);
strophe_free(ctx, msg); xmpp_free(ctx, msg);
} }
return result; return result;
@@ -68,7 +69,7 @@ static char *_make_string(xmpp_ctx_t *ctx, const char *s, unsigned len)
{ {
char *result; char *result;
result = strophe_alloc(ctx, len + 1); result = xmpp_alloc(ctx, len + 1);
if (result != NULL) { if (result != NULL) {
memcpy(result, s, len); memcpy(result, s, len);
result[len] = '\0'; result[len] = '\0';
@@ -82,7 +83,7 @@ static char *_make_quoted(xmpp_ctx_t *ctx, const char *s)
char *result; char *result;
size_t len = strlen(s); size_t len = strlen(s);
result = strophe_alloc(ctx, len + 3); result = xmpp_alloc(ctx, len + 3);
if (result != NULL) { if (result != NULL) {
result[0] = '"'; result[0] = '"';
memcpy(result + 1, s, len); memcpy(result + 1, s, len);
@@ -102,11 +103,11 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
text = (unsigned char *)xmpp_base64_decode_str(ctx, msg, strlen(msg)); text = (unsigned char *)xmpp_base64_decode_str(ctx, msg, strlen(msg));
if (text == NULL) { if (text == NULL) {
strophe_error(ctx, "SASL", "couldn't Base64 decode challenge!"); xmpp_error(ctx, "SASL", "couldn't Base64 decode challenge!");
return NULL; return NULL;
} }
result = hash_new(ctx, 10, strophe_free); result = hash_new(ctx, 10, xmpp_free);
if (result != NULL) { if (result != NULL) {
s = text; s = text;
while (*s != '\0') { while (*s != '\0') {
@@ -144,16 +145,16 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
s = t; s = t;
} }
if (value == NULL) { if (value == NULL) {
strophe_free(ctx, key); xmpp_free(ctx, key);
break; break;
} }
/* TODO: check for collisions per spec */ /* TODO: check for collisions per spec */
hash_add(result, key, value); hash_add(result, key, value);
/* hash table now owns the value, free the key */ /* hash table now owns the value, free the key */
strophe_free(ctx, key); xmpp_free(ctx, key);
} }
} }
strophe_free(ctx, text); xmpp_free(ctx, text);
return result; return result;
} }
@@ -181,7 +182,7 @@ _add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote)
/* allocate a zero-length string if necessary */ /* allocate a zero-length string if necessary */
if (buf == NULL) { if (buf == NULL) {
buf = strophe_alloc(ctx, 1); buf = xmpp_alloc(ctx, 1);
buf[0] = '\0'; buf[0] = '\0';
} }
if (buf == NULL) if (buf == NULL)
@@ -191,7 +192,7 @@ _add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote)
olen = strlen(buf); olen = strlen(buf);
value = hash_get(table, key); value = hash_get(table, key);
if (value == NULL) { if (value == NULL) {
strophe_error(ctx, "SASL", "couldn't retrieve value for '%s'", key); xmpp_error(ctx, "SASL", "couldn't retrieve value for '%s'", key);
value = ""; value = "";
} }
if (quote) { if (quote) {
@@ -204,7 +205,7 @@ _add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote)
keylen = strlen(key); keylen = strlen(key);
valuelen = strlen(qvalue); valuelen = strlen(qvalue);
nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1; nlen = (olen ? 1 : 0) + keylen + 1 + valuelen + 1;
buf = strophe_realloc(ctx, buf, olen + nlen); buf = xmpp_realloc(ctx, buf, olen + nlen);
if (buf != NULL) { if (buf != NULL) {
c = buf + olen; c = buf + olen;
@@ -219,7 +220,7 @@ _add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote)
} }
if (quote) if (quote)
strophe_free(ctx, (char *)qvalue); xmpp_free(ctx, (char *)qvalue);
return buf; return buf;
} }
@@ -254,7 +255,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
/* parse the challenge */ /* parse the challenge */
table = _parse_digest_challenge(ctx, challenge); table = _parse_digest_challenge(ctx, challenge);
if (table == NULL) { if (table == NULL) {
strophe_error(ctx, "SASL", "couldn't parse digest challenge"); xmpp_error(ctx, "SASL", "couldn't parse digest challenge");
return NULL; return NULL;
} }
@@ -265,18 +266,18 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
server */ server */
realm = hash_get(table, "realm"); realm = hash_get(table, "realm");
if (realm == NULL || strlen(realm) == 0) { if (realm == NULL || strlen(realm) == 0) {
hash_add(table, "realm", strophe_strdup(ctx, domain)); hash_add(table, "realm", xmpp_strdup(ctx, domain));
realm = hash_get(table, "realm"); realm = hash_get(table, "realm");
} }
/* add our response fields */ /* add our response fields */
hash_add(table, "username", strophe_strdup(ctx, node)); hash_add(table, "username", xmpp_strdup(ctx, node));
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce)); xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
hash_add(table, "cnonce", strophe_strdup(ctx, cnonce)); hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
hash_add(table, "nc", strophe_strdup(ctx, "00000001")); hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
if (hash_get(table, "qop") == NULL) if (hash_get(table, "qop") == NULL)
hash_add(table, "qop", strophe_strdup(ctx, "auth")); hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
value = strophe_alloc(ctx, 5 + strlen(domain) + 1); value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
memcpy(value, "xmpp/", 5); memcpy(value, "xmpp/", 5);
memcpy(value + 5, domain, strlen(domain)); memcpy(value + 5, domain, strlen(domain));
value[5 + strlen(domain)] = '\0'; value[5 + strlen(domain)] = '\0';
@@ -342,7 +343,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
MD5Update(&MD5, (unsigned char *)hex, 32); MD5Update(&MD5, (unsigned char *)hex, 32);
MD5Final(digest, &MD5); MD5Final(digest, &MD5);
response = strophe_alloc(ctx, 32 + 1); response = xmpp_alloc(ctx, 32 + 1);
_digest_to_hex((char *)digest, hex); _digest_to_hex((char *)digest, hex);
memcpy(response, hex, 32); memcpy(response, hex, 32);
response[32] = '\0'; response[32] = '\0';
@@ -360,13 +361,13 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx,
result = _add_key(ctx, table, "response", result, 0); result = _add_key(ctx, table, "response", result, 0);
result = _add_key(ctx, table, "charset", result, 0); result = _add_key(ctx, table, "charset", result, 0);
strophe_free(ctx, node); xmpp_free(ctx, node);
strophe_free(ctx, domain); xmpp_free(ctx, domain);
hash_release(table); /* also frees value strings */ hash_release(table); /* also frees value strings */
/* reuse response for the base64 encode of our result */ /* reuse response for the base64 encode of our result */
response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result)); response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result));
strophe_free(ctx, result); xmpp_free(ctx, result);
return response; return response;
} }
@@ -400,7 +401,7 @@ char *sasl_scram(xmpp_ctx_t *ctx,
UNUSED(jid); UNUSED(jid);
tmp = strophe_strdup(ctx, challenge); tmp = xmpp_strdup(ctx, challenge);
if (!tmp) { if (!tmp) {
return NULL; return NULL;
} }
@@ -428,20 +429,20 @@ char *sasl_scram(xmpp_ctx_t *ctx,
ival = strtol(i, &saveptr, 10); ival = strtol(i, &saveptr, 10);
auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge); auth_len = 10 + strlen(r) + strlen(first_bare) + strlen(challenge);
auth = strophe_alloc(ctx, auth_len); auth = xmpp_alloc(ctx, auth_len);
if (!auth) { if (!auth) {
goto out_sval; goto out_sval;
} }
/* "c=biws," + r + ",p=" + sign_b64 + '\0' */ /* "c=biws," + r + ",p=" + sign_b64 + '\0' */
response_len = 7 + strlen(r) + 3 + ((alg->digest_size + 2) / 3 * 4) + 1; response_len = 7 + strlen(r) + 3 + ((alg->digest_size + 2) / 3 * 4) + 1;
response = strophe_alloc(ctx, response_len); response = xmpp_alloc(ctx, response_len);
if (!response) { if (!response) {
goto out_auth; goto out_auth;
} }
strophe_snprintf(response, response_len, "c=biws,%s", r); xmpp_snprintf(response, response_len, "c=biws,%s", r);
strophe_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge, xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
response); response);
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval, SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval,
@@ -456,12 +457,12 @@ char *sasl_scram(xmpp_ctx_t *ctx,
/* Check for buffer overflow */ /* Check for buffer overflow */
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) { if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
strophe_free(ctx, sign_b64); xmpp_free(ctx, sign_b64);
goto out_response; goto out_response;
} }
strcat(response, ",p="); strcat(response, ",p=");
strcat(response, sign_b64); strcat(response, sign_b64);
strophe_free(ctx, sign_b64); xmpp_free(ctx, sign_b64);
response_b64 = response_b64 =
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response)); xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response));
@@ -471,12 +472,12 @@ char *sasl_scram(xmpp_ctx_t *ctx,
result = response_b64; result = response_b64;
out_response: out_response:
strophe_free(ctx, response); xmpp_free(ctx, response);
out_auth: out_auth:
strophe_free(ctx, auth); xmpp_free(ctx, auth);
out_sval: out_sval:
strophe_free(ctx, sval); xmpp_free(ctx, sval);
out: out:
strophe_free(ctx, tmp); xmpp_free(ctx, tmp);
return result; return result;
} }

View File

@@ -61,7 +61,7 @@
/* JAM: we don't need this - #include "config.h" */ /* JAM: we don't need this - #include "config.h" */
/* JAM: changed declarations to strophe_snprintf and strophe_vsnprintf to /* JAM: changed declarations to xmpp_snprintf and xmpp_vsnprintf to
avoid namespace collision. */ avoid namespace collision. */
#include "snprintf.h" #include "snprintf.h"
@@ -706,7 +706,7 @@ static int dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
return 1; return 1;
} }
int strophe_vsnprintf(char *str, size_t count, const char *fmt, va_list args) int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{ {
if (str != NULL && count > 0) if (str != NULL && count > 0)
str[0] = 0; str[0] = 0;
@@ -716,13 +716,13 @@ int strophe_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
#ifndef HAVE_SNPRINTF #ifndef HAVE_SNPRINTF
/* VARARGS3 */ /* VARARGS3 */
int strophe_snprintf(char *str, size_t count, const char *fmt, ...) int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{ {
VA_LOCAL_DECL; VA_LOCAL_DECL;
int total; int total;
VA_START(fmt); VA_START(fmt);
total = strophe_vsnprintf(str, count, fmt, ap); total = xmpp_vsnprintf(str, count, fmt, ap);
VA_END; VA_END;
return total; return total;
} }

View File

@@ -20,15 +20,15 @@
#endif #endif
#ifdef HAVE_SNPRINTF #ifdef HAVE_SNPRINTF
#define strophe_snprintf snprintf #define xmpp_snprintf snprintf
#else #else
int strophe_snprintf(char *str, size_t count, const char *fmt, ...); int xmpp_snprintf(char *str, size_t count, const char *fmt, ...);
#endif #endif
#ifdef HAVE_VSNPRINTF #ifdef HAVE_VSNPRINTF
#define strophe_vsnprintf vsnprintf #define xmpp_vsnprintf vsnprintf
#else #else
int strophe_vsnprintf(char *str, size_t count, const char *fmt, va_list arg); int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg);
#endif #endif
#endif /* __LIBSTROPHE_SNPRINTF_H__ */ #endif /* __LIBSTROPHE_SNPRINTF_H__ */

View File

@@ -33,7 +33,8 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#include "common.h" #include "sock.h"
#include "snprintf.h"
void sock_initialize(void) void sock_initialize(void)
{ {
@@ -68,14 +69,14 @@ static int _in_progress(int error)
#endif #endif
} }
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port) sock_t sock_connect(const char *host, unsigned short port)
{ {
sock_t sock; sock_t sock;
char service[6]; char service[6];
struct addrinfo *res, *ainfo, hints; struct addrinfo *res, *ainfo, hints;
int err; int err;
strophe_snprintf(service, 6, "%u", port); xmpp_snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@@ -94,14 +95,6 @@ sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port)
if (sock < 0) if (sock < 0)
continue; continue;
if (conn->sockopt_cb != NULL)
err = (conn->sockopt_cb)(conn, &sock);
if (err != 0) {
sock_close(sock);
continue;
}
err = sock_set_nonblocking(sock); err = sock_set_nonblocking(sock);
if (err == 0) { if (err == 0) {
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen); err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
@@ -116,17 +109,12 @@ sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port)
return sock; return sock;
} }
int sock_set_keepalive(sock_t sock, int sock_set_keepalive(sock_t sock, int timeout, int interval)
int timeout,
int interval,
int count,
unsigned int user_timeout)
{ {
int ret; int ret;
int optval = (timeout && interval) ? 1 : 0; int optval = (timeout && interval) ? 1 : 0;
UNUSED(count); /* This function doesn't change maximum number of keepalive probes */
UNUSED(user_timeout);
#ifdef _WIN32 #ifdef _WIN32
struct tcp_keepalive ka; struct tcp_keepalive ka;
@@ -161,57 +149,11 @@ int sock_set_keepalive(sock_t sock,
return ret; return ret;
#endif /* TCP_KEEPINTVL */ #endif /* TCP_KEEPINTVL */
} }
if (count) {
#ifdef TCP_KEEPCNT
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count));
if (ret < 0)
return ret;
#endif /* TCP_KEEPCNT */
}
if (user_timeout) {
#ifdef TCP_USER_TIMEOUT
ret = setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout,
sizeof(user_timeout));
if (ret < 0)
return ret;
#elif defined(TCP_RXT_CONNDROPTIME)
int rxt = user_timeout / 1000;
ret = setsockopt(sock, IPPROTO_TCP, TCP_RXT_CONNDROPTIME, &rxt,
sizeof(rxt));
if (ret < 0)
return ret;
#endif /* TCP_USER_TIMEOUT */
}
#endif /* _WIN32 */ #endif /* _WIN32 */
return ret; return ret;
} }
/** Example sockopt callback function
* An example function that can be used to set reasonable default keepalive
* options on sockets when registered for a connection with
* xmpp_conn_set_sockopt_callback()
*
* @param conn a Strophe connection object
* @param socket pointer to a socket descriptor
*
* @see xmpp_sockopt_callback for details on the `socket` parameter
* @ingroup Connections
*/
int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *socket)
{
sock_t sock = *((sock_t *)socket);
return sock_set_keepalive(
sock, conn->ka_timeout, conn->ka_interval, conn->ka_count,
conn->ka_count
? (conn->ka_timeout + conn->ka_interval * conn->ka_count) * 1000
: 0);
}
int sock_close(sock_t sock) int sock_close(sock_t sock)
{ {
#ifdef _WIN32 #ifdef _WIN32

View File

@@ -22,9 +22,6 @@
typedef int sock_t; typedef int sock_t;
#else #else
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <mstcpip.h> /* tcp_keepalive */
typedef SOCKET sock_t; typedef SOCKET sock_t;
#endif #endif
@@ -33,7 +30,7 @@ void sock_shutdown(void);
int sock_error(void); int sock_error(void);
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port); sock_t sock_connect(const char *host, unsigned short port);
int sock_close(sock_t sock); int sock_close(sock_t sock);
int sock_set_blocking(sock_t sock); int sock_set_blocking(sock_t sock);
@@ -43,10 +40,6 @@ int sock_write(sock_t sock, const void *buff, size_t len);
int sock_is_recoverable(int error); int sock_is_recoverable(int error);
/* checks for an error after connect, return 0 if connect successful */ /* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(sock_t sock); int sock_connect_error(sock_t sock);
int sock_set_keepalive(sock_t sock, int sock_set_keepalive(sock_t sock, int timeout, int interval);
int timeout,
int interval,
int count,
unsigned int user_timeout);
#endif /* __LIBSTROPHE_SOCK_H__ */ #endif /* __LIBSTROPHE_SOCK_H__ */

View File

@@ -39,7 +39,7 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
{ {
xmpp_stanza_t *stanza; xmpp_stanza_t *stanza;
stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t)); stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
if (stanza != NULL) { if (stanza != NULL) {
stanza->ref = 1; stanza->ref = 1;
stanza->ctx = ctx; stanza->ctx = ctx;
@@ -124,7 +124,7 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t *stanza)
copy->type = stanza->type; copy->type = stanza->type;
if (stanza->data) { if (stanza->data) {
copy->data = strophe_strdup(stanza->ctx, stanza->data); copy->data = xmpp_strdup(stanza->ctx, stanza->data);
if (!copy->data) if (!copy->data)
goto copy_error; goto copy_error;
} }
@@ -188,8 +188,8 @@ int xmpp_stanza_release(xmpp_stanza_t *stanza)
if (stanza->attributes) if (stanza->attributes)
hash_release(stanza->attributes); hash_release(stanza->attributes);
if (stanza->data) if (stanza->data)
strophe_free(stanza->ctx, stanza->data); xmpp_free(stanza->ctx, stanza->data);
strophe_free(stanza->ctx, stanza); xmpp_free(stanza->ctx, stanza);
released = 1; released = 1;
} }
@@ -263,7 +263,7 @@ static char *_escape_xml(xmpp_ctx_t *ctx, char *text)
len++; len++;
} }
} }
if ((buf = strophe_alloc(ctx, (len + 1) * sizeof(char))) == NULL) if ((buf = xmpp_alloc(ctx, (len + 1) * sizeof(char))) == NULL)
return NULL; /* Error */ return NULL; /* Error */
dst = buf; dst = buf;
for (src = text; *src != '\0'; src++) { for (src = text; *src != '\0'; src++) {
@@ -336,8 +336,8 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
tmp = _escape_xml(stanza->ctx, stanza->data); tmp = _escape_xml(stanza->ctx, stanza->data);
if (tmp == NULL) if (tmp == NULL)
return XMPP_EMEM; return XMPP_EMEM;
ret = strophe_snprintf(ptr, left, "%s", tmp); ret = xmpp_snprintf(ptr, left, "%s", tmp);
strophe_free(stanza->ctx, tmp); xmpp_free(stanza->ctx, tmp);
if (ret < 0) if (ret < 0)
return XMPP_EMEM; return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
@@ -346,7 +346,7 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
return XMPP_EINVOP; return XMPP_EINVOP;
/* write beginning of tag and attributes */ /* write beginning of tag and attributes */
ret = strophe_snprintf(ptr, left, "<%s", stanza->data); ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
if (ret < 0) if (ret < 0)
return XMPP_EMEM; return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
@@ -374,8 +374,8 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
hash_iter_release(iter); hash_iter_release(iter);
return XMPP_EMEM; return XMPP_EMEM;
} }
ret = strophe_snprintf(ptr, left, " %s=\"%s\"", key, tmp); ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
strophe_free(stanza->ctx, tmp); xmpp_free(stanza->ctx, tmp);
if (ret < 0) { if (ret < 0) {
hash_iter_release(iter); hash_iter_release(iter);
return XMPP_EMEM; return XMPP_EMEM;
@@ -387,7 +387,7 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
if (!stanza->children) { if (!stanza->children) {
/* write end if singleton tag */ /* write end if singleton tag */
ret = strophe_snprintf(ptr, left, "/>"); ret = xmpp_snprintf(ptr, left, "/>");
if (ret < 0) if (ret < 0)
return XMPP_EMEM; return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
@@ -395,7 +395,7 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
/* this stanza has child stanzas */ /* this stanza has child stanzas */
/* write end of start tag */ /* write end of start tag */
ret = strophe_snprintf(ptr, left, ">"); ret = xmpp_snprintf(ptr, left, ">");
if (ret < 0) if (ret < 0)
return XMPP_EMEM; return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
@@ -413,7 +413,7 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
} }
/* write end tag */ /* write end tag */
ret = strophe_snprintf(ptr, left, "</%s>", stanza->data); ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
if (ret < 0) if (ret < 0)
return XMPP_EMEM; return XMPP_EMEM;
@@ -447,7 +447,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char **buf, size_t *buflen)
/* allocate a default sized buffer and attempt to render */ /* allocate a default sized buffer and attempt to render */
length = 1024; length = 1024;
buffer = strophe_alloc(stanza->ctx, length); buffer = xmpp_alloc(stanza->ctx, length);
if (!buffer) { if (!buffer) {
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
@@ -456,16 +456,16 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char **buf, size_t *buflen)
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if (ret < 0) { if (ret < 0) {
strophe_free(stanza->ctx, buffer); xmpp_free(stanza->ctx, buffer);
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return ret; return ret;
} }
if ((size_t)ret > length - 1) { if ((size_t)ret > length - 1) {
tmp = strophe_realloc(stanza->ctx, buffer, ret + 1); tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
if (!tmp) { if (!tmp) {
strophe_free(stanza->ctx, buffer); xmpp_free(stanza->ctx, buffer);
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return XMPP_EMEM; return XMPP_EMEM;
@@ -475,7 +475,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char **buf, size_t *buflen)
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if ((size_t)ret > length - 1) { if ((size_t)ret > length - 1) {
strophe_free(stanza->ctx, buffer); xmpp_free(stanza->ctx, buffer);
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return XMPP_EMEM; return XMPP_EMEM;
@@ -506,10 +506,10 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *name)
return XMPP_EINVOP; return XMPP_EINVOP;
if (stanza->data) if (stanza->data)
strophe_free(stanza->ctx, stanza->data); xmpp_free(stanza->ctx, stanza->data);
stanza->type = XMPP_STANZA_TAG; stanza->type = XMPP_STANZA_TAG;
stanza->data = strophe_strdup(stanza->ctx, name); stanza->data = xmpp_strdup(stanza->ctx, name);
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK; return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
} }
@@ -615,19 +615,19 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t *stanza,
return XMPP_EINVOP; return XMPP_EINVOP;
if (!stanza->attributes) { if (!stanza->attributes) {
stanza->attributes = hash_new(stanza->ctx, 8, strophe_free); stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
if (!stanza->attributes) if (!stanza->attributes)
return XMPP_EMEM; return XMPP_EMEM;
} }
val = strophe_strdup(stanza->ctx, value); val = xmpp_strdup(stanza->ctx, value);
if (!val) { if (!val) {
return XMPP_EMEM; return XMPP_EMEM;
} }
rc = hash_add(stanza->attributes, key, val); rc = hash_add(stanza->attributes, key, val);
if (rc < 0) { if (rc < 0) {
strophe_free(stanza->ctx, val); xmpp_free(stanza->ctx, val);
return XMPP_EMEM; return XMPP_EMEM;
} }
@@ -728,8 +728,8 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *text)
stanza->type = XMPP_STANZA_TEXT; stanza->type = XMPP_STANZA_TEXT;
if (stanza->data) if (stanza->data)
strophe_free(stanza->ctx, stanza->data); xmpp_free(stanza->ctx, stanza->data);
stanza->data = strophe_strdup(stanza->ctx, text); stanza->data = xmpp_strdup(stanza->ctx, text);
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK; return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
} }
@@ -758,8 +758,8 @@ int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
stanza->type = XMPP_STANZA_TEXT; stanza->type = XMPP_STANZA_TEXT;
if (stanza->data) if (stanza->data)
strophe_free(stanza->ctx, stanza->data); xmpp_free(stanza->ctx, stanza->data);
stanza->data = strophe_alloc(stanza->ctx, size + 1); stanza->data = xmpp_alloc(stanza->ctx, size + 1);
if (!stanza->data) if (!stanza->data)
return XMPP_EMEM; return XMPP_EMEM;
@@ -844,82 +844,6 @@ const char *xmpp_stanza_get_from(xmpp_stanza_t *stanza)
return xmpp_stanza_get_attribute(stanza, "from"); return xmpp_stanza_get_attribute(stanza, "from");
} }
/** Get the first child of stanza following a path-like list of names.
* This function searches the children and their children that match
* the given path.
*
* * "name" - Search 'name'
*
* * "name[@ns='foo']" - Search 'name' which is in the namespace 'foo'
*
* The Syntax to pass namespaces is inspired by the XPATH way of passing
* attributes.
*
* The namespace syntax only supports single quotes `'`.
*
* The \ref XMPP_STANZA_NAME_IN_NS macro is provided as a helper for names
* in namespaces.
*
* @param stanza a Strophe stanza object
* @param ... a var-args list that must be terminated by a NULL entry
*
* @return the matching child stanza object or NULL if no match was found
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_get_child_by_path(xmpp_stanza_t *stanza, ...)
{
xmpp_stanza_t *child = NULL;
char *p, *tok, *attr, *saveattr, *ns = NULL;
const char *xmlns;
va_list ap;
va_start(ap, stanza);
while ((p = va_arg(ap, char *)) != NULL) {
tok = strophe_strdup(stanza->ctx, p);
if (!tok) {
child = NULL;
break;
}
saveattr = ns = NULL;
attr = strophe_strtok_r(tok, "[", &saveattr);
if (attr) {
attr = strophe_strtok_r(NULL, "]", &saveattr);
if (attr) {
if (!strncmp(attr, "@ns='", 5)) {
ns = attr + 5;
strophe_strtok_r(ns, "'", &saveattr);
}
}
}
if (!child) {
if (strcmp(xmpp_stanza_get_name(stanza), tok))
goto error_out;
if (ns) {
xmlns = xmpp_stanza_get_ns(stanza);
if (!xmlns || strcmp(xmlns, ns))
goto error_out;
}
child = stanza;
} else {
if (!ns)
child = xmpp_stanza_get_child_by_name(child, tok);
else
child = xmpp_stanza_get_child_by_name_and_ns(child, tok, ns);
}
error_out:
strophe_free(stanza->ctx, tok);
if (!child)
break;
}
va_end(ap);
return p == NULL ? child : NULL;
}
/** Get the first child of stanza with name. /** Get the first child of stanza with name.
* This function searches all the immediate children of stanza for a child * This function searches all the immediate children of stanza for a child
* stanza that matches the name. The first matching child is returned. * stanza that matches the name. The first matching child is returned.
@@ -1053,7 +977,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t *stanza)
if (stanza->type == XMPP_STANZA_TEXT) { if (stanza->type == XMPP_STANZA_TEXT) {
if (stanza->data) if (stanza->data)
return strophe_strdup(stanza->ctx, stanza->data); return xmpp_strdup(stanza->ctx, stanza->data);
else else
return NULL; return NULL;
} }
@@ -1066,7 +990,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t *stanza)
if (len == 0) if (len == 0)
return NULL; return NULL;
text = (char *)strophe_alloc(stanza->ctx, len + 1); text = (char *)xmpp_alloc(stanza->ctx, len + 1);
if (!text) if (!text)
return NULL; return NULL;
@@ -1213,8 +1137,8 @@ int xmpp_stanza_del_attribute(xmpp_stanza_t *stanza, const char *name)
} }
/** Create a stanza object in reply to another. /** Create a stanza object in reply to another.
* This function makes a copy of a stanza object with the attribute "to" set * This function makes a copy of a stanza object with the attribute to set
* its original "from". * its original from.
* The stanza will have a reference count of one, so the caller does not * The stanza will have a reference count of one, so the caller does not
* need to clone it. * need to clone it.
* *
@@ -1241,7 +1165,7 @@ xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t *stanza)
copy->type = stanza->type; copy->type = stanza->type;
if (stanza->data) { if (stanza->data) {
copy->data = strophe_strdup(stanza->ctx, stanza->data); copy->data = xmpp_strdup(stanza->ctx, stanza->data);
if (!copy->data) if (!copy->data)
goto copy_error; goto copy_error;
} }
@@ -1271,7 +1195,7 @@ copy_error:
* Check https://tools.ietf.org/html/rfc6120#section-8.3 for details. * Check https://tools.ietf.org/html/rfc6120#section-8.3 for details.
* *
* @param stanza a Strophe stanza object * @param stanza a Strophe stanza object
* @param error_type type attribute in the `<error/>` child element * @param error_type type attribute in the <error/> child element
* @param condition the defined-condition (e.g. "item-not-found") * @param condition the defined-condition (e.g. "item-not-found")
* @param text optional description, may be NULL * @param text optional description, may be NULL
* *
@@ -1286,9 +1210,9 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
{ {
xmpp_ctx_t *ctx = stanza->ctx; xmpp_ctx_t *ctx = stanza->ctx;
xmpp_stanza_t *reply = NULL; xmpp_stanza_t *reply = NULL;
xmpp_stanza_t *error = NULL; xmpp_stanza_t *error;
xmpp_stanza_t *item = NULL; xmpp_stanza_t *item;
xmpp_stanza_t *text_stanza = NULL; xmpp_stanza_t *text_stanza;
const char *to; const char *to;
if (!error_type || !condition) if (!error_type || !condition)
@@ -1297,53 +1221,41 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
reply = xmpp_stanza_reply(stanza); reply = xmpp_stanza_reply(stanza);
if (!reply) if (!reply)
goto quit_err; goto quit_err;
if (xmpp_stanza_set_type(reply, "error") != XMPP_EOK)
goto quit_err; xmpp_stanza_set_type(reply, "error");
to = xmpp_stanza_get_to(stanza); to = xmpp_stanza_get_to(stanza);
if (to) if (to)
if (xmpp_stanza_set_from(reply, to) != XMPP_EOK) xmpp_stanza_set_from(reply, to);
goto quit_err;
error = xmpp_stanza_new(ctx); error = xmpp_stanza_new(ctx);
if (!error) if (!error)
goto quit_err; goto quit_err;
if (xmpp_stanza_set_name(error, "error") != XMPP_EOK) xmpp_stanza_set_name(error, "error");
goto quit_err; xmpp_stanza_set_type(error, error_type);
if (xmpp_stanza_set_type(error, error_type) != XMPP_EOK) xmpp_stanza_add_child(reply, error);
goto quit_err;
if (xmpp_stanza_add_child(reply, error) != XMPP_EOK)
goto quit_err;
xmpp_stanza_release(error); xmpp_stanza_release(error);
item = xmpp_stanza_new(ctx); item = xmpp_stanza_new(ctx);
if (!item) if (!item)
goto quit_err; goto quit_err;
if (xmpp_stanza_set_name(item, condition) != XMPP_EOK) xmpp_stanza_set_name(item, condition);
goto quit_err; xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
if (xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF) != XMPP_EOK) xmpp_stanza_add_child(error, item);
goto quit_err;
if (xmpp_stanza_add_child(error, item) != XMPP_EOK)
goto quit_err;
xmpp_stanza_release(item); xmpp_stanza_release(item);
if (text) { if (text) {
item = xmpp_stanza_new(ctx); item = xmpp_stanza_new(ctx);
if (!item) if (!item)
goto quit_err; goto quit_err;
if (xmpp_stanza_set_name(item, "text") != XMPP_EOK) xmpp_stanza_set_name(item, "text");
goto quit_err; xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
if (xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF) != XMPP_EOK) xmpp_stanza_add_child(error, item);
goto quit_err;
if (xmpp_stanza_add_child(error, item) != XMPP_EOK)
goto quit_err;
xmpp_stanza_release(item); xmpp_stanza_release(item);
text_stanza = xmpp_stanza_new(ctx); text_stanza = xmpp_stanza_new(ctx);
if (!text_stanza) if (!text_stanza)
goto quit_err; goto quit_err;
if (xmpp_stanza_set_text(text_stanza, text) != XMPP_EOK) xmpp_stanza_set_text(text_stanza, text);
goto quit_err; xmpp_stanza_add_child(item, text_stanza);
if (xmpp_stanza_add_child(item, text_stanza) != XMPP_EOK)
goto quit_err;
xmpp_stanza_release(text_stanza); xmpp_stanza_release(text_stanza);
} }
@@ -1352,12 +1264,6 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
quit_err: quit_err:
if (reply) if (reply)
xmpp_stanza_release(reply); xmpp_stanza_release(reply);
if (error)
xmpp_stanza_release(error);
if (item)
xmpp_stanza_release(item);
if (text_stanza)
xmpp_stanza_release(text_stanza);
return NULL; return NULL;
} }
@@ -1386,7 +1292,7 @@ static xmpp_stanza_t *_stanza_new_with_attrs(xmpp_ctx_t *ctx,
return stanza; return stanza;
} }
/** Create a `<message/>` stanza object with given attributes. /** Create a <message/> stanza object with given attributes.
* Attributes are optional and may be NULL. * Attributes are optional and may be NULL.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
@@ -1406,13 +1312,13 @@ xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
return _stanza_new_with_attrs(ctx, "message", type, id, to); return _stanza_new_with_attrs(ctx, "message", type, id, to);
} }
/** Get text from `<body/>` child element. /** Get text from <body/> child element.
* This function returns new allocated string. The caller is responsible * This function returns new allocated string. The caller is responsible
* for freeing this string with xmpp_free(). * for freeing this string with xmpp_free().
* *
* @param msg well formed `<message/>` stanza * @param msg well formed <message/> stanza
* *
* @return allocated string or NULL on failure (no `<body/>` element or * @return allocated string or NULL on failure (no <body/> element or
* memory allocation error) * memory allocation error)
* *
* @ingroup Stanza * @ingroup Stanza
@@ -1431,10 +1337,9 @@ char *xmpp_message_get_body(xmpp_stanza_t *msg)
return text; return text;
} }
/** Add `<body/>` child element to a `<message/>` stanza with the given text. /** Add <body/> child element to a <message/> stanza with the given text.
* *
* @param msg a `<message>` stanza object without `<body/>` child element. * @param msg a <message> stanza object without <body/> child element.
* @param text The text that shall be placed in the body.
* *
* @return 0 on success (XMPP_EOK), and a number less than 0 on failure * @return 0 on success (XMPP_EOK), and a number less than 0 on failure
* (XMPP_EMEM, XMPP_EINVOP) * (XMPP_EMEM, XMPP_EINVOP)
@@ -1449,7 +1354,7 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text)
const char *name; const char *name;
int ret; int ret;
/* check that msg is a `<message/>` stanza and doesn't contain `<body/>` */ /* check that msg is a <message/> stanza and doesn't contain <body/> */
name = xmpp_stanza_get_name(msg); name = xmpp_stanza_get_name(msg);
body = xmpp_stanza_get_child_by_name(msg, "body"); body = xmpp_stanza_get_child_by_name(msg, "body");
if (!name || strcmp(name, "message") != 0 || body) if (!name || strcmp(name, "message") != 0 || body)
@@ -1476,7 +1381,7 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text)
return ret; return ret;
} }
/** Create an `<iq/>` stanza object with given attributes. /** Create an <iq/> stanza object with given attributes.
* Attributes are optional and may be NULL. * Attributes are optional and may be NULL.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
@@ -1492,7 +1397,7 @@ xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char *type, const char *id)
return _stanza_new_with_attrs(ctx, "iq", type, id, NULL); return _stanza_new_with_attrs(ctx, "iq", type, id, NULL);
} }
/** Create a `<presence/>` stanza object. /** Create a <presence/> stanza object.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
* *
@@ -1509,7 +1414,7 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
* The error text is optional and may be NULL. * The error text is optional and may be NULL.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param type enum of strophe_error_type_t * @param type enum of xmpp_error_type_t
* @param text content of a 'text' * @param text content of a 'text'
* *
* @return a new Strophe stanza object * @return a new Strophe stanza object
@@ -1640,11 +1545,8 @@ static void _stub_stream_end(char *name, void *userdata)
static void _stream_stanza(xmpp_stanza_t *stanza, void *userdata) static void _stream_stanza(xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t **dest = userdata;
if (*dest == NULL) {
stanza = xmpp_stanza_clone(stanza); stanza = xmpp_stanza_clone(stanza);
*dest = stanza; *(xmpp_stanza_t **)userdata = stanza;
}
} }
/** Create a stanza object from the string. /** Create a stanza object from the string.

254
src/tls.c
View File

@@ -1,254 +0,0 @@
/* tls.c
** strophe XMPP client library -- generic TLS functions
**
** Copyright (C) 2021 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 and GPLv3 licenses.
*/
/** @file
* Generic TLS functionality.
*/
/** @defgroup TLS SSL/TLS specific functionality
* These functions provide SSL/TLS specific functionality.
*/
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#if !defined(_WIN32)
#include <unistd.h>
#endif
#include "strophe.h"
#include "common.h"
struct _dnsname_t {
char **data;
size_t cur, max;
};
const size_t tlscert_dnsnames_increment = 4;
/** Get the Strophe context which is assigned to this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the Strophe context object where this certificate originates from
*
* @ingroup TLS
*/
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert)
{
return cert->ctx;
}
/** Get the Strophe connection which is assigned to this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return the Strophe connection object where this certificate originates from
*
* @ingroup TLS
*/
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
{
return cert->conn;
}
/** Get the complete PEM of this certificate.
*
* @param cert a Strophe TLS certificate object
*
* @return a string containing the PEM of this certificate
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
{
return cert->pem;
}
/** Get the dnsName entries out of the SubjectAlternativeNames.
*
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
*
* @param cert a Strophe TLS certificate object
* @param n which dnsName entry
*
* @return a string with the n'th dnsName
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n)
{
if (n >= cert->dnsnames->cur)
return NULL;
return cert->dnsnames->data[n];
}
/** Get various parts of the certificate as String.
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param cert a Strophe TLS certificate object
* @param elmnt which part of the certificate
*
* @return a string with the part of the certificate
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
xmpp_cert_element_t elmnt)
{
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return cert->elements[elmnt];
}
/** Get a descriptive string for each xmpp_cert_element_t.
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param elmnt which element
*
* @return a string with the description
*
* @ingroup TLS
*/
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
{
static const char *descriptions[] = {
"X.509 Version",
"SerialNumber",
"Subject",
"Issuer",
"Issued On",
"Expires On",
"Public Key Algorithm",
"Certificate Signature Algorithm",
"Fingerprint SHA-1",
"Fingerprint SHA-256",
};
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return descriptions[elmnt];
}
/** Allocate and initialize a Strophe TLS certificate object.
*
* @param ctx a Strophe context object
*
* @return a certificate object or NULL
*/
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
{
xmpp_tlscert_t *tlscert = strophe_alloc(ctx, sizeof(*tlscert));
if (!tlscert)
return NULL;
memset(tlscert, 0, sizeof(*tlscert));
tlscert->dnsnames = strophe_alloc(ctx, sizeof(*tlscert->dnsnames));
if (!tlscert->dnsnames) {
strophe_free(ctx, tlscert);
return NULL;
}
memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
tlscert->ctx = ctx;
return tlscert;
}
/** Free a certificate object.
*
* @param cert a Strophe TLS certificate object
*
* @ingroup TLS
*/
void xmpp_tlscert_free(xmpp_tlscert_t *cert)
{
size_t n;
for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
if (cert->elements[n])
strophe_free(cert->ctx, cert->elements[n]);
}
if (cert->dnsnames->data) {
for (n = 0; n < cert->dnsnames->cur; ++n) {
if (cert->dnsnames->data[n])
strophe_free(cert->ctx, cert->dnsnames->data[n]);
}
}
strophe_free(cert->ctx, cert->dnsnames->data);
strophe_free(cert->ctx, cert->dnsnames);
if (cert->pem)
strophe_free(cert->ctx, cert->pem);
strophe_free(cert->ctx, cert);
}
/** Add a dnsName to the Strophe TLS certificate object.
*
* @param cert a Strophe TLS certificate object
* @param dnsname dnsName that shall be stored
*
* @return classic Unix style - 0=success, 1=error
*/
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
{
if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
char **dnsnames =
strophe_realloc(cert->ctx, cert->dnsnames->data,
(cert->dnsnames->max + tlscert_dnsnames_increment) *
sizeof(char **));
if (!dnsnames)
return 1;
cert->dnsnames->data = dnsnames;
cert->dnsnames->max += tlscert_dnsnames_increment;
}
cert->dnsnames->data[cert->dnsnames->cur++] =
strophe_strdup(cert->ctx, dnsname);
return 0;
}
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_cert;
size_t fname_len = strlen(fname);
xmpp_sha1_digest((void *)fname, fname_len, hash);
if (fname_len && fname_len == conn->password_cache.fnamelen &&
memcmp(hash, conn->password_cache.fname_hash, sizeof(hash)) == 0) {
if (conn->password_cache.passlen) {
memcpy(pw, conn->password_cache.pass,
conn->password_cache.passlen + 1);
return conn->password_cache.passlen;
}
}
size_t max_len = pw_max == 256 ? pw_max : sizeof(conn->password_cache.pass);
ret = conn->password_callback(conn->password_cache.pass, max_len, conn,
conn->password_callback_userdata);
if (ret < 0 || ret >= (ssize_t)max_len) {
memset(conn->password_cache.pass, 0, sizeof(conn->password_cache.pass));
return -1;
}
conn->password_cache.pass[ret] = '\0';
memcpy(pw, conn->password_cache.pass, ret + 1);
conn->password_cache.passlen = ret;
conn->password_cache.fnamelen = fname_len;
memcpy(conn->password_cache.fname_hash, hash, sizeof(hash));
return conn->password_cache.passlen;
}
void tls_clear_password_cache(xmpp_conn_t *conn)
{
memset(&conn->password_cache, 0, sizeof(conn->password_cache));
}

View File

@@ -21,18 +21,6 @@
typedef struct _tls tls_t; typedef struct _tls tls_t;
typedef struct _dnsname_t dnsname_t;
struct _xmpp_tlscert_t {
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
char *pem;
char *elements[XMPP_CERT_ELEMENT_MAX];
dnsname_t *dnsnames;
};
/* provided by the real TLS implementation */
void tls_initialize(void); void tls_initialize(void);
void tls_shutdown(void); void tls_shutdown(void);
@@ -42,7 +30,6 @@ void tls_free(tls_t *tls);
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n); char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn); 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_set_credentials(tls_t *tls, const char *cafilename);
int tls_start(tls_t *tls); int tls_start(tls_t *tls);
@@ -57,12 +44,4 @@ int tls_write(tls_t *tls, const void *buff, size_t len);
int tls_clear_pending_write(tls_t *tls); int tls_clear_pending_write(tls_t *tls);
int tls_is_recoverable(int error); int tls_is_recoverable(int error);
/* provided by tls.c */
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
int tls_caching_password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn);
void tls_clear_password_cache(xmpp_conn_t *conn);
#endif /* __LIBSTROPHE_TLS_H__ */ #endif /* __LIBSTROPHE_TLS_H__ */

View File

@@ -61,12 +61,6 @@ void tls_free(tls_t *tls)
return; return;
} }
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
UNUSED(conn);
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(tls); UNUSED(tls);

View File

@@ -17,16 +17,17 @@
#include <gnutls/gnutls.h> #include <gnutls/gnutls.h>
#include <gnutls/x509.h> #include <gnutls/x509.h>
#include <gnutls/x509-ext.h> #include <gnutls/x509-ext.h>
#include <gnutls/pkcs11.h>
#include <gnutls/pkcs12.h>
#include "common.h" #include "common.h"
#include "tls.h" #include "tls.h"
#include "sock.h" #include "sock.h"
/* FIXME this shouldn't be a constant string */
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
struct _tls { struct _tls {
xmpp_ctx_t *ctx; /* do we need this? */ xmpp_ctx_t *ctx; /* do we need this? */
xmpp_conn_t *conn; sock_t sock;
gnutls_session_t session; gnutls_session_t session;
gnutls_certificate_credentials_t cred; gnutls_certificate_credentials_t cred;
gnutls_x509_crt_t client_cert; gnutls_x509_crt_t client_cert;
@@ -49,131 +50,27 @@ void tls_shutdown(void)
gnutls_global_deinit(); gnutls_global_deinit();
} }
static int _tls_password_callback(void *userdata, static gnutls_x509_crt_t _tls_load_cert(xmpp_conn_t *conn)
int attempt,
const char *token_url,
const char *token_label,
unsigned int flags,
char *pin,
size_t pin_max)
{
xmpp_conn_t *conn = userdata;
UNUSED(attempt);
UNUSED(token_url);
UNUSED(token_label);
UNUSED(flags);
int ret = tls_caching_password_callback(pin, pin_max, conn);
return ret > 0 ? 0 : GNUTLS_E_PKCS11_PIN_ERROR;
}
static gnutls_x509_crt_t _tls_load_cert_x509(xmpp_conn_t *conn)
{ {
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
gnutls_x509_crt_t cert; gnutls_x509_crt_t cert;
gnutls_datum_t data; gnutls_datum_t data;
int res; int res;
if (gnutls_x509_crt_init(&cert) < 0) if (gnutls_x509_crt_init(&cert) < 0)
return NULL; return NULL;
if (gnutls_load_file(conn->tls_client_cert, &data) < 0) if (gnutls_load_file(conn->tls_client_cert, &data) < 0)
goto error_out; goto LBL_ERR;
res = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM); res = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
gnutls_free(data.data); gnutls_free(data.data);
if (res < 0) if (res < 0)
goto error_out; goto LBL_ERR;
return cert; return cert;
error_out: LBL_ERR:
gnutls_x509_crt_deinit(cert); gnutls_x509_crt_deinit(cert);
return NULL; return NULL;
} }
static gnutls_x509_crt_t _tls_load_cert_p12(xmpp_conn_t *conn)
{
gnutls_pkcs12_t p12;
gnutls_x509_crt_t *cert = NULL;
gnutls_datum_t data;
gnutls_x509_privkey_t key;
unsigned int cert_num = 0, retries = 0;
int err = -1;
if (gnutls_pkcs12_init(&p12) < 0)
return NULL;
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;
/* First try to open file with no pass */
if ((err = gnutls_pkcs12_simple_parse(p12, NULL, &key, &cert, &cert_num,
NULL, NULL, NULL, 0)) == 0) {
goto done;
}
/* Now let's try to open file with an empty pass */
if ((err = gnutls_pkcs12_simple_parse(p12, "", &key, &cert, &cert_num, NULL,
NULL, NULL, 0)) == 0) {
goto done;
}
if (!conn->password_callback) {
strophe_error(conn->ctx, "tls", "No password callback set");
goto error_out2;
}
/* ... and only now ask the user for a password */
while (retries++ < conn->password_retries) {
char pass[GNUTLS_PKCS11_MAX_PIN_LEN];
int passlen =
_tls_password_callback(conn, 0, NULL, NULL, 0, pass, sizeof(pass));
if (passlen < 0)
continue;
err = gnutls_pkcs12_simple_parse(p12, pass, &key, &cert, &cert_num,
NULL, NULL, NULL, 0);
memset(pass, 0, sizeof(pass));
if (err == 0)
break;
tls_clear_password_cache(conn);
if (err != GNUTLS_E_DECRYPTION_FAILED &&
err != GNUTLS_E_MAC_VERIFY_FAILED) {
strophe_error(conn->ctx, "tls", "could not read P12 file");
break;
}
strophe_debug(conn->ctx, "tls", "wrong password?");
}
done:
gnutls_pkcs12_deinit(p12);
gnutls_free(data.data);
if (err < 0)
goto error_out;
gnutls_x509_privkey_deinit(key);
if (cert_num > 1) {
strophe_error(conn->ctx, "tls", "Can't handle stack of %u certs",
cert_num);
goto error_out;
}
gnutls_x509_crt_t ret = *cert;
gnutls_free(cert);
return ret;
error_out2:
gnutls_free(data.data);
error_out:
tls_clear_password_cache(conn);
if (cert) {
for (unsigned int n = 0; n < cert_num; ++n) {
gnutls_x509_crt_deinit(cert[n]);
}
gnutls_free(cert);
}
return NULL;
}
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) {
return _tls_load_cert_p12(conn);
}
return _tls_load_cert_x509(conn);
}
static void _tls_free_cert(xmpp_conn_t *conn, gnutls_x509_crt_t cert) static void _tls_free_cert(xmpp_conn_t *conn, gnutls_x509_crt_t cert)
{ {
if (conn->tls && conn->tls->client_cert == cert) if (conn->tls && conn->tls->client_cert == cert)
@@ -199,7 +96,7 @@ static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
* https://gitlab.com/gnutls/gnutls/-/merge_requests/1397 * https://gitlab.com/gnutls/gnutls/-/merge_requests/1397
*/ */
if (ret) { if (ret) {
*ret = strophe_strdup(conn->ctx, name); *ret = xmpp_strdup(conn->ctx, name);
} }
return GNUTLS_SAN_OTHERNAME_XMPP; return GNUTLS_SAN_OTHERNAME_XMPP;
} }
@@ -218,7 +115,7 @@ static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
return GNUTLS_E_MEMORY_ERROR; return GNUTLS_E_MEMORY_ERROR;
} }
if (ret) { if (ret) {
*ret = strophe_strdup(conn->ctx, (char *)xmpp_addr.data); *ret = xmpp_strdup(conn->ctx, (char *)xmpp_addr.data);
} }
gnutls_free(xmpp_addr.data); gnutls_free(xmpp_addr.data);
return GNUTLS_SAN_OTHERNAME_XMPP; return GNUTLS_SAN_OTHERNAME_XMPP;
@@ -226,7 +123,7 @@ static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
return GNUTLS_E_X509_UNKNOWN_SAN; return GNUTLS_E_X509_UNKNOWN_SAN;
} }
static int _tls_id_on_xmppaddr(xmpp_conn_t *conn, int _tls_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert, gnutls_x509_crt_t cert,
unsigned int n, unsigned int n,
char **ret) char **ret)
@@ -276,232 +173,41 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
return ret; return ret;
} }
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
{
int res;
char buf[512], smallbuf[64];
size_t size, m;
unsigned int algo, n;
gnutls_datum_t data;
time_t time_val;
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
gnutls_x509_crt_export2(cert, GNUTLS_X509_FMT_PEM, &data);
tlscert->pem = strophe_alloc(ctx, data.size + 1);
memcpy(tlscert->pem, data.data, data.size);
tlscert->pem[data.size] = '\0';
gnutls_free(data.data);
size = sizeof(buf);
gnutls_x509_crt_get_dn(cert, buf, &size);
tlscert->elements[XMPP_CERT_SUBJECT] = strophe_strdup(ctx, buf);
size = sizeof(buf);
gnutls_x509_crt_get_issuer_dn(cert, buf, &size);
tlscert->elements[XMPP_CERT_ISSUER] = strophe_strdup(ctx, buf);
time_val = gnutls_x509_crt_get_activation_time(cert);
tlscert->elements[XMPP_CERT_NOTBEFORE] =
strophe_strdup(ctx, ctime(&time_val));
tlscert->elements[XMPP_CERT_NOTBEFORE]
[strlen(tlscert->elements[XMPP_CERT_NOTBEFORE]) - 1] =
'\0';
time_val = gnutls_x509_crt_get_expiration_time(cert);
tlscert->elements[XMPP_CERT_NOTAFTER] =
strophe_strdup(ctx, ctime(&time_val));
tlscert->elements[XMPP_CERT_NOTAFTER]
[strlen(tlscert->elements[XMPP_CERT_NOTAFTER]) - 1] = '\0';
size = sizeof(smallbuf);
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] = strophe_strdup(ctx, buf);
size = sizeof(smallbuf);
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf);
strophe_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
algo = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
tlscert->elements[XMPP_CERT_KEYALG] =
strophe_strdup(ctx, gnutls_pk_algorithm_get_name(algo));
algo = gnutls_x509_crt_get_signature_algorithm(cert);
tlscert->elements[XMPP_CERT_SIGALG] =
strophe_strdup(ctx, gnutls_sign_get_name(algo));
size = sizeof(smallbuf);
gnutls_x509_crt_get_serial(cert, smallbuf, &size);
hex_encode(buf, smallbuf, size);
tlscert->elements[XMPP_CERT_SERIALNUMBER] = strophe_strdup(ctx, buf);
for (n = 0, m = 0, res = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
++n) {
size = sizeof(buf);
res = gnutls_x509_crt_get_subject_alt_name(cert, n, buf, &size, NULL);
if (res == GNUTLS_SAN_DNSNAME) {
if (tlscert_add_dnsname(tlscert, buf))
strophe_debug(ctx, "tls", "Can't store dnsName(%zu): %s", m,
buf);
m++;
}
}
return tlscert;
}
static int _tls_verify(gnutls_session_t session)
{
tls_t *tls = gnutls_session_get_ptr(session);
const gnutls_datum_t *cert_list;
gnutls_certificate_type_t type;
gnutls_datum_t out;
unsigned int cert_list_size = 0, status;
gnutls_x509_crt_t cert;
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
return -1;
if (gnutls_certificate_verify_peers2(session, &status) < 0) {
strophe_error(tls->ctx, "tls", "Verify peers failed");
return -1;
}
type = gnutls_certificate_type_get(session);
if (gnutls_certificate_verification_status_print(status, type, &out, 0) <
0) {
strophe_error(tls->ctx, "tls", "Status print failed");
return -1;
}
/* Return early if the Certificate is trusted
* OR if we trust all Certificates */
if (status == 0 || tls->conn->tls_trust) {
gnutls_free(out.data);
return 0;
}
if (!tls->conn->certfail_handler) {
strophe_error(tls->ctx, "tls",
"No certfail handler set, canceling connection attempt");
gnutls_free(out.data);
return -1;
}
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
/* OpenSSL displays the certificate chain in reverse order than GnuTLS.
* To show consistent behavior to the user, traverse the list from the
* end.
*/
while (cert_list_size--) {
gnutls_x509_crt_init(&cert);
gnutls_x509_crt_import(cert, &cert_list[cert_list_size],
GNUTLS_X509_FMT_DER);
xmpp_tlscert_t *tlscert = _x509_to_tlscert(tls->ctx, cert);
if (!tlscert) {
gnutls_x509_crt_deinit(cert);
gnutls_free(out.data);
return -1;
}
if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) {
xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert);
gnutls_free(out.data);
return -1;
}
xmpp_tlscert_free(tlscert);
gnutls_x509_crt_deinit(cert);
}
gnutls_free(out.data);
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
tls_t *tls = strophe_alloc(conn->ctx, sizeof(tls_t)); tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) { if (tls) {
memset(tls, 0, sizeof(*tls)); memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx; tls->ctx = conn->ctx;
tls->conn = conn; tls->sock = conn->sock;
gnutls_init(&tls->session, GNUTLS_CLIENT); gnutls_init(&tls->session, GNUTLS_CLIENT);
gnutls_certificate_allocate_credentials(&tls->cred); gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, NULL); tls_set_credentials(tls, CAFILE);
if (conn->password_callback)
gnutls_certificate_set_pin_function(tls->cred,
_tls_password_callback, conn);
if (conn->tls_client_cert && conn->tls_client_key) { if (conn->tls_client_cert && conn->tls_client_key) {
unsigned int retries = 0;
tls->client_cert = _tls_load_cert(conn); tls->client_cert = _tls_load_cert(conn);
if (!tls->client_cert) { if (!tls->client_cert) {
strophe_error(tls->ctx, "tls", xmpp_error(tls->ctx, "tls",
"could not read client certificate"); "could not read client certificate");
goto error_out; gnutls_certificate_free_credentials(tls->cred);
gnutls_deinit(tls->session);
xmpp_free(tls->ctx, tls);
return NULL;
} }
while (retries++ < conn->password_retries) { gnutls_certificate_set_x509_key_file(
int err = gnutls_certificate_set_x509_key_file(
tls->cred, conn->tls_client_cert, conn->tls_client_key, tls->cred, conn->tls_client_cert, conn->tls_client_key,
GNUTLS_X509_FMT_PEM); GNUTLS_X509_FMT_PEM);
if (err == 0)
break;
tls_clear_password_cache(conn);
if (err != GNUTLS_E_DECRYPTION_FAILED) {
strophe_error(tls->ctx, "tls",
"could not read private key");
goto error_out;
} }
strophe_debug(tls->ctx, "tls", "wrong password?");
}
} else if (conn->tls_client_cert) {
unsigned int retries = 0;
while (retries++ < conn->password_retries) {
char pass[GNUTLS_PKCS11_MAX_PIN_LEN];
pass[0] = '\0';
int passlen = _tls_password_callback(conn, 0, NULL, NULL, 0,
pass, sizeof(pass));
if (passlen < 0)
continue;
int err = gnutls_certificate_set_x509_simple_pkcs12_file(
tls->cred, conn->tls_client_cert, GNUTLS_X509_FMT_DER,
pass);
memset(pass, 0, sizeof(pass));
if (err == 0)
break;
tls_clear_password_cache(conn);
if (err != GNUTLS_E_DECRYPTION_FAILED &&
err != GNUTLS_E_MAC_VERIFY_FAILED) {
strophe_error(tls->ctx, "tls", "could not read P12 file");
goto error_out;
}
strophe_debug(tls->ctx, "tls", "wrong password?");
}
}
gnutls_certificate_set_verify_function(tls->cred, _tls_verify);
gnutls_set_default_priority(tls->session); gnutls_set_default_priority(tls->session);
gnutls_session_set_ptr(tls->session, tls);
/* fixme: this may require setting a callback on win32? */ /* fixme: this may require setting a callback on win32? */
gnutls_transport_set_int(tls->session, conn->sock); gnutls_transport_set_int(tls->session, conn->sock);
} }
return tls; return tls;
error_out:
if (tls->client_cert)
gnutls_x509_crt_deinit(tls->client_cert);
gnutls_certificate_free_credentials(tls->cred);
gnutls_deinit(tls->session);
strophe_free(tls->ctx, tls);
return NULL;
} }
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
@@ -510,41 +216,16 @@ void tls_free(tls_t *tls)
gnutls_x509_crt_deinit(tls->client_cert); gnutls_x509_crt_deinit(tls->client_cert);
gnutls_deinit(tls->session); gnutls_deinit(tls->session);
gnutls_certificate_free_credentials(tls->cred); gnutls_certificate_free_credentials(tls->cred);
strophe_free(tls->ctx, tls); xmpp_free(tls->ctx, tls);
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
xmpp_tlscert_t *tlscert = NULL;
if (conn && conn->tls && conn->tls->session) {
unsigned int list_size = 0;
const gnutls_datum_t *der_cert =
gnutls_certificate_get_peers(conn->tls->session, &list_size);
if (der_cert && list_size) {
gnutls_x509_crt_t cert;
if (gnutls_x509_crt_init(&cert) < 0)
return NULL;
if (gnutls_x509_crt_import(cert, der_cert, GNUTLS_X509_FMT_DER) ==
0)
tlscert = _x509_to_tlscert(conn->ctx, cert);
gnutls_x509_crt_deinit(cert);
}
}
return tlscert;
} }
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(cafilename); int err;
/* set trusted credentials -- takes a .pem filename */ /* set trusted credentials -- takes a .pem filename */
int err = gnutls_certificate_set_x509_system_trust(tls->cred); err = gnutls_certificate_set_x509_trust_file(tls->cred, cafilename,
if (err >= 0 && tls->conn->tls_cafile) GNUTLS_X509_FMT_PEM);
err = gnutls_certificate_set_x509_trust_file(
tls->cred, tls->conn->tls_cafile, GNUTLS_X509_FMT_PEM);
if (err >= 0 && tls->conn->tls_capath)
err = gnutls_certificate_set_x509_trust_dir(
tls->cred, tls->conn->tls_capath, GNUTLS_X509_FMT_PEM);
if (err >= 0) { if (err >= 0) {
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred); tls->cred);
@@ -556,9 +237,9 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
int tls_start(tls_t *tls) int tls_start(tls_t *tls)
{ {
sock_set_blocking(tls->conn->sock); sock_set_blocking(tls->sock);
tls->lasterror = gnutls_handshake(tls->session); tls->lasterror = gnutls_handshake(tls->session);
sock_set_nonblocking(tls->conn->sock); sock_set_nonblocking(tls->sock);
return tls->lasterror == GNUTLS_E_SUCCESS; return tls->lasterror == GNUTLS_E_SUCCESS;
} }

View File

@@ -26,7 +26,6 @@
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <openssl/x509v3.h> #include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
#include "common.h" #include "common.h"
#include "tls.h" #include "tls.h"
@@ -48,12 +47,6 @@
#endif #endif
#endif #endif
#if OPENSSL_VERSION_NUMBER < 0x30000000L
#define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e)
#else
#define STROPHE_ERR_func_error_string(e) ""
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER < 0x10100000L
static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1) static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
{ {
@@ -61,30 +54,6 @@ static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
} }
#endif #endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER
static int SSL_CTX_use_cert_and_key(SSL_CTX *ctx,
X509 *x509,
EVP_PKEY *privatekey,
STACK_OF(X509) * chain,
int override)
{
UNUSED(override);
if (!ctx)
return 0;
if (x509 && !SSL_CTX_use_certificate(ctx, x509))
return 0;
if (privatekey && !SSL_CTX_use_PrivateKey(ctx, privatekey))
return 0;
#ifdef SSL_CTX_set1_chain
if (chain && !SSL_CTX_set1_chain(ctx, chain))
return 0;
#else
UNUSED(chain);
#endif
return 1;
}
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L #if OPENSSL_VERSION_NUMBER < 0x10000000L
static int GENERAL_NAME_get0_otherName(const GENERAL_NAME *gen, static int GENERAL_NAME_get0_otherName(const GENERAL_NAME *gen,
ASN1_OBJECT **poid, ASN1_OBJECT **poid,
@@ -121,13 +90,9 @@ static void _tls_set_error(tls_t *tls, int error);
static void _tls_log_error(xmpp_ctx_t *ctx); static void _tls_log_error(xmpp_ctx_t *ctx);
static void _tls_dump_cert_info(tls_t *tls); static void _tls_dump_cert_info(tls_t *tls);
static X509 *_tls_cert_read(xmpp_conn_t *conn); static X509 *_tls_cert_read(xmpp_conn_t *conn);
static X509 *
_tls_cert_read_p12(xmpp_conn_t *conn, EVP_PKEY **pkey, STACK_OF(X509) * *ca);
static int _tls_xaddr_nid(void); static int _tls_xaddr_nid(void);
static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res); static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res);
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res); static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn);
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn);
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert);
#define TLS_ERROR_STR(error, table) \ #define TLS_ERROR_STR(error, table) \
_tls_error_str(error, table, ARRAY_SIZE(table)) _tls_error_str(error, table, ARRAY_SIZE(table))
@@ -235,11 +200,9 @@ const char *cert_errors[] = {
TLS_ERROR_FIELD(X509_V_ERR_CA_MD_TOO_WEAK), TLS_ERROR_FIELD(X509_V_ERR_CA_MD_TOO_WEAK),
TLS_ERROR_FIELD(X509_V_ERR_NO_VALID_SCTS), TLS_ERROR_FIELD(X509_V_ERR_NO_VALID_SCTS),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION), TLS_ERROR_FIELD(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION),
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_NEEDED), TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_NEEDED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_FAILED), TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_FAILED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN), TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN),
#endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */
#endif /* !LIBRESSL_VERSION_NUMBER */ #endif /* !LIBRESSL_VERSION_NUMBER */
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ #endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
}; };
@@ -292,23 +255,21 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{ {
char *ret = NULL; char *ret = NULL;
int i, j; int i, j;
GENERAL_NAMES *names = _tls_conn_get_names(conn); GENERAL_NAMES *names = _tls_cert_get_names(conn);
if (!names) { if (!names)
_tls_log_error(conn->ctx);
return NULL; return NULL;
}
int num_names = sk_GENERAL_NAME_num(names); int num_names = sk_GENERAL_NAME_num(names);
for (i = j = 0; i < num_names; ++i) { for (i = j = 0; i < num_names; ++i) {
char *res; char *res;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i); GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
if (name == NULL) if (name == NULL)
break; break;
if (_tls_xmppaddr_to_string(name, &res)) if (_tls_name_to_xmppaddr(name, &res))
continue; continue;
if (j == (int)n) { if (j == (int)n) {
strophe_debug(conn->ctx, "tls", xmpp_debug(conn->ctx, "tls", "extracted jid %s from id-on-xmppAddr",
"extracted jid %s from id-on-xmppAddr", res); res);
ret = strophe_strdup(conn->ctx, res); ret = xmpp_strdup(conn->ctx, res);
OPENSSL_free(res); OPENSSL_free(res);
break; break;
} }
@@ -322,15 +283,13 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn) unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{ {
unsigned int ret = 0; unsigned int ret = 0;
GENERAL_NAMES *names = _tls_conn_get_names(conn); GENERAL_NAMES *names = _tls_cert_get_names(conn);
if (!names) { if (!names)
_tls_log_error(conn->ctx);
return 0; return 0;
}
int j, num_names = sk_GENERAL_NAME_num(names); int j, num_names = sk_GENERAL_NAME_num(names);
for (j = 0; j < num_names; ++j) { for (j = 0; j < num_names; ++j) {
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j); GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
if (_tls_xmppaddr_to_string(name, NULL)) if (_tls_name_to_xmppaddr(name, NULL))
continue; continue;
ret++; ret++;
} }
@@ -338,222 +297,10 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
return ret; return ret;
} }
static int _convert_ASN1TIME(ASN1_TIME *ansi_time, char *buf, size_t len)
{
BIO *bio = BIO_new(BIO_s_mem());
int rc = ASN1_TIME_print(bio, ansi_time);
if (rc <= 0) {
BIO_free(bio);
return 0;
}
rc = BIO_gets(bio, buf, len);
if (rc <= 0) {
BIO_free(bio);
return 0;
}
BIO_free(bio);
return 1;
}
static char *_asn1_time_to_str(const xmpp_ctx_t *ctx, ASN1_TIME *t)
{
char buf[128];
int res = _convert_ASN1TIME(t, buf, sizeof(buf));
if (res) {
return strophe_strdup(ctx, buf);
}
return NULL;
}
static char *
_get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
unsigned char buf[EVP_MAX_MD_SIZE];
unsigned int len;
const EVP_MD *digest;
switch (el) {
case XMPP_CERT_FINGERPRINT_SHA1:
digest = EVP_sha1();
break;
case XMPP_CERT_FINGERPRINT_SHA256:
digest = EVP_sha256();
break;
default:
return NULL;
}
if (X509_digest(err_cert, digest, buf, &len) != 0) {
char fingerprint[4 * EVP_MAX_MD_SIZE];
hex_encode(fingerprint, buf, len);
return strophe_strdup(ctx, fingerprint);
}
return NULL;
}
static char *
_get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
int alg_nid = NID_undef;
switch (el) {
case XMPP_CERT_KEYALG: {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
alg_nid = OBJ_obj2nid(err_cert->cert_info->key->algor->algorithm);
#else
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(err_cert);
ASN1_OBJECT *ppkalg = NULL;
if (X509_PUBKEY_get0_param(&ppkalg, NULL, NULL, NULL, pubkey)) {
alg_nid = OBJ_obj2nid(ppkalg);
}
#endif
} break;
case XMPP_CERT_SIGALG: {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
#else
const X509_ALGOR *palg;
X509_get0_signature(NULL, &palg, err_cert);
alg_nid = OBJ_obj2nid(palg->algorithm);
#endif
} break;
default:
break;
}
if (alg_nid != NID_undef) {
const char *alg = OBJ_nid2ln(alg_nid);
if (alg) {
return strophe_strdup(ctx, alg);
}
}
return NULL;
}
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
{
char *subject, *issuer, buf[32];
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
if (!tlscert)
return NULL;
BIO *b = BIO_new(BIO_s_mem());
if (!b)
goto error_out;
PEM_write_bio_X509(b, cert);
BUF_MEM *bptr;
BIO_get_mem_ptr(b, &bptr);
tlscert->pem = strophe_alloc(ctx, bptr->length + 1);
if (!tlscert->pem)
goto error_out;
memcpy(tlscert->pem, bptr->data, bptr->length);
tlscert->pem[bptr->length] = '\0';
BIO_free(b);
subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (!subject)
goto error_out;
tlscert->elements[XMPP_CERT_SUBJECT] = strophe_strdup(ctx, subject);
OPENSSL_free(subject);
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (!issuer)
goto error_out;
tlscert->elements[XMPP_CERT_ISSUER] = strophe_strdup(ctx, issuer);
OPENSSL_free(issuer);
tlscert->elements[XMPP_CERT_NOTBEFORE] =
_asn1_time_to_str(ctx, X509_get_notBefore(cert));
tlscert->elements[XMPP_CERT_NOTAFTER] =
_asn1_time_to_str(ctx, X509_get_notAfter(cert));
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
strophe_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
tlscert->elements[XMPP_CERT_VERSION] = strophe_strdup(ctx, buf);
tlscert->elements[XMPP_CERT_KEYALG] = _get_alg(ctx, cert, XMPP_CERT_KEYALG);
tlscert->elements[XMPP_CERT_SIGALG] = _get_alg(ctx, cert, XMPP_CERT_SIGALG);
ASN1_INTEGER *serial = X509_get_serialNumber(cert);
BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
if (bn) {
char *serialnumber = BN_bn2hex(bn);
if (serialnumber) {
tlscert->elements[XMPP_CERT_SERIALNUMBER] =
strophe_strdup(ctx, serialnumber);
OPENSSL_free(serialnumber);
}
BN_free(bn);
}
GENERAL_NAMES *names = _tls_cert_get_names(cert);
if (names) {
int j, num_names = sk_GENERAL_NAME_num(names);
size_t n = 0;
for (j = 0; j < num_names; ++j) {
char *res;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
if (_tls_dnsname_to_string(name, &res))
continue;
if (tlscert_add_dnsname(tlscert, res))
strophe_debug(ctx, "tls", "Can't store dnsName(%zu): %s", n,
res);
n++;
OPENSSL_free(res);
}
GENERAL_NAMES_free(names);
}
return tlscert;
error_out:
xmpp_tlscert_free(tlscert);
return NULL;
}
static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
if (preverify_ok == 1)
return 1;
SSL *ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
xmpp_conn_t *conn = SSL_get_app_data(ssl);
if (!conn->certfail_handler) {
strophe_error(conn->ctx, "tls",
"No certfail handler set, canceling connection attempt");
return 0;
}
X509 *err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, err_cert);
if (!tlscert)
return 0;
strophe_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
tlscert->elements[XMPP_CERT_ISSUER]);
int ret = conn->certfail_handler(
tlscert,
X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
xmpp_tlscert_free(tlscert);
return ret;
}
static int _tls_password_callback(char *buf, int size, int rwflag, void *u)
{
UNUSED(rwflag);
return tls_caching_password_callback(buf, size, u);
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls)); tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
int mode;
if (tls) { if (tls) {
int ret; int ret;
@@ -581,56 +328,18 @@ tls_t *tls_new(xmpp_conn_t *conn)
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */ SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_SSLv3); /* POODLE */
SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */ SSL_CTX_set_options(tls->ssl_ctx, SSL_OP_NO_TLSv1); /* BEAST */
if (conn->password_callback) {
SSL_CTX_set_default_passwd_cb(tls->ssl_ctx, _tls_password_callback);
SSL_CTX_set_default_passwd_cb_userdata(tls->ssl_ctx, conn);
}
if (conn->tls_client_cert && conn->tls_client_key) { if (conn->tls_client_cert && conn->tls_client_key) {
unsigned int retries = 0;
tls->client_cert = _tls_cert_read(conn); tls->client_cert = _tls_cert_read(conn);
if (!tls->client_cert) { if (!tls->client_cert) {
strophe_error(tls->ctx, "tls", xmpp_error(tls->ctx, "tls",
"could not read client certificate"); "could not read client certificate");
goto err_free_ctx; goto err_free_ctx;
} }
SSL_CTX_use_certificate_file(tls->ssl_ctx, conn->tls_client_cert, SSL_CTX_use_certificate_file(tls->ssl_ctx, conn->tls_client_cert,
SSL_FILETYPE_PEM); SSL_FILETYPE_PEM);
while (retries++ < conn->password_retries) { SSL_CTX_use_PrivateKey_file(tls->ssl_ctx, conn->tls_client_key,
if (SSL_CTX_use_PrivateKey_file( SSL_FILETYPE_PEM);
tls->ssl_ctx, conn->tls_client_key, SSL_FILETYPE_PEM)) {
break;
}
tls_clear_password_cache(conn);
unsigned long err = ERR_peek_error();
if ((ERR_GET_LIB(err) == ERR_LIB_EVP &&
ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT) ||
(ERR_GET_LIB(err) == ERR_LIB_PEM &&
ERR_GET_REASON(err) == PEM_R_BAD_DECRYPT)) {
strophe_debug(tls->ctx, "tls", "wrong password?");
continue;
}
strophe_error(tls->ctx, "tls",
"could not use private key %d %d",
ERR_GET_LIB(err), ERR_GET_REASON(err));
goto err_free_ctx;
}
} else if (conn->tls_client_cert) {
EVP_PKEY *pkey = NULL;
STACK_OF(X509) *ca = NULL;
X509 *cert = _tls_cert_read_p12(conn, &pkey, &ca);
if (!cert) {
goto err_free_ctx;
}
SSL_CTX_use_cert_and_key(tls->ssl_ctx, cert, pkey, ca, 1);
if (pkey)
EVP_PKEY_free(pkey);
if (ca)
sk_X509_pop_free(ca, X509_free);
tls->client_cert = cert;
} else { } else {
/* If the server asks for a client certificate, don't send one. */ /* If the server asks for a client certificate, don't send one. */
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL); SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
@@ -645,20 +354,11 @@ tls_t *tls_new(xmpp_conn_t *conn)
* location is still treated as a success. * location is still treated as a success.
* Ignore errors when XMPP_CONN_FLAG_TRUST_TLS is set. * Ignore errors when XMPP_CONN_FLAG_TRUST_TLS is set.
*/ */
strophe_error(tls->ctx, "tls", xmpp_error(tls->ctx, "tls",
"SSL_CTX_set_default_verify_paths() failed"); "SSL_CTX_set_default_verify_paths() failed");
goto err_free_cert; goto err_free_cert;
} }
if (conn->tls_cafile || conn->tls_capath) {
if (SSL_CTX_load_verify_locations(tls->ssl_ctx, conn->tls_cafile,
conn->tls_capath) == 0) {
strophe_error(tls->ctx, "tls",
"SSL_CTX_load_verify_locations() failed");
goto err_free_cert;
}
}
tls->ssl = SSL_new(tls->ssl_ctx); tls->ssl = SSL_new(tls->ssl_ctx);
if (tls->ssl == NULL) if (tls->ssl == NULL)
goto err_free_cert; goto err_free_cert;
@@ -668,13 +368,9 @@ tls_t *tls_new(xmpp_conn_t *conn)
SSL_set_tlsext_host_name(tls->ssl, conn->domain); SSL_set_tlsext_host_name(tls->ssl, conn->domain);
#endif #endif
/* Trust server's certificate when user sets the flag explicitly. /* Trust server's certificate when user sets the flag explicitly. */
* Otherwise call the verification callback */ mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
if (conn->tls_trust) SSL_set_verify(tls->ssl, mode, NULL);
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
else
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, _tls_verify);
SSL_set_app_data(tls->ssl, conn);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */ /* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
param = SSL_get0_param(tls->ssl); param = SSL_get0_param(tls->ssl);
@@ -705,7 +401,7 @@ err_free_cert:
err_free_ctx: err_free_ctx:
SSL_CTX_free(tls->ssl_ctx); SSL_CTX_free(tls->ssl_ctx);
err: err:
strophe_free(conn->ctx, tls); xmpp_free(conn->ctx, tls);
_tls_log_error(conn->ctx); _tls_log_error(conn->ctx);
return NULL; return NULL;
} }
@@ -715,20 +411,7 @@ void tls_free(tls_t *tls)
SSL_free(tls->ssl); SSL_free(tls->ssl);
X509_free(tls->client_cert); X509_free(tls->client_cert);
SSL_CTX_free(tls->ssl_ctx); SSL_CTX_free(tls->ssl_ctx);
strophe_free(tls->ctx, tls); xmpp_free(tls->ctx, 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);
if (cert) {
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
X509_free(cert);
return tlscert;
}
}
return NULL;
} }
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
@@ -762,13 +445,11 @@ int tls_start(tls_t *tls)
x509_res = SSL_get_verify_result(tls->ssl); x509_res = SSL_get_verify_result(tls->ssl);
if (x509_res == X509_V_OK) { if (x509_res == X509_V_OK) {
strophe_debug(tls->ctx, "tls", "Certificate verification passed"); xmpp_debug(tls->ctx, "tls", "Certificate verification passed");
} else { } else {
strophe_debug(tls->ctx, "tls", xmpp_debug(tls->ctx, "tls",
"Certificate verification FAILED, result=%s(%ld)", "Certificate verification FAILED, result=%s(%ld)",
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res); TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
if (ret > 0)
strophe_debug(tls->ctx, "tls", "User decided to connect anyways");
} }
_tls_dump_cert_info(tls); _tls_dump_cert_info(tls);
@@ -883,13 +564,9 @@ static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
static void _tls_set_error(tls_t *tls, int error) static void _tls_set_error(tls_t *tls, int error)
{ {
if (error != 0 && !tls_is_recoverable(error)) { if (error != 0 && !tls_is_recoverable(error)) {
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d", xmpp_debug(tls->ctx, "tls", "error=%s(%d) errno=%d",
TLS_ERROR_STR(error, tls_errors), error, errno, TLS_ERROR_STR(error, tls_errors), error, errno);
tls->lasterror);
_tls_log_error(tls->ctx); _tls_log_error(tls->ctx);
} else if (tls->lasterror && tls->lasterror != error) {
strophe_debug_verbose(1, tls->ctx, "tls", "overwrite lasterror=%d",
tls->lasterror);
} }
tls->lasterror = error; tls->lasterror = error;
} }
@@ -897,13 +574,13 @@ static void _tls_set_error(tls_t *tls, int error)
static void _tls_log_error(xmpp_ctx_t *ctx) static void _tls_log_error(xmpp_ctx_t *ctx)
{ {
unsigned long e; unsigned long e;
char buf[256];
do { do {
e = ERR_get_error(); e = ERR_get_error();
if (e != 0) { if (e != 0) {
strophe_debug( ERR_error_string_n(e, buf, sizeof(buf));
ctx, "tls", "error:%08X:%s:%s:%s", e, ERR_lib_error_string(e), xmpp_debug(ctx, "tls", "%s", buf);
STROPHE_ERR_func_error_string(e), ERR_reason_error_string(e));
} }
} while (e != 0); } while (e != 0);
} }
@@ -915,131 +592,43 @@ static void _tls_dump_cert_info(tls_t *tls)
cert = SSL_get_peer_certificate(tls->ssl); cert = SSL_get_peer_certificate(tls->ssl);
if (cert == NULL) if (cert == NULL)
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer"); xmpp_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else { else {
name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (name != NULL) { if (name != NULL) {
strophe_debug(tls->ctx, "tls", "Subject=%s", name); xmpp_debug(tls->ctx, "tls", "Subject=%s", name);
OPENSSL_free(name); OPENSSL_free(name);
} }
name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (name != NULL) { if (name != NULL) {
strophe_debug(tls->ctx, "tls", "Issuer=%s", name); xmpp_debug(tls->ctx, "tls", "Issuer=%s", name);
OPENSSL_free(name); OPENSSL_free(name);
} }
X509_free(cert); X509_free(cert);
} }
} }
static X509 *_tls_cert_read_x509(xmpp_conn_t *conn) static X509 *_tls_cert_read(xmpp_conn_t *conn)
{ {
if (conn->tls && conn->tls->client_cert) if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert; return conn->tls->client_cert;
BIO *f = BIO_new_file(conn->tls_client_cert, "r"); BIO *f = BIO_new_file(conn->tls_client_cert, "r");
if (!f) { if (!f) {
strophe_debug(conn->ctx, "tls", "f == NULL"); xmpp_debug(conn->ctx, "tls", "f == NULL");
return NULL; return NULL;
} }
X509 *c = PEM_read_bio_X509(f, NULL, NULL, NULL); X509 *c = PEM_read_bio_X509(f, NULL, NULL, NULL);
BIO_free(f); BIO_free(f);
if (!c) { if (!c) {
_tls_log_error(conn->ctx); unsigned long error;
while ((error = ERR_get_error()) != 0) {
xmpp_debug(conn->ctx, "tls", "c == NULL: %s",
ERR_error_string(error, NULL));
}
} }
return c; return c;
} }
static int _tls_parse_p12(PKCS12 *p12,
const char *pass,
EVP_PKEY **pkey,
X509 **cert,
STACK_OF(X509) * *ca)
{
/* For some reason `PKCS12_parse()` fails without a `EVP_PKEY`
* so if the user doesn't want it, use a local one and free it
* again directly after parsing.
*/
EVP_PKEY *pkey_;
if (!pkey)
pkey = &pkey_;
int parse_ok = PKCS12_parse(p12, pass, pkey, cert, ca);
if (pkey == &pkey_ && pkey_)
EVP_PKEY_free(pkey_);
return parse_ok;
}
static X509 *
_tls_cert_read_p12(xmpp_conn_t *conn, EVP_PKEY **pkey, STACK_OF(X509) * *ca)
{
if (conn->tls && conn->tls->client_cert && !pkey && !ca)
return conn->tls->client_cert;
X509 *cert = NULL;
PKCS12 *p12 = NULL;
BIO *f = BIO_new_file(conn->tls_client_cert, "rb");
if (!f) {
strophe_debug(conn->ctx, "tls", "f == NULL");
goto error_out;
}
p12 = d2i_PKCS12_bio(f, NULL);
BIO_free(f);
if (!p12) {
strophe_debug(conn->ctx, "tls", "Could not read p12 file");
goto error_out;
}
/* First try to open file w/o a pass */
if (_tls_parse_p12(p12, NULL, pkey, &cert, ca)) {
goto success;
}
cert = NULL;
unsigned int retries = 0;
pem_password_cb *cb = PEM_def_callback;
void *userdata = NULL;
if (conn->password_callback) {
cb = _tls_password_callback;
userdata = conn;
}
while (retries++ < conn->password_retries) {
char pass[PEM_BUFSIZE + 1];
int passlen = cb(pass, PEM_BUFSIZE, 0, userdata);
if (passlen < 0 || passlen > PEM_BUFSIZE)
goto error_out;
int parse_ok = _tls_parse_p12(p12, pass, pkey, &cert, ca);
if (parse_ok) {
goto success;
}
cert = NULL;
tls_clear_password_cache(conn);
int err = ERR_peek_last_error();
if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
strophe_debug(conn->ctx, "tls",
"Entered password is most likely wrong!");
continue;
}
strophe_debug(conn->ctx, "tls", "Could not parse PKCS#12");
goto error_out;
}
error_out:
_tls_log_error(conn->ctx);
success:
if (p12)
PKCS12_free(p12);
return cert;
}
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) {
return _tls_cert_read_p12(conn, NULL, NULL);
}
return _tls_cert_read_x509(conn);
}
static int _tls_xaddr_nid(void) static int _tls_xaddr_nid(void)
{ {
static int xaddr_nid = NID_undef; static int xaddr_nid = NID_undef;
@@ -1053,32 +642,28 @@ static int _tls_xaddr_nid(void)
return xaddr_nid; return xaddr_nid;
} }
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn) static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn)
{ {
X509 *client_cert; X509 *client_cert;
GENERAL_NAMES *names = NULL; GENERAL_NAMES *names = NULL;
client_cert = _tls_cert_read(conn); client_cert = _tls_cert_read(conn);
if (!client_cert) if (!client_cert)
return NULL; return NULL;
names = _tls_cert_get_names(client_cert);
if (!conn->tls || !conn->tls->client_cert)
X509_free(client_cert);
return names;
}
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert)
{
int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0); int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
X509_EXTENSION *san_ext = X509_get_ext(client_cert, san); X509_EXTENSION *san_ext = X509_get_ext(client_cert, san);
if (!san_ext) if (!san_ext)
return NULL; goto OUT;
ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext); ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext);
if (!data) if (!data)
return NULL; goto OUT;
const unsigned char *d = ASN1_STRING_get0_data(data); const unsigned char *d = ASN1_STRING_get0_data(data);
if (!d) if (!d)
return NULL; goto OUT;
return d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data)); names = d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
OUT:
if (!conn->tls || !conn->tls->client_cert)
X509_free(client_cert);
return names;
} }
/** Convert GENERAL_NAME* to a string /** Convert GENERAL_NAME* to a string
@@ -1095,7 +680,7 @@ static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert)
* *
* @return classic Unix style - 0=success, 1=error * @return classic Unix style - 0=success, 1=error
*/ */
static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res) static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res)
{ {
ASN1_OBJECT *oid; ASN1_OBJECT *oid;
ASN1_TYPE *val; ASN1_TYPE *val;
@@ -1111,18 +696,3 @@ static int _tls_xmppaddr_to_string(GENERAL_NAME *name, char **res)
return 1; return 1;
return 0; return 0;
} }
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res)
{
ASN1_STRING *str;
if (!name || name->type != GEN_DNS)
return 1;
str = GENERAL_NAME_get0_value(name, NULL);
if (str == NULL)
return 1;
if (!res)
return 0;
if (ASN1_STRING_to_UTF8((unsigned char **)res, str) < 0)
return 1;
return 0;
}

View File

@@ -65,14 +65,14 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{ {
UNUSED(n); UNUSED(n);
/* always fail */ /* always fail */
strophe_error(conn->ctx, "tls", "Client-Authentication not implemented"); xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return NULL; return NULL;
} }
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn) unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{ {
/* always fail */ /* always fail */
strophe_error(conn->ctx, "tls", "Client-Authentication not implemented"); xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return 0; return 0;
} }
@@ -102,7 +102,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
return NULL; return NULL;
} }
tls = strophe_alloc(ctx, sizeof(*tls)); tls = xmpp_alloc(ctx, sizeof(*tls));
if (!tls) { if (!tls) {
return NULL; return NULL;
@@ -138,7 +138,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
return NULL; return NULL;
} }
strophe_debug(ctx, "TLSS", "QuerySecurityPackageInfo() success"); xmpp_debug(ctx, "TLSS", "QuerySecurityPackageInfo() success");
memset(&scred, 0, sizeof(scred)); memset(&scred, 0, sizeof(scred));
scred.dwVersion = SCHANNEL_CRED_VERSION; scred.dwVersion = SCHANNEL_CRED_VERSION;
@@ -163,7 +163,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
return NULL; return NULL;
} }
strophe_debug(ctx, "TLSS", "AcquireCredentialsHandle() success"); xmpp_debug(ctx, "TLSS", "AcquireCredentialsHandle() success");
tls->init = 1; tls->init = 1;
@@ -196,15 +196,15 @@ tls_t *tls_new(xmpp_conn_t *conn)
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
if (tls->recvbuffer) { if (tls->recvbuffer) {
strophe_free(tls->ctx, tls->recvbuffer); xmpp_free(tls->ctx, tls->recvbuffer);
} }
if (tls->readybuffer) { if (tls->readybuffer) {
strophe_free(tls->ctx, tls->readybuffer); xmpp_free(tls->ctx, tls->readybuffer);
} }
if (tls->sendbuffer) { if (tls->sendbuffer) {
strophe_free(tls->ctx, tls->sendbuffer); xmpp_free(tls->ctx, tls->sendbuffer);
} }
if (tls->init) { if (tls->init) {
@@ -218,17 +218,10 @@ void tls_free(tls_t *tls)
tls->hsec32 = NULL; tls->hsec32 = NULL;
} }
strophe_free(tls->ctx, tls); xmpp_free(tls->ctx, tls);
return; return;
} }
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{
/* always fail */
strophe_error(conn->ctx, "tls", "tls_peer_cert() not implemented");
return NULL;
}
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
UNUSED(tls); UNUSED(tls);
@@ -263,7 +256,7 @@ int tls_start(tls_t *tls)
memset(&(sbin[0]), 0, sizeof(sbin[0])); memset(&(sbin[0]), 0, sizeof(sbin[0]));
sbin[0].BufferType = SECBUFFER_TOKEN; sbin[0].BufferType = SECBUFFER_TOKEN;
sbin[0].pvBuffer = strophe_alloc(tls->ctx, tls->spi->cbMaxToken); sbin[0].pvBuffer = xmpp_alloc(tls->ctx, tls->spi->cbMaxToken);
sbin[0].cbBuffer = tls->spi->cbMaxToken; sbin[0].cbBuffer = tls->spi->cbMaxToken;
memset(&(sbin[1]), 0, sizeof(sbin[1])); memset(&(sbin[1]), 0, sizeof(sbin[1]));
@@ -369,11 +362,11 @@ int tls_start(tls_t *tls)
} }
} }
strophe_free(tls->ctx, sbin[0].pvBuffer); xmpp_free(tls->ctx, sbin[0].pvBuffer);
if (ret != SEC_E_OK) { if (ret != SEC_E_OK) {
tls->lasterror = ret; tls->lasterror = ret;
strophe_error(tls->ctx, "TLSS", "Schannel error 0x%lx", xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx",
(unsigned long)ret); (unsigned long)ret);
return 0; return 0;
} }
@@ -383,16 +376,16 @@ int tls_start(tls_t *tls)
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage + tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage +
tls->spcss.cbTrailer; tls->spcss.cbTrailer;
tls->recvbuffer = strophe_alloc(tls->ctx, tls->recvbuffermaxlen); tls->recvbuffer = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen);
tls->recvbufferpos = 0; tls->recvbufferpos = 0;
tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage + tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage +
tls->spcss.cbTrailer; tls->spcss.cbTrailer;
tls->sendbuffer = strophe_alloc(tls->ctx, tls->sendbuffermaxlen); tls->sendbuffer = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen);
tls->sendbufferpos = 0; tls->sendbufferpos = 0;
tls->sendbufferlen = 0; tls->sendbufferlen = 0;
tls->readybuffer = strophe_alloc(tls->ctx, tls->spcss.cbMaximumMessage); tls->readybuffer = xmpp_alloc(tls->ctx, tls->spcss.cbMaximumMessage);
tls->readybufferpos = 0; tls->readybufferpos = 0;
tls->readybufferlen = 0; tls->readybufferlen = 0;

252
src/tls_securetransport.c Normal file
View File

@@ -0,0 +1,252 @@
// Secure Transport implementation of TLS by Christopher A. Taylor (2013)
#include <Security/Security.h>
#include <Security/SecureTransport.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonDigest.h>
#include "common.h"
#include "tls.h"
#include "sock.h"
struct _tls {
xmpp_ctx_t *ctx;
sock_t sock;
SSLContextRef sslctx;
};
void tls_initialize(void)
{
}
void tls_shutdown(void)
{
}
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
UNUSED(n);
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return NULL;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return 0;
}
OSStatus MySSLReadFunction(SSLConnectionRef connection, void *data, size_t *dataLength) {
size_t bytesToGo = *dataLength;
size_t initLen = bytesToGo;
UInt8 *currData = (UInt8 *)data;
/*int sock = *(int *)connection;*/
tls_t *connssl = (tls_t *)connection;
int sock = connssl->sock;
OSStatus rtn = noErr;
size_t bytesRead;
ssize_t rrtn;
int theErr;
*dataLength = 0;
for(;;) {
bytesRead = 0;
rrtn = read(sock, currData, bytesToGo);
if(rrtn <= 0) {
/* this is guesswork... */
theErr = errno;
if(rrtn == 0) { /* EOF = server hung up */
/* the framework will turn this into errSSLClosedNoNotify */
rtn = errSSLClosedGraceful;
}
else /* do the switch */
switch(theErr) {
case ENOENT:
/* connection closed */
rtn = errSSLClosedGraceful;
break;
case ECONNRESET:
rtn = errSSLClosedAbort;
break;
case EAGAIN:
rtn = errSSLWouldBlock;
//connssl->ssl_direction = false;
break;
default:
rtn = errSSLClosedAbort;
break;
}
break;
}
else {
bytesRead = rrtn;
}
bytesToGo -= bytesRead;
currData += bytesRead;
if(bytesToGo == 0) {
/* filled buffer with incoming data, done */
break;
}
}
*dataLength = initLen - bytesToGo;
return rtn;
}
OSStatus MySSLWriteFunction(SSLConnectionRef connection, const void *data, size_t *dataLength) {
size_t bytesSent = 0;
/*int sock = *(int *)connection;*/
tls_t *connssl = (tls_t *)connection;
int sock = connssl->sock;
ssize_t length;
size_t dataLen = *dataLength;
const UInt8 *dataPtr = (UInt8 *)data;
OSStatus ortn;
int theErr;
*dataLength = 0;
do {
length = write(sock,
(char*)dataPtr + bytesSent,
dataLen - bytesSent);
} while((length > 0) &&
( (bytesSent += length) < dataLen) );
if(length <= 0) {
theErr = errno;
if(theErr == EAGAIN) {
ortn = errSSLWouldBlock;
//connssl->ssl_direction = true;
}
else {
ortn = errSSLClosedAbort;
}
}
else {
ortn = noErr;
}
*dataLength = bytesSent;
return ortn;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) {
tls->ctx = conn->ctx;
tls->sock = conn->sock;
tls->sslctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
SSLSetIOFuncs(tls->sslctx, MySSLReadFunction, MySSLWriteFunction);
SSLSetConnection(tls->sslctx, tls);
}
return tls;
}
void tls_free(tls_t *tls)
{
CFRelease(tls->sslctx);
xmpp_free(tls->ctx, tls);
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
/*
Not implemented in OpenSSL version so we should not need it either.
But if we want to do it here's a place to start:
FILE * ret = fopen(cafilename, options);
void *data = malloc(bytes);
fread(data, 1, bytes, ret);
fclose(ret);
NSData *myCertData = [NSData dataWithBytesNoCopy:data length:bytes]; <- requires -ObjC compile option?
SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, myCertData);
CFArrayRef certRefs = CFArrayCreate(kCFAllocatorDefault, (const void **)&cert, 1, NULL);
SSLSetCertificate(tls->sslctx, certRefs);
*/
return -1;
}
int tls_start(tls_t *tls)
{
int ret;
/* Since we're non-blocking, loop the connect call until it
succeeds or fails */
do {
ret = SSLHandshake(tls->sslctx);
} while (ret == errSSLWouldBlock);
return ret < 0 ? -1 : 0;
}
int tls_stop(tls_t *tls)
{
SSLClose(tls->sslctx);
return 0;
}
int tls_is_recoverable(int error)
{
switch (error) {
case errSSLWouldBlock:
return true;
default:
break;
}
return false;
}
int tls_error(tls_t *tls)
{
/* todo: some kind of error polling/dump */
return 0;
}
int tls_pending(tls_t *tls)
{
size_t buffer;
if (SSLGetBufferedReadSize(tls->sslctx, &buffer) < 0) {
return 0;
}
return buffer;
}
int tls_read(tls_t *tls, void * const buff, const size_t len)
{
size_t processed;
SSLRead(tls->sslctx, buff, len, &processed);
return processed;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
{
size_t processed;
SSLWrite(tls->sslctx, buff, len, &processed);
return processed;
}
int tls_clear_pending_write(tls_t *tls)
{
return 0;
}

View File

@@ -15,7 +15,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
@@ -37,41 +36,21 @@
* @param ctx a Strophe context object * @param ctx a Strophe context object
* @param s a string * @param s a string
* *
* @return a newly allocated string with the same data as s or NULL on error * @return a new allocates string with the same data as s or NULL on error
*/ */
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s) char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s)
{
return strophe_strndup(ctx, s, SIZE_MAX);
}
/** Duplicate a string with a maximum length.
* This function replaces the standard strndup library call with a version
* that uses the Strophe context object's allocator.
*
* @param ctx a Strophe context object
* @param s a string
* @param len the maximum length of the string to copy
*
* @return a newly allocated string that contains at most `len` symbols
* of the original string or NULL on error
*/
char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
{ {
size_t len;
char *copy; char *copy;
size_t l;
l = strlen(s); len = strlen(s);
if (l > len) copy = xmpp_alloc(ctx, len + 1);
l = len;
copy = strophe_alloc(ctx, l + 1);
if (!copy) { if (!copy) {
strophe_error(ctx, "xmpp", "failed to allocate required memory"); xmpp_error(ctx, "xmpp", "failed to allocate required memory");
return NULL; return NULL;
} }
memcpy(copy, s, l); memcpy(copy, s, len + 1);
copy[l] = '\0';
return copy; return copy;
} }
@@ -81,7 +60,7 @@ char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
* For example, visual studio older than 2005 doesn't provide strtok_r() * For example, visual studio older than 2005 doesn't provide strtok_r()
* nor strtok_s(). * nor strtok_s().
*/ */
char *strophe_strtok_r(char *s, const char *delim, char **saveptr) char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
{ {
size_t len; size_t len;
@@ -158,22 +137,6 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
*/ */
void disconnect_mem_error(xmpp_conn_t *conn) void disconnect_mem_error(xmpp_conn_t *conn)
{ {
strophe_error(conn->ctx, "xmpp", "Memory allocation error"); xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} }
int string_to_ul(const char *s, unsigned long *ul)
{
char *endptr;
*ul = strtoul(s, &endptr, 10);
return *endptr != '\0';
}
void hex_encode(char *writebuf, void *readbuf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
sprintf(writebuf, "%02x", ((unsigned char *)readbuf)[i]);
writebuf += 2;
}
}

View File

@@ -26,14 +26,10 @@
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y)) #define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
/* string functions */ /* string functions */
char *strophe_strtok_r(char *s, const char *delim, char **saveptr); char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
/* timing functions */ /* timing functions */
uint64_t time_stamp(void); uint64_t time_stamp(void);
uint64_t time_elapsed(uint64_t t1, uint64_t t2); uint64_t time_elapsed(uint64_t t1, uint64_t t2);
/* misc functions */
int string_to_ul(const char *s, unsigned long *ul);
void hex_encode(char *writebuf, void *readbuf, size_t len);
#endif /* __LIBSTROPHE_UTIL_H__ */ #endif /* __LIBSTROPHE_UTIL_H__ */

View File

@@ -15,6 +15,7 @@
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#include "rand.h"
/** @def XMPP_UUID_LEN /** @def XMPP_UUID_LEN
* UUID length in string representation excluding '\0'. * UUID length in string representation excluding '\0'.
@@ -64,7 +65,7 @@ char *xmpp_uuid_gen(xmpp_ctx_t *ctx)
{ {
char *uuid; char *uuid;
uuid = strophe_alloc(ctx, XMPP_UUID_LEN + 1); uuid = xmpp_alloc(ctx, XMPP_UUID_LEN + 1);
if (uuid != NULL) { if (uuid != NULL) {
crypto_uuid_gen(ctx, uuid); crypto_uuid_gen(ctx, uuid);
} }

274
strophe.h
View File

@@ -79,10 +79,6 @@ extern "C" {
* Namespace definition for 'jabber:iq:register'. * Namespace definition for 'jabber:iq:register'.
*/ */
#define XMPP_NS_REGISTER "jabber:iq:register" #define XMPP_NS_REGISTER "jabber:iq:register"
/** @def XMPP_NS_SM
* Namespace definition for Stream Management.
*/
#define XMPP_NS_SM "urn:xmpp:sm:3"
/* error defines */ /* error defines */
/** @def XMPP_EOK /** @def XMPP_EOK
@@ -126,14 +122,9 @@ typedef struct _xmpp_log_t xmpp_log_t;
/* opaque run time context containing the above hooks */ /* opaque run time context containing the above hooks */
typedef struct _xmpp_ctx_t xmpp_ctx_t; typedef struct _xmpp_ctx_t xmpp_ctx_t;
typedef struct _xmpp_tlscert_t xmpp_tlscert_t;
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log); xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log);
void xmpp_ctx_free(xmpp_ctx_t *ctx); void xmpp_ctx_free(xmpp_ctx_t *ctx);
/* set the verbosity level of the ctx */
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level);
/* free some blocks returned by other APIs, for example the /* free some blocks returned by other APIs, for example the
buffer you get from xmpp_stanza_to_text */ buffer you get from xmpp_stanza_to_text */
void xmpp_free(const xmpp_ctx_t *ctx, void *p); void xmpp_free(const xmpp_ctx_t *ctx, void *p);
@@ -172,7 +163,6 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level);
/* opaque connection object */ /* opaque connection object */
typedef struct _xmpp_conn_t xmpp_conn_t; typedef struct _xmpp_conn_t xmpp_conn_t;
typedef struct _xmpp_stanza_t xmpp_stanza_t; typedef struct _xmpp_stanza_t xmpp_stanza_t;
typedef struct _xmpp_sm_t xmpp_sm_state_t;
/* connection flags */ /* connection flags */
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0) #define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
@@ -186,10 +176,6 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
* Enable legacy authentication support. * Enable legacy authentication support.
*/ */
#define XMPP_CONN_FLAG_LEGACY_AUTH (1UL << 4) #define XMPP_CONN_FLAG_LEGACY_AUTH (1UL << 4)
/** @def XMPP_CONN_FLAG_DISABLE_SM
* Disable Stream-Management XEP-0198.
*/
#define XMPP_CONN_FLAG_DISABLE_SM (1UL << 5)
/* connect callback */ /* connect callback */
typedef enum { typedef enum {
@@ -226,24 +212,6 @@ typedef enum {
XMPP_SE_XML_NOT_WELL_FORMED XMPP_SE_XML_NOT_WELL_FORMED
} xmpp_error_type_t; } xmpp_error_type_t;
/** Certificate Elements
*
* @ingroup TLS
*/
typedef enum {
XMPP_CERT_VERSION, /**< X.509 Version */
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
XMPP_CERT_SUBJECT, /**< Subject */
XMPP_CERT_ISSUER, /**< Issuer */
XMPP_CERT_NOTBEFORE, /**< Issued on */
XMPP_CERT_NOTAFTER, /**< Expires on */
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
} xmpp_cert_element_t;
typedef struct { typedef struct {
xmpp_error_type_t type; xmpp_error_type_t type;
char *text; char *text;
@@ -256,103 +224,6 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t *conn,
xmpp_stream_error_t *stream_error, xmpp_stream_error_t *stream_error,
void *userdata); void *userdata);
/** The Handler function which will be called when the TLS stack can't
* verify the authenticity of a Certificate that gets presented by
* the server we're trying to connect to.
*
* When this function is called and details of the `cert` have to be
* kept, please copy them yourself. The `cert` object will be free'd
* automatically when this function returns.
*
* NB: `errormsg` is specific per certificate on OpenSSL and the same
* for all certificates on GnuTLS.
*
* @param cert a Strophe certificate object
* @param errormsg The error that caused this.
*
* @return 0 if the connection attempt should be terminated,
* 1 if the connection should be established.
*
* @ingroup TLS
*/
typedef int (*xmpp_certfail_handler)(const xmpp_tlscert_t *cert,
const char *const errormsg);
/** The Handler function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* When this callback is called it shall write a NULL-terminated
* string of maximum length `pw_max - 1` to `pw`.
*
* This is currently only supported for GnuTLS and OpenSSL.
*
* On 2022-02-02 the following maximum lengths are valid:
* ```
* include/gnutls/pkcs11.h: #define GNUTLS_PKCS11_MAX_PIN_LEN 256
* include/openssl/pem.h: #define PEM_BUFSIZE 1024
* ```
*
* We expect the buffer to be NULL-terminated, therefore the usable lengths
* are:
*
* * 255 for GnuTLS
* * 1023 for OpenSSL
*
* Useful API's inside this callback are e.g.
*
* \ref xmpp_conn_get_keyfile
*
*
* @param pw The buffer where the password shall be stored.
* @param pw_max The maximum length of the password.
* @param conn The Strophe connection object this callback originates from.
* @param userdata The userdata pointer as supplied when setting this callback.
*
* @return -1 on error, else the number of bytes written to `pw` w/o
* terminating NUL byte
*
* @ingroup TLS
*/
typedef int (*xmpp_password_callback)(char *pw,
size_t pw_max,
xmpp_conn_t *conn,
void *userdata);
/** The function which will be called when Strophe creates a new socket.
*
* The `sock` argument is a pointer that is dependent on the architecture
* Strophe is compiled for.
*
* For POSIX compatible systems usage shall be:
* ```
* int soc = *((int*)sock);
* ```
*
* On Windows usage shall be:
* ```
* SOCKET soc = *((SOCKET*)sock);
* ```
*
* This function will be called for each socket that is created.
*
* `examples/bot.c` uses a libstrophe supplied callback function that sets
* basic keepalive parameters (`xmpp_sockopt_cb_keepalive()`).
*
* `examples/complex.c` implements a custom function that could be useful
* for an application.
*
* @param conn The Strophe connection object this callback originates from.
* @param sock A pointer to the underlying file descriptor.
*
* @return 0 on success, -1 on error
*
* @ingroup Connections
*/
typedef int (*xmpp_sockopt_callback)(xmpp_conn_t *conn, void *sock);
/* an example callback that sets basic keepalive parameters */
int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text); void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx); xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn); xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
@@ -363,16 +234,6 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid); void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn, void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert, const char *cert,
const char *key); const char *key);
@@ -383,24 +244,10 @@ void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn); xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
void xmpp_conn_disable_tls(xmpp_conn_t *conn); void xmpp_conn_disable_tls(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn); int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn, void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
xmpp_sockopt_callback callback);
int xmpp_conn_is_connecting(xmpp_conn_t *conn); int xmpp_conn_is_connecting(xmpp_conn_t *conn);
int xmpp_conn_is_connected(xmpp_conn_t *conn); int xmpp_conn_is_connected(xmpp_conn_t *conn);
int xmpp_conn_is_disconnected(xmpp_conn_t *conn); int xmpp_conn_is_disconnected(xmpp_conn_t *conn);
int xmpp_conn_send_queue_len(const xmpp_conn_t *conn);
typedef enum {
XMPP_QUEUE_OLDEST = -1,
XMPP_QUEUE_YOUNGEST = -2,
} xmpp_queue_element_t;
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);
void xmpp_free_sm_state(xmpp_sm_state_t *sm_state);
int xmpp_connect_client(xmpp_conn_t *conn, int xmpp_connect_client(xmpp_conn_t *conn,
const char *altdomain, const char *altdomain,
@@ -509,9 +356,6 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t *stanza,
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t *stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t *stanza,
const char *name, const char *name,
const char *ns); const char *ns);
/* helper macro for names with a namespace */
#define XMPP_STANZA_NAME_IN_NS(name, ns) name "[@ns='" ns "']"
xmpp_stanza_t *xmpp_stanza_get_child_by_path(xmpp_stanza_t *stanza, ...);
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t *stanza); xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t *stanza);
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child); int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza, int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza,
@@ -590,17 +434,6 @@ void xmpp_run(xmpp_ctx_t *ctx);
void xmpp_stop(xmpp_ctx_t *ctx); void xmpp_stop(xmpp_ctx_t *ctx);
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout); void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
/* TLS certificates */
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert);
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n);
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
xmpp_cert_element_t elmnt);
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt);
void xmpp_tlscert_free(xmpp_tlscert_t *cert);
/* UUID */ /* UUID */
char *xmpp_uuid_gen(xmpp_ctx_t *ctx); char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
@@ -638,111 +471,6 @@ void xmpp_base64_decode_bin(xmpp_ctx_t *ctx,
unsigned char **out, unsigned char **out,
size_t *outlen); size_t *outlen);
/* RNG */
typedef struct _xmpp_rand_t xmpp_rand_t;
/** Create new xmpp_rand_t object.
*
* @param ctx A Strophe context object
*
* @ingroup Random
*/
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
/** Destroy an xmpp_rand_t object.
*
* @param ctx A Strophe context object
* @param rand A xmpp_rand_t object
*
* @ingroup Random
*/
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
/** Generate random integer.
* Analogue of rand(3).
*
* @ingroup Random
*/
int xmpp_rand(xmpp_rand_t *rand);
/** Generate random bytes.
* Generates len bytes and stores them to the output buffer.
*
* @param rand A xmpp_rand_t object
* @param output A buffer where a len random bytes will be placed.
* @param len Number of bytes reserved for the output..
*
* @ingroup Random
*/
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
/** Generate a nonce that is printable randomized string.
* This function doesn't allocate memory and doesn't fail.
*
* @param rand A xmpp_rand_t object
* @param output A buffer where a NULL-terminated string will be placed.
* The string will contain len-1 printable symbols.
* @param len Number of bytes reserved for the output string, including
* end of line '\0'.
*
* @ingroup Random
*/
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>
#if defined(__GNUC__)
#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
#define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
#elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 300)
#define XMPP_DEPRECATED(x) __attribute__((deprecated))
#endif
#elif defined(_MSC_VER) && _MSC_VER >= 1500
#define XMPP_DEPRECATED(x) __declspec(deprecated("replaced by " #x))
#else
#define XMPP_DEPRECATED(x)
#endif
XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
XMPP_DEPRECATED(internal)
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
XMPP_DEPRECATED(internal)
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s);
XMPP_DEPRECATED(internal)
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
XMPP_DEPRECATED(internal)
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
XMPP_DEPRECATED(internal)
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...);
XMPP_DEPRECATED(internal)
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg);
XMPP_DEPRECATED(internal)
void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap);
XMPP_DEPRECATED(internal)
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
XMPP_DEPRECATED(internal)
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
XMPP_DEPRECATED(internal)
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
XMPP_DEPRECATED(internal)
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
XMPP_DEPRECATED(internal)
void xmpp_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
XMPP_DEPRECATED(xmpp_conn_set_sockopt_callback)
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,13 +0,0 @@
#!/bin/sh
logfile="../../testbuild.log"
err_out() {
tail $logfile
exit 1
}
./bootstrap.sh
./configure >> $logfile || err_out
make -j$(( `nproc` * 2 + 1 )) >> $logfile || err_out
make check >> $logfile || err_out

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,8 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,30B7F2152A39184AEEF290ED2B1DBC0E
IojJAF1hGHL9qnu5MCzl5l1PzsnxLj38JjLBLPXaNekiAbag5H9Tzr7y5nfyviPM
hi6syrkXgLOBF+mZWJouOxCNx7+t6eWVfsDZcnzsw6HrTN/2xwkYP/3lYfzlnt6q
/AKYQIUUPc/31J6xg3kGRQ==
-----END EC PRIVATE KEY-----

View File

@@ -14,7 +14,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include "ostypes.h" #include "ostypes.h"
@@ -38,7 +37,7 @@
do { \ do { \
const char *__v1 = v1; \ const char *__v1 = v1; \
const char *__v2 = v2; \ const char *__v2 = v2; \
if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \ if (strcmp(__v1, __v2) != 0) { \
printf("Error: %s\n" \ printf("Error: %s\n" \
"Expected: %s\n" \ "Expected: %s\n" \
"Got: %s\n", \ "Got: %s\n", \
@@ -61,19 +60,6 @@
} \ } \
} while (0) } 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); \
} \
} while (0)
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len); void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len);
const char *test_bin_to_hex(const uint8_t *bin, size_t len); const char *test_bin_to_hex(const uint8_t *bin, size_t len);

View File

@@ -81,22 +81,22 @@ int main()
mylog.userdata = my_str; mylog.userdata = my_str;
ctx = xmpp_ctx_new(&mymem, &mylog); ctx = xmpp_ctx_new(&mymem, &mylog);
strophe_debug(ctx, "test", "hello"); xmpp_debug(ctx, "test", "hello");
testptr1 = strophe_alloc(ctx, 1024); testptr1 = xmpp_alloc(ctx, 1024);
if (testptr1 == NULL) { if (testptr1 == NULL) {
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
return 1; return 1;
} }
testptr2 = strophe_realloc(ctx, testptr1, 2048); testptr2 = xmpp_realloc(ctx, testptr1, 2048);
if (testptr2 == NULL) { if (testptr2 == NULL) {
strophe_free(ctx, testptr1); xmpp_free(ctx, testptr1);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
return 1; return 1;
} }
strophe_free(ctx, testptr2); xmpp_free(ctx, testptr2);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);

View File

@@ -1,49 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "parser.h"
void xmpp_initialize(void);
void cbtest_handle_start(char *name, char **attrs, void *userdata)
{
(void)name;
(void)attrs;
(void)userdata;
}
void cbtest_handle_end(char *name, void *userdata)
{
(void)name;
(void)userdata;
}
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
{
(void)stanza;
(void)userdata;
}
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
xmpp_ctx_t *ctx;
parser_t *parser;
char *dup = malloc(Size);
memcpy(dup, Data, Size);
ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end,
cbtest_handle_stanza, NULL);
parser_feed(parser, dup, Size);
free(dup);
parser_free(parser);
xmpp_ctx_free(ctx);
return 0;
}

View File

@@ -1,63 +0,0 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "resolver.h"
void xmpp_initialize(void);
void cbtest_handle_start(char *name, char **attrs, void *userdata)
{
(void)name;
(void)attrs;
(void)userdata;
}
void cbtest_handle_end(char *name, void *userdata)
{
(void)name;
(void)userdata;
}
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
{
(void)stanza;
(void)userdata;
}
/* res_query("_xmpp-client._tcp.jabber.org", C_IN, T_SRV, ...) */
static const unsigned char data2[] = {
0xf2, 0x98, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65,
0x72, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c,
0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1a, 0x00, 0x1e,
0x00, 0x1e, 0x14, 0x66, 0x07, 0x68, 0x65, 0x72, 0x6d, 0x65, 0x73, 0x32,
0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03, 0x6f, 0x72, 0x67, 0x00,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x1c,
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0x09, 0x68, 0x65, 0x72, 0x6d, 0x65,
0x73, 0x32, 0x76, 0x36, 0x06, 0x6a, 0x61, 0x62, 0x62, 0x65, 0x72, 0x03,
0x6f, 0x72, 0x67, 0x00,
};
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
xmpp_ctx_t *ctx;
resolver_srv_rr_t *srv_rr_list;
unsigned char *dup = malloc(Size + 64);
memcpy(dup, data2, 64);
memcpy(&dup[64], Data, Size);
ctx = xmpp_ctx_new(NULL, NULL);
resolver_srv_lookup_buf(ctx, dup, 64 + Size, &srv_rr_list);
if (srv_rr_list != NULL)
resolver_srv_free(ctx, srv_rr_list);
free(dup);
xmpp_ctx_free(ctx);
return 0;
}

View File

@@ -55,7 +55,7 @@ int main(int argc, char **argv)
} }
/* allocate a hash table */ /* allocate a hash table */
table = hash_new(ctx, TABLESIZE, strophe_free); table = hash_new(ctx, TABLESIZE, xmpp_free);
if (table == NULL) { if (table == NULL) {
/* table allocation failed! */ /* table allocation failed! */
return 1; return 1;
@@ -63,7 +63,7 @@ int main(int argc, char **argv)
/* test insertion */ /* test insertion */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[i], strophe_strdup(ctx, values[i])); err = hash_add(table, keys[i], xmpp_strdup(ctx, values[i]));
if (err) if (err)
return err; return err;
} }
@@ -76,7 +76,7 @@ int main(int argc, char **argv)
/* test replacing old values */ /* test replacing old values */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[0], strophe_strdup(ctx, values[i])); err = hash_add(table, keys[0], xmpp_strdup(ctx, values[i]));
if (err) if (err)
return err; return err;
if (hash_num_keys(table) != nkeys) if (hash_num_keys(table) != nkeys)
@@ -88,7 +88,7 @@ int main(int argc, char **argv)
return 1; return 1;
} }
/* restore value for the 1st key */ /* restore value for the 1st key */
hash_add(table, keys[0], strophe_strdup(ctx, values[0])); hash_add(table, keys[0], xmpp_strdup(ctx, values[0]));
/* test cloning */ /* test cloning */
clone = hash_clone(table); clone = hash_clone(table);

View File

@@ -47,13 +47,13 @@ int test_jid(xmpp_ctx_t *ctx)
if (resource != NULL) if (resource != NULL)
return 1; return 1;
if (bare) if (bare)
strophe_free(ctx, bare); xmpp_free(ctx, bare);
if (node) if (node)
strophe_free(ctx, node); xmpp_free(ctx, node);
if (domain) if (domain)
strophe_free(ctx, domain); xmpp_free(ctx, domain);
if (resource) if (resource)
strophe_free(ctx, resource); xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid2); bare = xmpp_jid_bare(ctx, jid2);
node = xmpp_jid_node(ctx, jid2); node = xmpp_jid_node(ctx, jid2);
@@ -70,13 +70,13 @@ int test_jid(xmpp_ctx_t *ctx)
if (resource == NULL || strcmp(resource, "hullo")) if (resource == NULL || strcmp(resource, "hullo"))
return 1; return 1;
if (bare) if (bare)
strophe_free(ctx, bare); xmpp_free(ctx, bare);
if (node) if (node)
strophe_free(ctx, node); xmpp_free(ctx, node);
if (domain) if (domain)
strophe_free(ctx, domain); xmpp_free(ctx, domain);
if (resource) if (resource)
strophe_free(ctx, resource); xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3); bare = xmpp_jid_bare(ctx, jid3);
node = xmpp_jid_node(ctx, jid3); node = xmpp_jid_node(ctx, jid3);
@@ -93,13 +93,13 @@ int test_jid(xmpp_ctx_t *ctx)
if (resource == NULL || strcmp(resource, "frob")) if (resource == NULL || strcmp(resource, "frob"))
return 1; return 1;
if (bare) if (bare)
strophe_free(ctx, bare); xmpp_free(ctx, bare);
if (node) if (node)
strophe_free(ctx, node); xmpp_free(ctx, node);
if (domain) if (domain)
strophe_free(ctx, domain); xmpp_free(ctx, domain);
if (resource) if (resource)
strophe_free(ctx, resource); xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4); bare = xmpp_jid_bare(ctx, jid4);
node = xmpp_jid_node(ctx, jid4); node = xmpp_jid_node(ctx, jid4);
@@ -116,13 +116,13 @@ int test_jid(xmpp_ctx_t *ctx)
if (resource != NULL) if (resource != NULL)
return 1; return 1;
if (bare) if (bare)
strophe_free(ctx, bare); xmpp_free(ctx, bare);
if (node) if (node)
strophe_free(ctx, node); xmpp_free(ctx, node);
if (domain) if (domain)
strophe_free(ctx, domain); xmpp_free(ctx, domain);
if (resource) if (resource)
strophe_free(ctx, resource); xmpp_free(ctx, resource);
return 0; return 0;
} }
@@ -135,13 +135,13 @@ int test_jid_new(xmpp_ctx_t *ctx)
printf("new jid: '%s'\n", jid); printf("new jid: '%s'\n", jid);
if (strcmp(jid, "node@domain/resource")) if (strcmp(jid, "node@domain/resource"))
return 1; return 1;
strophe_free(ctx, jid); xmpp_free(ctx, jid);
jid = xmpp_jid_new(ctx, "foo", "bar.com", NULL); jid = xmpp_jid_new(ctx, "foo", "bar.com", NULL);
printf("new jid: '%s'\n", jid); printf("new jid: '%s'\n", jid);
if (strcmp(jid, "foo@bar.com")) if (strcmp(jid, "foo@bar.com"))
return 1; return 1;
strophe_free(ctx, jid); xmpp_free(ctx, jid);
return 0; return 0;
} }

View File

@@ -21,21 +21,21 @@
#include "rand.c" #include "rand.c"
/* stubs to build test without whole libstrophe */ /* stubs to build test without whole libstrophe */
void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
{ {
(void)ctx; (void)ctx;
(void)size; (void)size;
return NULL; return NULL;
} }
void strophe_free(const xmpp_ctx_t *ctx, void *p) void xmpp_free(const xmpp_ctx_t *ctx, void *p)
{ {
(void)ctx; (void)ctx;
(void)p; (void)p;
} }
#ifndef HAVE_SNPRINTF #ifndef HAVE_SNPRINTF
int strophe_snprintf(char *str, size_t count, const char *fmt, ...) int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{ {
(void)str; (void)str;
(void)count; (void)count;
@@ -49,8 +49,6 @@ uint64_t time_stamp(void)
return 0; return 0;
} }
#ifndef USE_GETRANDOM
static struct { static struct {
const char *entropy_input; const char *entropy_input;
const char *nonce; const char *nonce;
@@ -162,19 +160,3 @@ int main()
return 0; return 0;
} }
#else
int main()
{
uint8_t output[1024];
xmpp_rand_t *rand = xmpp_rand_new(NULL);
assert(rand != NULL);
/* this would assert if it failed */
xmpp_rand_bytes(rand, output, sizeof(output));
return 0;
}
#endif

View File

@@ -13,6 +13,7 @@
#include <stdio.h> #include <stdio.h>
#include "strophe.h" #include "strophe.h"
#include "rand.h"
#include "resolver.h" #include "resolver.h"
#include "test.h" #include "test.h"
@@ -216,14 +217,14 @@ int main()
rand = xmpp_rand_new(ctx); rand = xmpp_rand_new(ctx);
assert(rand != NULL); assert(rand != NULL);
assert(sizeof(data2) > 64); assert(sizeof(data2) > 64);
buf = strophe_alloc(ctx, sizeof(data2)); buf = xmpp_alloc(ctx, sizeof(data2));
assert(buf != NULL); assert(buf != NULL);
memcpy(buf, data2, 64); memcpy(buf, data2, 64);
xmpp_rand_bytes(rand, &buf[64], sizeof(data2) - 64); xmpp_rand_bytes(rand, &buf[64], sizeof(data2) - 64);
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list); ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL) if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
resolver_srv_free(ctx, srv_rr_list); resolver_srv_free(ctx, srv_rr_list);
strophe_free(ctx, buf); xmpp_free(ctx, buf);
xmpp_rand_free(ctx, rand); xmpp_rand_free(ctx, rand);
printf("ok\n"); printf("ok\n");

View File

@@ -29,6 +29,23 @@ static const char response_md5[] =
"MDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL3NvbWVyZWFsbSIscmVz" "MDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL3NvbWVyZWFsbSIscmVz"
"cG9uc2U9NGVhNmU4N2JjMDkzMzUwNzQzZGIyOGQ3MDIwOGNhZmIsY2hhcnNl" "cG9uc2U9NGVhNmU4N2JjMDkzMzUwNzQzZGIyOGQ3MDIwOGNhZmIsY2hhcnNl"
"dD11dGYtOA=="; "dD11dGYtOA==";
static const char response_md5_rfc[] =
"dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i"
"T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw"
"MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i"
"LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo"
"YXJzZXQ9dXRmLTgK";
static const char challenge_md5_2[] =
"cmVhbG09ImVsd29vZC5pbm5vc29mdC5jb20iLG5vbmNlPSJPQTZNRzl0"
"RVFHbTJoaCIscW9wPSJhdXRoIixhbGdvcml0aG09bWQ1LXNlc3MsY2hh"
"cnNldD11dGYtOA==";
static const char response_md5_2[] =
"Y2hhcnNldD11dGYtOCx1c2VybmFtZT0iY2hyaXMiLHJlYWxtPSJlbHdvb2"
"QuaW5ub3NvZnQuY29tIixub25jZT0iT0E2TUc5dEVRR20yaGgiLG5jPTAw"
"MDAwMDAxLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLGRpZ2VzdC11cmk9Im"
"ltYXAvZWx3b29kLmlubm9zb2Z0LmNvbSIscmVzcG9uc2U9ZDM4OGRhZDkw"
"ZDRiYmQ3NjBhMTUyMzIxZjIxNDNhZjcscW9wPWF1dGg=";
int test_plain(xmpp_ctx_t *ctx) int test_plain(xmpp_ctx_t *ctx)
{ {
@@ -43,7 +60,7 @@ int test_plain(xmpp_ctx_t *ctx)
/* SASL PLAIN returned incorrect string! */ /* SASL PLAIN returned incorrect string! */
return 2; return 2;
} }
strophe_free(ctx, result); xmpp_free(ctx, result);
return 0; return 0;
} }

View File

@@ -1,92 +0,0 @@
/* test_send_queue.c
** libstrophe XMPP client library -- test routines for the send queue
**
** Copyright (C) 2021 Steffen Jaeckel
**
** This software is provided AS-IS with no warranty, either express
** or implied.
**
** This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "strophe.h"
#include "common.h"
#include "test.h"
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;
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;
xmpp_conn_set_sm_state(conn, sm_state);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 0);
state = conn->state;
conn->state = XMPP_STATE_CONNECTED;
xmpp_send_raw(conn, "foo", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 1);
xmpp_send_raw(conn, "bar", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 2);
xmpp_send_raw(conn, "baz", 3);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3);
xmpp_send_raw(conn, "baan", 4);
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 4);
conn->send_queue_head->wip = 1;
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3);
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);
conn->send_queue_head->wip = 0;
ENSURE_EQ(xmpp_conn_send_queue_len(conn), 3);
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);
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);
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);
conn->state = state;
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -37,7 +37,7 @@ int main(void)
for (x = 0; fp_fmt[x] != NULL; x++) for (x = 0; fp_fmt[x] != NULL; x++)
for (y = 0; fp_nums[y] != 0; y++) { for (y = 0; fp_nums[y] != 0; y++) {
strophe_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); xmpp_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
sprintf(buf2, fp_fmt[x], fp_nums[y]); sprintf(buf2, fp_fmt[x], fp_nums[y]);
if (strcmp(buf1, buf2)) { if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: " printf("xmpp_snprintf doesn't match Format: "
@@ -50,7 +50,7 @@ int main(void)
for (x = 0; int_fmt[x] != NULL; x++) for (x = 0; int_fmt[x] != NULL; x++)
for (y = 0; int_nums[y] != 0; y++) { for (y = 0; int_nums[y] != 0; y++) {
strophe_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); xmpp_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
sprintf(buf2, int_fmt[x], int_nums[y]); sprintf(buf2, int_fmt[x], int_nums[y]);
if (strcmp(buf1, buf2)) { if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: " printf("xmpp_snprintf doesn't match Format: "

View File

@@ -17,8 +17,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "test.h"
#define MAGICPTR ((void *)0xfeedbeef) #define MAGICPTR ((void *)0xfeedbeef)
static unsigned long used_blocks = 0; static unsigned long used_blocks = 0;
@@ -99,7 +97,7 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
size_t buflen; size_t buflen;
int ret; int ret;
const char *str = static const char *str =
"<signcrypt xmlns=\"urn:xmpp:openpgp:0\"><to " "<signcrypt xmlns=\"urn:xmpp:openpgp:0\"><to "
"jid=\"user@domain.com\"/><time " "jid=\"user@domain.com\"/><time "
"stamp=\"2020-06-03T21:26:24+0200\"/><rpad/><payload><body " "stamp=\"2020-06-03T21:26:24+0200\"/><rpad/><payload><body "
@@ -109,137 +107,9 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
assert(stanza != NULL); assert(stanza != NULL);
ret = xmpp_stanza_to_text(stanza, &buf, &buflen); ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
assert(ret == XMPP_EOK); assert(ret == XMPP_EOK);
COMPARE(str, buf); assert(strcmp(buf, str) == 0);
xmpp_free(ctx, buf); xmpp_free(ctx, buf);
xmpp_stanza_release(stanza); xmpp_stanza_release(stanza);
/* create a string with two stanzas to make sure we don't
* leak any memory when we convert them to a xmpp_stanza_t
*/
buf = malloc(strlen(str) * 2 + 1);
assert(buf != NULL);
memcpy(buf, str, strlen(str) + 1);
memcpy(&buf[strlen(str)], str, strlen(str) + 1);
stanza = xmpp_stanza_new_from_string(ctx, buf);
assert(stanza != NULL);
free(buf);
ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
assert(ret == XMPP_EOK);
COMPARE(str, buf);
xmpp_free(ctx, buf);
xmpp_stanza_release(stanza);
/* Error path. */
stanza = xmpp_stanza_new_from_string(ctx, "<uu><uu>tt");
assert(stanza == NULL);
}
static void test_stanza_error(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
xmpp_stanza_t *error;
xmpp_stanza_t *item;
xmpp_stanza_t *mood;
char *buf;
size_t buflen;
const char *attr[10];
int attrlen = ARRAY_SIZE(attr);
int ret;
static const char *str =
"<iq from='romeo@montague.lit/home' to='juliet@capulet.lit/chamber' "
"type='get' id='e2e1'><ping xmlns='urn:xmpp:ping'/></iq>";
static const char *str_error =
"<error type=\"cancel\"><service-unavailable "
"xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/></error>";
// clang-format off
static const char *str_mood =
"<iq from='juliet@capulet.lit/balcony' id='publish1' type='set'>"
"<pubsub xmlns='http://jabber.org/protocol/pubsub'>"
"<publish node='http://jabber.org/protocol/mood'>"
"<item>"
"<mood xmlns='http://jabber.org/protocol/mood'>"
"<annoyed/>"
"<text>curse my nurse!</text>"
"</mood>"
"</item>"
"</publish>"
"</pubsub>"
"</iq>";
// clang-format on
stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
error =
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(xmpp_stanza_get_to(error) != NULL);
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));
assert(xmpp_stanza_get_from(error) != NULL);
COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error));
assert(xmpp_stanza_get_id(error) != NULL);
COMPARE("e2e1", xmpp_stanza_get_id(error));
assert(xmpp_stanza_get_type(error) != NULL);
COMPARE("error", xmpp_stanza_get_type(error));
/* FAIL - no list given */
item = xmpp_stanza_get_child_by_path(mood, NULL);
assert(item == NULL);
/* FAIL - first entry doesn't match */
item = xmpp_stanza_get_child_by_path(mood, "foo", NULL);
assert(item == NULL);
/* FAIL - 'iq' has no namespace */
item = xmpp_stanza_get_child_by_path(
mood, XMPP_STANZA_NAME_IN_NS("iq", "foobar"),
XMPP_STANZA_NAME_IN_NS("pubsub", "http://jabber.org/protocol/pubsub"),
"publish", "item", "mood", NULL);
assert(item == NULL);
/* FAIL - 'pubsub' is in another namespace */
item = xmpp_stanza_get_child_by_path(
mood, "iq",
XMPP_STANZA_NAME_IN_NS("pubsub", "http://jabber.org/protocol/foobar"),
"publish", "item", "mood", NULL);
assert(item == NULL);
item = xmpp_stanza_get_child_by_path(mood, "iq", "pubsub", "publish",
"item", "mood", NULL);
assert(item != NULL);
assert(xmpp_stanza_get_children(item) != NULL);
assert(xmpp_stanza_get_name(xmpp_stanza_get_children(item)) != NULL);
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
item = xmpp_stanza_get_child_by_path(
mood, "iq",
XMPP_STANZA_NAME_IN_NS("pubsub", "http://jabber.org/protocol/pubsub"),
"publish", "item",
XMPP_STANZA_NAME_IN_NS("mood", "http://jabber.org/protocol/mood"),
NULL);
assert(item != NULL);
assert(xmpp_stanza_get_children(item) != NULL);
assert(xmpp_stanza_get_name(xmpp_stanza_get_children(item)) != NULL);
COMPARE("annoyed", xmpp_stanza_get_name(xmpp_stanza_get_children(item)));
ret = xmpp_stanza_get_attributes(error, attr, attrlen);
/* attr contains both attribute name and value. */
assert(ret == 8);
item = xmpp_stanza_get_child_by_name(error, "error");
assert(item != NULL);
ret = xmpp_stanza_to_text(item, &buf, &buflen);
assert(ret == XMPP_EOK);
COMPARE(str_error, buf);
xmpp_free(ctx, buf);
xmpp_stanza_release(mood);
xmpp_stanza_release(stanza);
xmpp_stanza_release(error);
} }
int main() int main()
@@ -252,7 +122,6 @@ int main()
test_stanza_add_child(ctx); test_stanza_add_child(ctx);
test_stanza_from_string(ctx); test_stanza_from_string(ctx);
test_stanza_error(ctx);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
xmpp_shutdown(); xmpp_shutdown();

View File

@@ -41,19 +41,19 @@ static int test_strtok_r(void)
assert(strcmp(s1, s2) == 0); assert(strcmp(s1, s2) == 0);
sub1 = strtok_r(s1, "-", &sp1); sub1 = strtok_r(s1, "-", &sp1);
sub2 = strophe_strtok_r(s2, "-", &sp2); sub2 = xmpp_strtok_r(s2, "-", &sp2);
if (strcmp(sub1, sub2) != 0) { if (strcmp(sub1, sub2) != 0) {
printf("1st token is '%s', must be '%s'\n", sub2, sub1); printf("1st token is '%s', must be '%s'\n", sub2, sub1);
return -1; return -1;
} }
sub1 = strtok_r(NULL, "-=", &sp1); sub1 = strtok_r(NULL, "-=", &sp1);
sub2 = strophe_strtok_r(NULL, "-=", &sp2); sub2 = xmpp_strtok_r(NULL, "-=", &sp2);
if (strcmp(sub1, sub2) != 0) { if (strcmp(sub1, sub2) != 0) {
printf("2nd token is '%s', must be '%s'\n", sub2, sub1); printf("2nd token is '%s', must be '%s'\n", sub2, sub1);
return -1; return -1;
} }
sub1 = strtok_r(NULL, "-", &sp1); sub1 = strtok_r(NULL, "-", &sp1);
sub2 = strophe_strtok_r(NULL, "-", &sp2); sub2 = xmpp_strtok_r(NULL, "-", &sp2);
if (sub1 != sub2) { if (sub1 != sub2) {
printf("3rd call returns %p instead of NULL\n", sub2); printf("3rd call returns %p instead of NULL\n", sub2);
return -1; return -1;
@@ -71,7 +71,7 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
int rc = 0; int rc = 0;
s1 = strdup(s); s1 = strdup(s);
s2 = strophe_strdup(ctx, s); s2 = xmpp_strdup(ctx, s);
if (!s1 || !s2 || strcmp(s1, s2) != 0) { if (!s1 || !s2 || strcmp(s1, s2) != 0) {
rc = -1; rc = -1;
@@ -81,7 +81,7 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
free(s1); free(s1);
if (s2) if (s2)
strophe_free(ctx, s2); xmpp_free(ctx, s2);
return rc; return rc;
} }

View File

@@ -13,75 +13,28 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/param.h>
#include "strophe.h" #include "strophe.h"
#include "test.h" #include "test.h"
static int
password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn, void *userdata)
{
(void)pw_max;
(void)userdata;
(void)conn;
memcpy(pw, "abc123", 7);
return 6;
}
int main() int main()
{ {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_log_t *log; xmpp_log_t *log;
struct {
int needs_callback;
char *pem, *key;
} client_cert[] = {
{0, "tests/cert.pem", "tests/key.pem"},
{1, "tests/cert.pem", "tests/key_encrypted.pem"},
{0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"},
{0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL},
};
const char *srcdir;
char *certbuf, *keybuf;
char xmppaddr_num[] = "0"; char xmppaddr_num[] = "0";
unsigned int m, n; unsigned int n;
xmpp_initialize(); xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log); 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); conn = xmpp_conn_new(ctx);
if (client_cert[m].pem) xmpp_conn_set_client_cert(conn, "tests/cert.pem", "tests/key.pem");
snprintf(certfile, MAXPATHLEN, "%s/%s", srcdir, client_cert[m].pem);
else
certfile = NULL;
if (client_cert[m].key) xmppaddr_num[0] = xmppaddr_num[0] + xmpp_conn_cert_xmppaddr_num(conn);
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, certfile, keyfile);
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);
COMPARE("2", xmppaddr_num); COMPARE("2", xmppaddr_num);
@@ -89,8 +42,7 @@ int main()
char *r = xmpp_conn_cert_xmppaddr(conn, n); char *r = xmpp_conn_cert_xmppaddr(conn, n);
switch (n) { switch (n) {
case 0: case 0:
COMPARE( COMPARE("very.long.username@so.the.asn1.length.is.a.valid.ascii."
"very.long.username@so.the.asn1.length.is.a.valid.ascii."
"character", "character",
r); r);
break; break;
@@ -99,8 +51,8 @@ int main()
break; break;
default: default:
if (r != NULL) { if (r != NULL) {
printf("\nThere shall only be two id-on-xmppAddr SANs!\n" printf("\nThere shall only be two id-on-xmppAddr SANs!\nFound "
"Found another one: %s\n", "another one: %s\n",
r); r);
exit(1); exit(1);
} }
@@ -108,11 +60,8 @@ int main()
} }
free(r); free(r);
} }
xmpp_conn_release(conn);
}
free(certbuf);
free(keybuf);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx); xmpp_ctx_free(ctx);
xmpp_shutdown(); xmpp_shutdown();

View File

@@ -1,26 +1,14 @@
#!/bin/sh #!/bin/sh
set -e if [ "x$LIBRESSL" = "xyes" ]; then
[ "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"
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" cd "$HOME"
git clone --no-checkout "$REPO_URL" xssl-git git clone https://github.com/libressl-portable/portable.git libressl-git
cd xssl-git cd libressl-git
git checkout "$XSSL_COMMITISH" if [ -n "$LIBRESSL_COMMIT" ]; then
$AUTOGEN_CMD git checkout "$LIBRESSL_COMMIT"
$CONFIG_CMD fi
./autogen.sh
./configure --prefix="$HOME/libressl"
make -j"$(nproc)" make -j"$(nproc)"
make $MAKE_TARGET make install
fi