65 Commits

Author SHA1 Message Date
Steffen Jaeckel
675ba5b3fc Release libstrophe-0.12.0
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-05-09 15:40:09 +02:00
Steffen Jaeckel
62d1063560 prevent memory leak in xmpp_stanza_new_from_string()
Only remember the first stanza in case the string contains
multiple stanzas.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-05-05 16:34:44 +02:00
Steffen Jaeckel
d8c9ca49e1 Be user-friendly when opening a pfx/p12 file
Before this change the user had to provide a password callback, even if the
PKCS#12 encoded file has no or an empty password.

This changes the behavior, so we first try to open the file without a
password and only then ask the user to provide one.

This fixes #204.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-05-05 16:34:44 +02:00
Steffen Jaeckel
91d6dac985 add Stream-Management support to bot example
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 13:51:05 +02:00
Steffen Jaeckel
d7bd434f41 add client-cert support to bot example
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 13:51:05 +02:00
Steffen Jaeckel
5ac415986e finish implementing XEP-0198
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 13:51:05 +02:00
Steffen Jaeckel
266fd0b1d4 add send-queue tests
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 11:24:13 +02:00
Steffen Jaeckel
10760238b3 add xmpp_conn_send_queue_drop_element()
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 11:24:13 +02:00
Steffen Jaeckel
d9acad3d91 add xmpp_conn_send_queue_len()
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 11:24:13 +02:00
Steffen Jaeckel
27278c032b introduce owner concept in send_queue
In order to be able to distinguish between user-created entries and
library-internal entries, we mark each entry who it belongs to.
This allows then later to let the user manage only the queue entries
that were created by them.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-04-06 11:24:13 +02:00
Dmitry Podgorny
57bc4bbb75 WIP XEP-0198: implement stream management
Stream management is enabled when server supports it. There is no option
to disable it.
2022-03-31 12:45:39 +02:00
Steffen Jaeckel
3600756723 fix linter warnings
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-31 12:44:19 +02:00
Steffen Jaeckel
7111ee2f85 better deprecation warnings
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-23 19:05:48 +01:00
Steffen Jaeckel
dcee2eea91 also run valgrind in CI
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-23 19:05:48 +01:00
Steffen Jaeckel
4a0c71a840 add option to enable valgrind for tests
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-23 17:04:13 +01:00
Steffen Jaeckel
e1ee758b61 fix warning when compiling against OpenSSL 3.0.x
`ERR_func_error_string()` has been deprecated.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-23 17:04:13 +01:00
Steffen Jaeckel
4b5e103d9c move password cache into libstrophe
The cache is stored per connection object and is cleared on
* entry of wrong password
* release of connection object
* successful connection

It can be configured that libstrophe retries the password entry in case
the user entered a wrong password.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-23 17:04:13 +01:00
Steffen Jaeckel
bddb80a192 add support for a password callback
In order to be able to load password-protected key files a password
callback was added.

This also adds support for PKCS#12 containers instead of certificate+key.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-21 00:24:22 +01:00
Stu Tomlinson
06afe3d1c2 Add API to register callback to set socket options
The registered callback function will be called before connect() is
called on the socket, allowing tweaking of much more than just keepalive
settings.

This deprecates xmpp_conn_set_keepalive().

Includes helper/example callback function to set default keepalive
parameters that some library users may find useful.
2022-03-17 22:59:07 +00:00
Steffen Jaeckel
97b1452211 revive removed API's
In order to do proper deprecation of those API's we re-introduce them
so they can be removed in the next release. This will then also lead to
an ABI bump.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-16 14:39:20 +01:00
Steffen Jaeckel
fc6ba89c61 properly rename internal [v]snprintf() functions
Otherwise it clashes when we want to re-introduce the `xmpp_` prefix'ed
versions.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-16 14:39:20 +01:00
Stu Tomlinson
a92115ab9f Do not compile/link snprintf.o if it is not needed 2022-03-16 11:33:58 +00:00
Stu Tomlinson
08158ee8ad Support (cross)compiling using MinGW-w64 2022-03-16 11:32:24 +00:00
Steffen Jaeckel
528c16e6c8 fix build with OpenSSL 1.1.0l
Debian 9.13 (stretch) brings this version and building failed there.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-09 16:48:07 +01:00
Steffen Jaeckel
870f2174d5 fix potential infinite looping of resolver
In case a pointer to itself was received, the resolver looped inifinitely
until the stack overflows.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-09 16:48:07 +01:00
Steffen Jaeckel
1406198087 add fuzzing of resolver
based on the "random test" at the end of the regular resolver tests.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-09 12:08:15 +01:00
Steffen Jaeckel
53373261ad fix example/perf.c compilation
In case this ifdef-elseif-chain falls back to the else path, the macro
to `clock()` wasn't defined.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-09 12:08:11 +01:00
Steffen Jaeckel
c1c697b177 show error-logs on failure
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-03-09 12:08:07 +01:00
Stu Tomlinson
808a981e86 Compile fix
examples/perf.c: In function ‘perf_rand’:
examples/perf.c:42:5: error: ‘for’ loop initial declarations are only allowed in C99 mode
     for (size_t sz = 2; sz <= alloc_sz; sz <<= 1) {
2022-03-02 11:25:44 +00:00
Stu Tomlinson
879f40a0ae Minor compile warning fix
src/handler.c: In function 'handler_system_delete_all':
src/handler.c:706:25: warning: 'key2' may be used uninitialized in this function [-Wmaybe-uninitialized]
                 hash_add(conn->id_handlers, key2, head);
2022-03-02 11:25:05 +00:00
Steffen Jaeckel
0365f03342 fix --help string
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-22 15:02:47 +01:00
Steffen Jaeckel
1e8dc3caa8 move common code to static function
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-22 14:58:44 +01:00
Steffen Jaeckel
e32d39dbc1 forgot to update tls_schannel.c with new API's
Fixup of
93e04b8d03
a97714da18

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-10 11:39:25 +01:00
Steffen Jaeckel
2bc34b5847 add new CI job that does a test-release
This also re-defines that `make release` does the release of all tarballs
and will run the tests against them.

Latest LibreSSL test is also marked non-essential, as it tends to fail
from time to time ...

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-10 11:29:57 +01:00
Steffen Jaeckel
4cf7805e9e update files included in a release
Removal of `rand.h` is a fixup of
118087f2a1

Somehow autotools manages to know that all those files must be
included in a release, no need to track them manually.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-10 11:21:43 +01:00
Steffen Jaeckel
a1206435eb add CI test-run with getrandom disabled
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
69550f9be9 allow reading arbitrary number of bytes from xmpp_rand_bytes()
If we expose the API it shouldn't be limited.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
9c7b8580d8 add examples/perf
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
ec5e942705 test against latest LibreSSL
... and test against latest patch of the minor versions we use to test

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
404464fd40 auto-format
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
619bcc38e9 make [v]snprintf() private
Fixes #189

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
728e050a05 make strtok_r private
Fixes #189

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
93e04b8d03 make logging functions private
Fixes #189

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
a97714da18 make alloc-class of functions private
Fixes #189

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-06 12:36:38 +01:00
Steffen Jaeckel
118087f2a1 make RNG API (officially) public
Fixes #189

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
3a3b4faa10 use getrandom() on recent linux distros
Instead of using the internal DRBG-based RNG, use the `getrandom()` system
call where available.
Keep the existing version as fall-back for other systems that don't provide
that system call.

... and for cases where auto-detection fails or the user simply wants to
use the internal RNG a new configure-switch is provided.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
2850fd7792 fix build with libressl
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
db91f793dc port travis CI to GitHub actions
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
3225bafd54 make basic example basic again
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
47f4d883c8 fix Doxygen warnings
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
d8d0e75466 improve OpenSSL error logging
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
e9d983dec2 update Doxyfile
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
f3878b954a use ascii chars
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
f693efd532 add some new make targets
* `release` creates the tarballs
* `test-release` takes the tarballs, extracts them, builds the library
  and tests and runs the tests
* `docs` run doxygen

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-02-04 13:36:17 +01:00
Steffen Jaeckel
6a052ed0fc add Issue template
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-01-31 16:51:19 +01:00
Steffen Jaeckel
edb54ebe90 introduce library versioning
This is done by loosely following the description on [1]
and other examples.

Fixes #190

[1] https://phab.enlightenment.org/w/autotoolsintegration/

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2022-01-31 16:51:01 +01:00
Steffen Jaeckel
28f3ce19b8 add xmpp_stanza_get_child_by_path()
... to provide an easier way to find long paths.

After looking at some code in profanity-im/profanity#1605 I thought this
could help to make libstrophe-user code easier to write (and read).

Initially it started off as `xmpp_stanza_get_child_by_xpath()` but then
I was annoyed when it came to handling all those potential corner cases
like e.g. escaping URL's in the ns ... so here we go with a
vararg approach :)

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-12-03 15:17:54 +01:00
Steffen Jaeckel
b0631e322f use lower-case labels
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-12-03 12:04:29 +01:00
Steffen Jaeckel
c3c28cb4c1 add code coverage support
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-12-03 12:04:29 +01:00
Steffen Jaeckel
ae5484ebd5 handler: refactor some copy-pasta
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-12-03 12:04:29 +01:00
Steffen Jaeckel
01f2c3128a handler: no need to dup string
`hash_iter_next()` returns a pointer to an element of the data structure
which is persistent and not altered while calling `hash_iter_next()`.
Therefor we don't have to dup the string, but simply can remember the
pointer.
In the case where the element would be `hash_drop()`'ped which contains
the key, the key is not accessed after it has been free'd.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-12-03 12:04:29 +01:00
Dmitry Podgorny
07a4f778d3 ctx: initialize field 'verbosity'
Uninitialized field can contain a garbage and break expected logs
behavior.
2021-12-02 00:08:34 +02:00
Dmitry Podgorny
44a5556278 .gitignore: ignore tar.bz2 and tar.xz packages 2021-11-25 19:34:39 +02:00
Dmitry Podgorny
b3e355736f event: move xmpp_ctx_set_timeout() to the Event loop module
xmpp_ctx_set_timeout() belongs to the event loop. Move it to provide
better doxygen documentation.
2021-11-25 19:29:07 +02:00
Dmitry Podgorny
058576e768 autotools: add key.pem and cert.pem to EXTRA_DIST 2021-10-28 22:09:42 +03:00
64 changed files with 5005 additions and 1514 deletions

49
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,49 @@
<!--
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.
-->

120
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,120 @@
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
libressl-tests:
runs-on: ubuntu-20.04
strategy:
matrix:
libressl_versions:
- { version: "v3.4.2", continue: true }
- { version: "v3.1.5", continue: false }
- { version: "v2.1.10", continue: false }
valgrind:
- { configure: '' , make: 'check' }
- { configure: '--enable-valgrind' , make: 'check-valgrind' }
name: LibreSSL tests
continue-on-error: ${{ matrix.libressl_versions.continue }}
steps:
- uses: actions/checkout@v2
- name: install dependencies
run: |
sudo apt update
sudo apt install -y libtool pkg-config libexpat1-dev valgrind
- name: build&install libressl
env:
LIBRESSL_COMMIT: ${{ matrix.libressl_versions.version }}
run: |
./travis/before_script.sh
- name: Build the library
run: |
./bootstrap.sh
./configure ${{ matrix.valgrind.configure }} PKG_CONFIG_PATH="${HOME}/libressl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/libressl"
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,6 +20,8 @@ autom4te.cache
.dirstamp
.deps
.sconsign*
src/*.gcda
src/*.gcno
src/*.o
src/*.lo
examples/*.o
@@ -27,6 +29,8 @@ examples/*.o
*.la
*.pc
*.tar.gz
*.tar.bz2
*.tar.xz
*.zip
docs/html
TAGS
@@ -34,19 +38,25 @@ tags
examples/active
examples/basic
examples/bot
examples/complex
examples/component
examples/perf
examples/register
examples/roster
examples/uuid
examples/vcard
testbuild*.log
test-release/
test_stamp
test-suite.log
test-suite*.log
tests/*.o
tests/*.log
tests/*.trs
tests/check_parser
tests/test_base64
tests/test_ctx
tests/test_fuzz_parser
tests/test_fuzz_resolver
tests/test_hash
tests/test_jid
tests/test_md5
@@ -54,6 +64,7 @@ tests/test_rand
tests/test_resolver
tests/test_sasl
tests/test_scram
tests/test_send_queue
tests/test_sha1
tests/test_sha256
tests/test_sha512
@@ -62,7 +73,8 @@ tests/test_sock
tests/test_stanza
tests/test_string
tests/test_xmppaddr
m4/
m4/lt*
m4/libtool*
libstrophe.project
libs/
obj/
@@ -70,3 +82,7 @@ expat/
.settings/
.project
.cproject
coverage/
coverage.info
configure~
fuzz-*.log

View File

@@ -1,26 +0,0 @@
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,3 +1,48 @@
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
- SASL EXTERNAL support (XEP-0178)
- Client certificate can be provided for TLS negotiation. If the

929
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,11 @@ AUTOMAKE_OPTIONS = subdir-objects
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_LIBS=@PARSER_LIBS@
@@ -13,26 +18,29 @@ SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@
endif
MINGW_LIBS = @MINGW_LIBS@
RESOLV_CFLAGS = @RESOLV_CFLAGS@
RESOLV_LIBS = @RESOLV_LIBS@
WARNING_FLAGS = @WARNING_FLAGS@
STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS)
STROPHE_LIBS = libstrophe.la
STROPHE_LIBS = $(COVERAGE_PRE) libstrophe.la $(COVERAGE_POST) $(COVERAGE_LDFLAGS)
## Main build targets
lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) -no-undefined
# Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@
libstrophe_la_SOURCES = \
src/auth.c \
src/conn.c \
src/crypto.c \
src/ctx.c \
src/deprecated.c \
src/event.c \
src/handler.c \
src/hash.c \
@@ -45,7 +53,6 @@ libstrophe_la_SOURCES = \
src/sha1.c \
src/sha256.c \
src/sha512.c \
src/snprintf.c \
src/sock.c \
src/stanza.c \
src/tls.c \
@@ -57,7 +64,6 @@ libstrophe_la_SOURCES += \
src/md5.h \
src/ostypes.h \
src/parser.h \
src/rand.h \
src/resolver.h \
src/sasl.h \
src/scram.h \
@@ -70,6 +76,10 @@ libstrophe_la_SOURCES += \
src/tls.h \
src/util.h
if NEED_SNPRINTF
libstrophe_la_SOURCES += src/snprintf.c
endif
if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c
else
@@ -98,28 +108,32 @@ EXTRA_DIST = \
MIT-LICENSE.txt \
bootstrap.sh \
build-android.sh \
testbuild.sh \
examples/README.md \
jni/Android.mk \
jni/Application.mk \
m4/ax_valgrind_check.m4 \
src/tls_schannel.c \
tests/cert.pem \
tests/cert.pfx \
tests/cert.emptypass.pfx \
tests/cert.nopass.pfx \
tests/key.pem \
tests/key_encrypted.pem \
tests/res_query_dump.c
if TLS_WITH_GNUTLS
EXTRA_DIST += src/tls_openssl.c
else
EXTRA_DIST += src/tls_gnutls.c
endif
## Examples
noinst_PROGRAMS = \
examples/active \
examples/basic \
examples/bot \
examples/complex \
examples/component \
examples/perf \
examples/register \
examples/roster \
examples/uuid \
examples/vcard \
examples/register
examples/vcard
examples_active_SOURCES = examples/active.c
examples_active_CFLAGS = $(STROPHE_FLAGS)
@@ -130,9 +144,18 @@ examples_basic_LDADD = $(STROPHE_LIBS)
examples_bot_SOURCES = examples/bot.c
examples_bot_CFLAGS = $(STROPHE_FLAGS)
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_CFLAGS = $(STROPHE_FLAGS)
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_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS)
@@ -142,9 +165,6 @@ examples_uuid_LDADD = $(STROPHE_LIBS)
examples_vcard_SOURCES = examples/vcard.c
examples_vcard_CFLAGS = $(STROPHE_FLAGS)
examples_vcard_LDADD = $(STROPHE_LIBS)
examples_register_SOURCES = examples/register.c
examples_register_CFLAGS = $(STROPHE_FLAGS)
examples_register_LDADD = $(STROPHE_LIBS)
## Tests
@@ -160,6 +180,7 @@ TESTS = \
tests/test_base64 \
tests/test_hash \
tests/test_jid \
tests/test_send_queue \
tests/test_snprintf \
tests/test_string \
tests/test_stanza \
@@ -172,13 +193,19 @@ endif
check_PROGRAMS = $(TESTS)
if FUZZ
check_PROGRAMS += tests/test_fuzz
check_PROGRAMS += tests/test_fuzz_parser tests/test_fuzz_resolver
tests_test_fuzz_SOURCES = tests/test_fuzz.c
tests_test_fuzz_CFLAGS = -fsanitize=fuzzer,address $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
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_LDADD = $(STROPHE_LIBS)
tests_test_fuzz_LDFLAGS = -static
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
@@ -231,6 +258,11 @@ 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_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_CFLAGS = -I$(top_srcdir)/src
@@ -251,5 +283,43 @@ tests_test_xmppaddr_LDFLAGS = -static
format:
@echo " * run clang-format on all sources"
@dos2unix -q src/*.[ch] *.h tests/*.[ch] examples/*.c
@clang-format -i src/*.[ch] *.h tests/*.[ch] examples/*.c
@dos2unix -k -q $(top_srcdir)/src/*.[ch] $(top_srcdir)/*.h $(top_srcdir)/tests/*.[ch] $(top_srcdir)/examples/*.c
@clang-format -i $(top_srcdir)/src/*.[ch] $(top_srcdir)/*.h $(top_srcdir)/tests/*.[ch] $(top_srcdir)/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:
@doxygen -q
@VALGRIND_CHECK_RULES@
.PHONY: docs test-release

View File

@@ -42,17 +42,30 @@ another path use the `--prefix` option during configure, e.g.:
Run script `build-android.sh` and follow the instructions. You will
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
------------
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
- openssl on UNIX systems
- openssl or GnuTLS on UNIX systems - openssl is default; use
`--with-gnutls` to switch
To build libstrophe using autotools you will need autoconf, automake,
libtool and pkg-config.
To build libstrophe using autotools you will need `autoconf`,
`automake`, `libtool` and `pkg-config`.
To run code coverage analysis you will need `gcov` and `lcov`.
Installation
------------

View File

@@ -1,4 +1,13 @@
AC_INIT([libstrophe], [0.11.0], [jack@metajack.im])
m4_define([v_maj], [0])
m4_define([v_min], [12])
m4_define([v_patch], [0])
m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min))
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])
AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen])
@@ -16,6 +25,8 @@ AS_CASE([$host_os],
[*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"],
[*haiku*], [PLATFORM="haiku"],
[*mingw*], [PLATFORM="win32"
MINGW_LIBS="-lws2_32"],
[PLATFORM="nix"])
WARNING_FLAGS="-Wall"
@@ -32,6 +43,8 @@ AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])])
AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([getrandom],
[AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])])
AC_ARG_ENABLE([fuzzing],
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
@@ -44,8 +57,31 @@ if test "x$enable_fuzzing" = "xyes" ; then
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_CHECK_FUNCS([snprintf vsnprintf])
AC_CHECK_FUNCS([snprintf vsnprintf], [], [have_snprintf=no])
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
@@ -70,6 +106,12 @@ elif test "x$enable_tls" != xno; then
)])
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=""
if test "x$with_libxml2" != xyes; then
PKG_CHECK_MODULES([expat], [expat >= 2.0.0],
@@ -136,8 +178,10 @@ AS_CASE([$PLATFORM],
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
[android], [RESOLV_LIBS=""],
[haiku], [RESOLV_LIBS="-lnetwork"],
[win32], [RESOLV_LIBS=""],
[RESOLV_LIBS="-lresolv"])
if test "x$PLATFORM" != xwin32; then
LIBS_TMP="${LIBS}"
LIBS="${RESOLV_LIBS}"
AC_LINK_IFELSE([AC_LANG_SOURCE([
@@ -156,6 +200,7 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
[AC_MSG_ERROR([res_query() not found with LIBS="${LIBS}"])])
LIBS="${LIBS_TMP}"
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
fi
fi
@@ -168,12 +213,33 @@ m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
AM_CONDITIONAL([PARSER_EXPAT], [test x$with_parser != xlibxml2])
AM_CONDITIONAL([DISABLE_TLS], [test x$enable_tls = xno])
AM_CONDITIONAL([NEED_SNPRINTF], [test x$have_snprintf = xno])
AM_CONDITIONAL([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
# 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_CFLAGS], [${PC_CFLAGS}])
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_LIBS)
AC_SUBST(RESOLV_CFLAGS)

View File

@@ -15,24 +15,6 @@
#include <strophe.h>
/* hardcoded TCP keepalive timeout and interval */
#define KA_TIMEOUT 60
#define KA_INTERVAL 1
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,
@@ -41,21 +23,12 @@ static void conn_handler(xmpp_conn_t *conn,
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");
@@ -63,23 +36,6 @@ static void conn_handler(xmpp_conn_t *conn,
}
}
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';
}
static void usage(int exit_code)
{
fprintf(stderr,
@@ -87,20 +43,11 @@ static void usage(int exit_code)
"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"
" --capath <path> Path to an additional CA trust store "
"(directory).\n"
" --cafile <path> Path to an additional CA trust store "
"(single file).\n"
" --tls-key <key> Path to private key.\n\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");
@@ -112,10 +59,8 @@ 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;
char *jid = NULL, *password = NULL, *host = NULL;
long flags = 0;
int tcp_keepalive = 0, verbosity = 0, certfail = 0;
int i;
unsigned long port = 0;
@@ -133,28 +78,14 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
else if (strcmp(argv[i], "--legacy-auth") == 0)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--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 && (!cert || !key)) || (argc - i) > 2) {
if ((!jid) || (argc - i) > 2) {
usage(1);
}
@@ -175,33 +106,19 @@ int main(int argc, char **argv)
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_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
/* setup authentication information */
if (cert && 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) {

View File

@@ -19,9 +19,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <strophe.h>
static int reconnect;
int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *reply, *query, *name, *version, *text;
@@ -95,6 +98,10 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
if (strcmp(intext, "quit") == 0) {
replytext = strdup("bye!");
quit = 1;
} else if (strcmp(intext, "reconnect") == 0) {
replytext = strdup("alright, let's see what happens!");
reconnect = 1;
quit = 1;
} else {
replytext = (char *)malloc(strlen(" to you too!") + strlen(intext) + 1);
strcpy(replytext, intext);
@@ -142,21 +149,94 @@ void conn_handler(xmpp_conn_t *conn,
}
}
static int
password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
printf("Trying to unlock %s\n", xmpp_conn_get_keyfile(conn));
char *pass = getpass("Please enter password: ");
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)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char *jid, *pass;
xmpp_sm_state_t *sm_state = NULL;
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 */
if (argc != 3) {
fprintf(stderr, "Usage: bot <jid> <pass>\n\n");
return 1;
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], "--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);
}
jid = argv[1];
pass = argv[2];
if (i < argc)
host = argv[i];
if (i + 1 < argc)
port = strtoul(argv[i + 1], NULL, 0);
/* init library */
xmpp_initialize();
@@ -166,29 +246,55 @@ int main(int argc, char **argv)
/* create a context */
ctx = xmpp_ctx_new(NULL, log);
create_connection:
reconnect = 0;
/* create a connection */
conn = xmpp_conn_new(ctx);
/*
* also you can disable TLS support or force legacy SSL
* connection without STARTTLS
*
* see xmpp_conn_set_flags() or examples/basic.c
*/
/* configure connection properties (optional) */
xmpp_conn_set_flags(conn, flags);
/* 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 */
xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass);
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);
/* 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 */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);
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);
/* enter the event loop -
our connect handler will trigger an exit */
xmpp_run(ctx);
}
/* release our connection and context */
/* save the Stream-Mangement state if we should re-connect */
if (reconnect)
sm_state = xmpp_conn_get_sm_state(conn);
/* release our connection */
xmpp_conn_release(conn);
if (reconnect)
goto create_connection;
/* release our context */
xmpp_ctx_free(ctx);
/* final shutdown of the library */

340
examples/complex.c Normal file
View File

@@ -0,0 +1,340 @@
/* 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 <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';
}
static int
password_callback(char *pw, size_t pw_max, xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
printf("Trying to unlock %s\n", xmpp_conn_get_keyfile(conn));
char *pass = getpass("Please enter password: ");
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;
}

164
examples/perf.c Normal file
View File

@@ -0,0 +1,164 @@
/* 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);
}

239
m4/ax_valgrind_check.m4 Normal file
View File

@@ -0,0 +1,239 @@
# ===========================================================================
# 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])])
])

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,6 @@
#include "hash.h"
#include "util.h"
#include "parser.h"
#include "rand.h"
#include "snprintf.h"
/** handlers **/
@@ -88,25 +87,38 @@ struct _xmpp_ctx_t {
};
/* convenience functions for accessing the context */
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s);
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
void xmpp_log(const xmpp_ctx_t *ctx,
const xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap);
void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size);
void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s);
char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
void strophe_free(const xmpp_ctx_t *ctx, void *p);
/* 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, ...);
void xmpp_debug_verbose(
void strophe_error(const xmpp_ctx_t *ctx,
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 *fmt,
va_list ap);
/** connection **/
/* opaque connection object */
@@ -116,13 +128,24 @@ typedef enum {
XMPP_STATE_CONNECTED
} 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;
struct _xmpp_send_queue_t {
char *data;
size_t len;
size_t written;
int wip;
xmpp_send_queue_owner_t owner;
void *userdata;
uint32_t sm_h;
xmpp_send_queue_t *next;
xmpp_send_queue_t *prev, *next;
};
#define UNUSED(x) ((void)(x))
@@ -148,6 +171,22 @@ enum {
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 {
unsigned int ref;
xmpp_ctx_t *ctx;
@@ -162,6 +201,7 @@ struct _xmpp_conn_t {
sock_t sock;
int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */
int ka_count; /* TCP keepalive count */
tls_t *tls;
int tls_support;
@@ -179,10 +219,20 @@ struct _xmpp_conn_t {
int auth_legacy_enabled;
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 */
int bind_required;
int session_required;
int sm_disable;
xmpp_sm_state_t *sm_state;
char *lang;
char *domain;
@@ -195,6 +245,7 @@ struct _xmpp_conn_t {
int blocking_send;
int send_queue_max;
int send_queue_len;
int send_queue_user_len;
xmpp_send_queue_t *send_queue_head;
xmpp_send_queue_t *send_queue_tail;
@@ -221,6 +272,7 @@ struct _xmpp_conn_t {
xmpp_handlist_t *timed_handlers;
hash_t *id_handlers;
xmpp_handlist_t *handlers;
xmpp_sockopt_callback sockopt_cb;
};
void conn_disconnect(xmpp_conn_t *conn);
@@ -282,4 +334,23 @@ void auth_handle_component_open(xmpp_conn_t *conn);
void auth_handle_open_raw(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__ */

File diff suppressed because it is too large Load Diff

View File

@@ -22,11 +22,11 @@
#include <assert.h>
#include <string.h> /* memset, memcpy */
#include "common.h" /* xmpp_alloc */
#include "common.h" /* strophe_alloc */
#include "ostypes.h" /* uint8_t, size_t */
#include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */
#include "strophe.h" /* xmpp_ctx_t, xmpp_free */
#include "strophe.h" /* xmpp_ctx_t, strophe_free */
struct _xmpp_sha1_t {
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;
for (i = 0; i < SHA1_DIGEST_SIZE; ++i)
xmpp_snprintf(s + i * 2, 3, "%02x", digest[i]);
strophe_snprintf(s + i * 2, 3, "%02x", digest[i]);
return s;
}
@@ -53,7 +53,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
size_t slen;
slen = SHA1_DIGEST_SIZE * 2 + 1;
s = xmpp_alloc(ctx, slen);
s = strophe_alloc(ctx, slen);
if (s) {
s = digest_to_string(digest, s, slen);
assert(s != NULL);
@@ -122,7 +122,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
{
xmpp_sha1_t *sha1;
sha1 = xmpp_alloc(ctx, sizeof(*sha1));
sha1 = strophe_alloc(ctx, sizeof(*sha1));
if (sha1) {
memset(sha1, 0, sizeof(*sha1));
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)
{
xmpp_free(sha1->xmpp_ctx, sha1);
strophe_free(sha1->xmpp_ctx, sha1);
}
/** 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.
* Returns an allocated string. Free the string using the Strophe context
* which is passed to xmpp_sha1_new(). Call this function after
* xmpp_sha1_final().
* Returns an allocated string. Free the string by calling xmpp_free() using
* the Strophe context which is passed to xmpp_sha1_new(). Call this function
* after xmpp_sha1_final().
*
* @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;
clen = base64_encoded_len(len);
cbuf = xmpp_alloc(ctx, clen + 1);
cbuf = strophe_alloc(ctx, clen + 1);
if (cbuf != NULL) {
c = cbuf;
/* 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)
goto _base64_error;
dbuf = xmpp_alloc(ctx, dlen + 1);
dbuf = strophe_alloc(ctx, dlen + 1);
if (dbuf != NULL) {
d = dbuf;
/* 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:
/* invalid character; abort decoding! */
xmpp_free(ctx, dbuf);
strophe_free(ctx, dbuf);
_base64_error:
*out = NULL;
*outlen = 0;
@@ -469,7 +469,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
if (len == 0) {
/* handle empty string */
buf = xmpp_alloc(ctx, 1);
buf = strophe_alloc(ctx, 1);
if (buf)
buf[0] = '\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 (buflen != strlen((char *)buf)) {
xmpp_free(ctx, buf);
strophe_free(ctx, buf);
buf = NULL;
}
}

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
*/
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size)
{
return ctx->mem->alloc(size, ctx->mem->userdata);
}
@@ -222,11 +222,21 @@ void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
* @param ctx a Strophe context object
* @param p a pointer referencing memory to be freed
*/
void xmpp_free(const xmpp_ctx_t *ctx, void *p)
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)
{
strophe_free(ctx, p);
}
/** Reallocate memory in a Strophe context.
* All Strophe functions will use this to reallocate memory.
*
@@ -236,7 +246,7 @@ void xmpp_free(const xmpp_ctx_t *ctx, void *p)
*
* @return a pointer to the reallocated memory or NULL on an error
*/
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
{
return ctx->mem->realloc(p, size, ctx->mem->userdata);
}
@@ -245,8 +255,8 @@ void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
* 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
* variable argument list (in va_list) format. This function is not meant
* to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
* and xmpp_debug.
* to be called directly, but is used via strophe_error, strophe_warn,
* strophe_info, and strophe_debug.
*
* @param ctx a Strophe context object
* @param level the level at which to log
@@ -254,11 +264,11 @@ void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
* @param fmt a printf-style format string for the message
* @param ap variable argument list supplied for the format string
*/
void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap)
static void _strophe_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap)
{
int oldret, ret;
char smbuf[1024];
@@ -273,20 +283,21 @@ void xmpp_log(const xmpp_ctx_t *ctx,
return;
va_copy(copy, ap);
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
ret = strophe_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
if (ret >= (int)sizeof(smbuf)) {
buf = (char *)xmpp_alloc(ctx, ret + 1);
buf = (char *)strophe_alloc(ctx, ret + 1);
if (!buf) {
buf = NULL;
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
strophe_error(ctx, "log",
"Failed allocating memory for log message.");
va_end(copy);
return;
}
oldret = ret;
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
ret = strophe_vsnprintf(buf, ret + 1, fmt, copy);
if (ret > oldret) {
xmpp_error(ctx, "log", "Unexpected error");
xmpp_free(ctx, buf);
strophe_error(ctx, "log", "Unexpected error");
strophe_free(ctx, buf);
va_end(copy);
return;
}
@@ -298,7 +309,17 @@ void xmpp_log(const xmpp_ctx_t *ctx,
ctx->log->handler(ctx->log->userdata, level, area, buf);
if (buf != smbuf)
xmpp_free(ctx, buf);
strophe_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.
@@ -311,12 +332,15 @@ void xmpp_log(const xmpp_ctx_t *ctx,
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
void strophe_error(const xmpp_ctx_t *ctx,
const char *area,
const char *fmt,
...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
_strophe_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
va_end(ap);
}
@@ -330,12 +354,12 @@ void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
void strophe_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
_strophe_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
va_end(ap);
}
@@ -349,12 +373,12 @@ void xmpp_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
* arguments to format
*/
void xmpp_info(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, ...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
_strophe_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
va_end(ap);
}
@@ -368,12 +392,15 @@ void xmpp_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
* arguments to format
*/
void xmpp_debug(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,
...)
{
va_list ap;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
_strophe_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
@@ -388,7 +415,7 @@ void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_debug_verbose(
void strophe_debug_verbose(
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
@@ -397,7 +424,7 @@ void xmpp_debug_verbose(
return;
va_start(ap, fmt);
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
_strophe_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
va_end(ap);
}
@@ -440,8 +467,9 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
ctx->verbosity = 0;
if (ctx->rand == NULL) {
xmpp_free(ctx, ctx);
strophe_free(ctx, ctx);
ctx = NULL;
}
}
@@ -459,19 +487,7 @@ void xmpp_ctx_free(xmpp_ctx_t *ctx)
{
/* mem and log are owned by their suppliers */
xmpp_rand_free(ctx, ctx->rand);
xmpp_free(ctx, ctx); /* pull the hole in after us */
}
/** 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 Context
*/
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout)
{
ctx->timeout = timeout;
strophe_free(ctx, ctx); /* pull the hole in after us */
}
/** Set the verbosity level of a Strophe context.

256
src/deprecated.c Normal file
View File

@@ -0,0 +1,256 @@
/* 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,10 +107,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occurred */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
strophe_debug(ctx, "xmpp",
"Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
goto NEXT_ITEM;
goto next_item;
}
}
@@ -130,18 +131,32 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
}
if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */
sq->wip = 1;
if (ret != towrite)
break; /* partial write or an error */
/* all data for this queue item written, delete and move on */
xmpp_debug(conn->ctx, "conn", "SENT: %s", sq->data);
xmpp_debug_verbose(1, ctx, "xmpp",
"Finished writing queue element: %p.", sq);
xmpp_free(ctx, sq->data);
strophe_debug(conn->ctx, "conn", "SENT: %s", sq->data);
strophe_debug_verbose(1, ctx, "xmpp", "Q_SENT: %p", sq);
tsq = sq;
sq = sq->next;
conn->send_queue_len--;
xmpp_free(ctx, tsq);
if (tsq->owner & XMPP_QUEUE_USER)
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 */
conn->send_queue_head = sq;
@@ -154,11 +169,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
if (conn->error) {
/* FIXME: need to tear down send queues and random other things
* maybe this should be abstracted */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
strophe_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn);
}
NEXT_ITEM:
next_item:
connitem = connitem->next;
}
@@ -195,7 +210,7 @@ NEXT_ITEM:
FD_SET(conn->sock, &wfds);
else {
conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
strophe_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn);
}
break;
@@ -232,8 +247,8 @@ NEXT_ITEM:
/* select errored */
if (ret < 0) {
if (!sock_is_recoverable(sock_error()))
xmpp_error(ctx, "xmpp", "event watcher internal error %d",
sock_error());
strophe_error(ctx, "xmpp", "event watcher internal error %d",
sock_error());
return;
}
@@ -255,13 +270,14 @@ NEXT_ITEM:
ret = sock_connect_error(conn->sock);
if (ret != 0) {
/* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
strophe_debug(ctx, "xmpp", "connection failed, error %d",
ret);
conn_disconnect(conn);
break;
}
conn->state = XMPP_STATE_CONNECTED;
xmpp_debug(ctx, "xmpp", "connection successful");
strophe_debug(ctx, "xmpp", "connection successful");
conn_established(conn);
}
@@ -279,23 +295,23 @@ NEXT_ITEM:
if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret);
if (!ret) {
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf);
strophe_debug(ctx, "xmpp", "parse error [%s]", buf);
xmpp_send_error(conn, XMPP_SE_INVALID_XML,
"parse error");
}
} else {
if (conn->tls) {
if (!tls_is_recoverable(tls_error(conn->tls))) {
xmpp_debug(ctx, "xmpp",
"Unrecoverable TLS error, %d.",
tls_error(conn->tls));
strophe_debug(ctx, "xmpp",
"Unrecoverable TLS error, %d.",
tls_error(conn->tls));
conn->error = tls_error(conn->tls);
conn_disconnect(conn);
}
} else {
/* return of 0 means socket closed by server */
xmpp_debug(ctx, "xmpp",
"Socket closed by remote host.");
strophe_debug(ctx, "xmpp",
"Socket closed by remote host.");
conn->error = ECONNRESET;
conn_disconnect(conn);
}
@@ -337,7 +353,7 @@ void xmpp_run(xmpp_ctx_t *ctx)
/* make it possible to start event loop again */
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
xmpp_debug(ctx, "event", "Event loop completed.");
strophe_debug(ctx, "event", "Event loop completed.");
}
/** Stop the event loop.
@@ -350,8 +366,20 @@ void xmpp_run(xmpp_ctx_t *ctx)
*/
void xmpp_stop(xmpp_ctx_t *ctx)
{
xmpp_debug(ctx, "event", "Stopping event loop.");
strophe_debug(ctx, "event", "Stopping event loop.");
if (ctx->loop_status == XMPP_LOOP_RUNNING)
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,6 +46,17 @@ 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.
* This function is called internally by the event loop whenever stanzas
* are received from the XMPP server.
@@ -87,8 +98,8 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
/* replace old value */
hash_add(conn->id_handlers, id, head);
}
xmpp_free(conn->ctx, item->u.id);
xmpp_free(conn->ctx, item);
strophe_free(conn->ctx, item->u.id);
strophe_free(conn->ctx, item);
}
item = next;
}
@@ -124,13 +135,7 @@ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
if (!ret) {
/* handler is one-shot, so delete it */
_handler_item_remove(&conn->handlers, 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);
_free_handlist_item(conn->ctx, item);
}
}
item = next;
@@ -189,7 +194,7 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(ctx, item);
strophe_free(ctx, item);
}
} else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed;
@@ -220,7 +225,7 @@ uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&ctx->timed_handlers, item);
xmpp_free(ctx, item);
strophe_free(ctx, item);
}
} else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed;
@@ -262,7 +267,7 @@ static void _timed_handler_add(xmpp_ctx_t *ctx,
/* check if handler is already in the list */
for (item = *handlers_list; item; item = item->next) {
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(ctx, "xmpp", "Timed handler already exists.");
strophe_warn(ctx, "xmpp", "Timed handler already exists.");
break;
}
}
@@ -270,7 +275,7 @@ static void _timed_handler_add(xmpp_ctx_t *ctx,
return;
/* build new item */
item = xmpp_alloc(ctx, sizeof(xmpp_handlist_t));
item = strophe_alloc(ctx, sizeof(xmpp_handlist_t));
if (!item)
return;
@@ -297,7 +302,7 @@ static void _timed_handler_delete(xmpp_ctx_t *ctx,
item = *handlers_list;
if (item->handler == handler) {
*handlers_list = item->next;
xmpp_free(ctx, item);
strophe_free(ctx, item);
} else {
handlers_list = &item->next;
}
@@ -328,7 +333,7 @@ static void _id_handler_add(xmpp_conn_t *conn,
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) {
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
strophe_warn(conn->ctx, "xmpp", "Id handler already exists.");
break;
}
item = item->next;
@@ -337,7 +342,7 @@ static void _id_handler_add(xmpp_conn_t *conn,
return;
/* build new item */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
item = strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item)
return;
@@ -347,9 +352,9 @@ static void _id_handler_add(xmpp_conn_t *conn,
item->enabled = 0;
item->next = NULL;
item->u.id = xmpp_strdup(conn->ctx, id);
item->u.id = strophe_strdup(conn->ctx, id);
if (!item->u.id) {
xmpp_free(conn->ctx, item);
strophe_free(conn->ctx, item);
return;
}
@@ -394,8 +399,8 @@ void xmpp_id_handler_delete(xmpp_conn_t *conn,
hash_add(conn->id_handlers, id, next);
}
xmpp_free(conn->ctx, item->u.id);
xmpp_free(conn->ctx, item);
strophe_free(conn->ctx, item->u.id);
strophe_free(conn->ctx, item);
item = next;
} else {
prev = item;
@@ -404,6 +409,16 @@ 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 */
static void _handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
@@ -420,7 +435,7 @@ static void _handler_add(xmpp_conn_t *conn,
/* same handler function can process different stanzas and
distinguish them according to userdata. */
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
strophe_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
break;
}
}
@@ -428,47 +443,21 @@ static void _handler_add(xmpp_conn_t *conn,
return;
/* build new item */
item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
item = (xmpp_handlist_t *)strophe_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item)
return;
memset(item, 0, sizeof(*item));
item->user_handler = user_handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
if (ns) {
item->u.ns = xmpp_strdup(conn->ctx, ns);
if (!item->u.ns) {
xmpp_free(conn->ctx, item);
return;
}
} 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;
if (_dup_string(conn->ctx, ns, &item->u.ns))
goto error_out;
if (_dup_string(conn->ctx, name, &item->u.name))
goto error_out;
if (_dup_string(conn->ctx, type, &item->u.type))
goto error_out;
/* append to list */
if (!conn->handlers)
@@ -479,6 +468,11 @@ static void _handler_add(xmpp_conn_t *conn,
tail = tail->next;
tail->next = item;
}
return;
error_out:
_free_handlist_item(conn->ctx, item);
}
/** Delete a stanza handler.
@@ -504,13 +498,7 @@ void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler)
else
conn->handlers = item->next;
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);
_free_handlist_item(conn->ctx, item);
item = prev ? prev->next : conn->handlers;
} else {
prev = item;
@@ -665,8 +653,7 @@ void handler_system_delete_all(xmpp_conn_t *conn)
{
xmpp_handlist_t *item, *next, *head, *head_old;
hash_iterator_t *iter;
const char *key;
char *key2 = NULL;
const char *key, *key2;
/* TODO unify all kinds of handlers and avoid copy-paste below */
@@ -675,13 +662,7 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->handlers, 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);
_free_handlist_item(conn->ctx, item);
item = next;
} else
item = item->next;
@@ -692,7 +673,7 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(conn->ctx, item);
strophe_free(conn->ctx, item);
item = next;
} else
item = item->next;
@@ -707,26 +688,24 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&head, item);
xmpp_free(conn->ctx, item->u.id);
xmpp_free(conn->ctx, item);
strophe_free(conn->ctx, item->u.id);
strophe_free(conn->ctx, item);
item = next;
} else
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
key before dropping current one. Otherwise, we will get access to
freed memory. */
key = hash_iter_next(iter);
key2 = hash_iter_next(iter);
if (head != head_old) {
/* hash_add() replaces value if the key exists */
if (head != NULL)
hash_add(conn->id_handlers, key2, head);
hash_add(conn->id_handlers, key, head);
else
hash_drop(conn->id_handlers, key2);
xmpp_free(conn->ctx, key2);
hash_drop(conn->id_handlers, key);
}
key = key2;
}
if (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;
result = xmpp_alloc(ctx, sizeof(hash_t));
result = strophe_alloc(ctx, sizeof(hash_t));
if (result != NULL) {
result->entries = xmpp_alloc(ctx, size * sizeof(hashentry_t *));
result->entries = strophe_alloc(ctx, size * sizeof(hashentry_t *));
if (result->entries == NULL) {
xmpp_free(ctx, result);
strophe_free(ctx, result);
return NULL;
}
memset(result->entries, 0, size * sizeof(hashentry_t *));
@@ -91,15 +91,15 @@ void hash_release(hash_t *table)
entry = table->entries[i];
while (entry != NULL) {
next = entry->next;
xmpp_free(ctx, entry->key);
strophe_free(ctx, entry->key);
if (table->free)
table->free(ctx, entry->value);
xmpp_free(ctx, entry);
strophe_free(ctx, entry);
entry = next;
}
}
xmpp_free(ctx, table->entries);
xmpp_free(ctx, table);
strophe_free(ctx, table->entries);
strophe_free(ctx, table);
}
}
@@ -153,12 +153,12 @@ int hash_add(hash_t *table, const char *key, void *data)
if (entry == NULL) {
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
entry = strophe_alloc(ctx, sizeof(hashentry_t));
if (!entry)
return -1;
entry->key = xmpp_strdup(ctx, key);
entry->key = strophe_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
strophe_free(ctx, entry);
return -1;
}
/* 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 */
if (!strcmp(key, entry->key)) {
/* match, remove the entry */
xmpp_free(ctx, entry->key);
strophe_free(ctx, entry->key);
if (table->free)
table->free(ctx, entry->value);
if (prev == NULL) {
@@ -206,7 +206,7 @@ int hash_drop(hash_t *table, const char *key)
} else {
prev->next = entry->next;
}
xmpp_free(ctx, entry);
strophe_free(ctx, entry);
table->num_keys--;
return 0;
}
@@ -228,7 +228,7 @@ hash_iterator_t *hash_iter_new(hash_t *table)
xmpp_ctx_t *ctx = table->ctx;
hash_iterator_t *iter;
iter = xmpp_alloc(ctx, sizeof(*iter));
iter = strophe_alloc(ctx, sizeof(*iter));
if (iter != NULL) {
iter->ref = 1;
iter->table = hash_clone(table);
@@ -248,7 +248,7 @@ void hash_iter_release(hash_iterator_t *iter)
if (iter->ref == 0) { // ref is unsigned!!!
hash_release(iter->table);
xmpp_free(ctx, iter);
strophe_free(ctx, iter);
}
}

View File

@@ -47,7 +47,7 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx,
len = nlen + dlen + rlen;
/* concat components */
result = xmpp_alloc(ctx, len + 1);
result = strophe_alloc(ctx, len + 1);
if (result != NULL) {
if (node != NULL) {
memcpy(result, node, nlen - 1);
@@ -77,7 +77,7 @@ char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid)
size_t len;
len = strcspn(jid, "/");
result = xmpp_alloc(ctx, len + 1);
result = strophe_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, jid, len);
result[len] = '\0';
@@ -101,7 +101,7 @@ char *xmpp_jid_node(xmpp_ctx_t *ctx, const char *jid)
c = strchr(jid, '@');
if (c != NULL) {
result = xmpp_alloc(ctx, (c - jid) + 1);
result = strophe_alloc(ctx, (c - jid) + 1);
if (result != NULL) {
memcpy(result, jid, (c - jid));
result[c - jid] = '\0';
@@ -133,7 +133,7 @@ char *xmpp_jid_domain(xmpp_ctx_t *ctx, const char *jid)
c++;
}
dlen = strcspn(c, "/"); /* do not include resource */
result = xmpp_alloc(ctx, dlen + 1);
result = strophe_alloc(ctx, dlen + 1);
if (result != NULL) {
memcpy(result, c, dlen);
result[dlen] = '\0';
@@ -155,5 +155,5 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid)
const char *c;
c = strchr(jid, '/');
return c != NULL ? xmpp_strdup(ctx, c + 1) : NULL;
return c != NULL ? strophe_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)
{
if (mem_ctx != NULL)
return xmpp_alloc(mem_ctx, size);
return strophe_alloc(mem_ctx, size);
else
return NULL;
}
@@ -68,7 +68,7 @@ static void *parser_mem_malloc(size_t size)
static void *parser_mem_realloc(void *ptr, size_t size)
{
if (mem_ctx != NULL)
return xmpp_realloc(mem_ctx, ptr, size);
return strophe_realloc(mem_ctx, ptr, size);
else
return NULL;
}
@@ -76,7 +76,7 @@ static void *parser_mem_realloc(void *ptr, size_t size)
static void parser_mem_free(void *ptr)
{
if (mem_ctx != NULL)
xmpp_free(mem_ctx, ptr);
strophe_free(mem_ctx, ptr);
}
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);
if (c == NULL)
return xmpp_strdup(ctx, nsname);
return strophe_strdup(ctx, nsname);
c++;
len = strlen(c);
result = xmpp_alloc(ctx, len + 1);
result = strophe_alloc(ctx, len + 1);
if (result != NULL) {
memcpy(result, c, len);
result[len] = '\0';
@@ -116,7 +116,7 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
c = strchr(nsname, namespace_sep);
if (c != NULL) {
result = xmpp_alloc(ctx, (c - nsname) + 1);
result = strophe_alloc(ctx, (c - nsname) + 1);
if (result != NULL) {
memcpy(result, nsname, (c - nsname));
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 */
attr = _xml_name(stanza->ctx, attrs[i]);
xmpp_stanza_set_attribute(stanza, attr, attrs[i + 1]);
xmpp_free(stanza->ctx, attr);
strophe_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_release(stanza);
}
xmpp_free(parser->ctx, parser->inner_text);
strophe_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_size = 0;
parser->inner_text_used = 0;
@@ -181,7 +181,8 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
if (!parser->stanza && parser->depth != 1) {
/* something terrible happened */
/* FIXME: shutdown disconnect */
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
strophe_error(parser->ctx, "parser",
"oops, where did our stanza go?");
} else {
child = xmpp_stanza_new(parser->ctx);
if (!child) {
@@ -202,9 +203,9 @@ _start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
}
if (ns)
xmpp_free(parser->ctx, ns);
strophe_free(parser->ctx, ns);
if (name)
xmpp_free(parser->ctx, name);
strophe_free(parser->ctx, name);
parser->depth++;
}
@@ -246,10 +247,10 @@ static void _characters(void *userdata, const XML_Char *s, int len)
if (parser->inner_text_used + len >= parser->inner_text_size) {
parser->inner_text_size =
parser->inner_text_used + len + 1 + INNER_TEXT_PADDING;
p = xmpp_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size);
p = strophe_realloc(parser->ctx, parser->inner_text,
parser->inner_text_size);
if (p == NULL) {
xmpp_free(parser->ctx, parser->inner_text);
strophe_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
parser->inner_text_used = 0;
parser->inner_text_size = 0;
@@ -270,7 +271,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
{
parser_t *parser;
parser = xmpp_alloc(ctx, sizeof(parser_t));
parser = strophe_alloc(ctx, sizeof(parser_t));
if (parser != NULL) {
parser->ctx = ctx;
parser->expat = NULL;
@@ -316,11 +317,11 @@ void parser_free(parser_t *parser)
}
if (parser->inner_text) {
xmpp_free(parser->ctx, parser->inner_text);
strophe_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
xmpp_free(parser->ctx, parser);
strophe_free(parser->ctx, parser);
}
/* shuts down and restarts XML parser. true on success */
@@ -349,7 +350,7 @@ int parser_reset(parser_t *parser)
}
if (parser->inner_text) {
xmpp_free(parser->ctx, parser->inner_text);
strophe_free(parser->ctx, parser->inner_text);
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 */
for (i = 0; i < nattrs * 5; i += 5) {
len = attrs[i + 4] - attrs[i + 3];
value = xmpp_alloc(stanza->ctx, len + 1);
value = strophe_alloc(stanza->ctx, len + 1);
if (value) {
memcpy(value, attrs[i + 3], len);
value[len] = '\0';
xmpp_stanza_set_attribute(stanza, (const char *)attrs[i], value);
xmpp_free(stanza->ctx, value);
strophe_free(stanza->ctx, value);
}
}
}
@@ -70,7 +70,7 @@ _convert_attrs(parser_t *parser, int nattrs, const xmlChar **attrs)
if (!attrs)
return NULL;
ret = xmpp_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *));
ret = strophe_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *));
if (!ret)
return NULL;
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;
len = attrs[i + 4] - attrs[i + 3];
value = xmpp_alloc(parser->ctx, len + 1);
value = strophe_alloc(parser->ctx, len + 1);
if (value) {
memcpy(value, attrs[i + 3], len);
value[len] = '\0';
ret[o] = xmpp_strdup(parser->ctx, (char *)attrs[i]);
ret[o] = strophe_strdup(parser->ctx, (char *)attrs[i]);
ret[o + 1] = value;
}
}
@@ -101,12 +101,12 @@ static void _free_cbattrs(parser_t *parser, char **attrs)
for (i = 0; attrs[i]; i += 2) {
if (attrs[i])
xmpp_free(parser->ctx, attrs[i]);
strophe_free(parser->ctx, attrs[i]);
if (attrs[i + 1])
xmpp_free(parser->ctx, attrs[i + 1]);
strophe_free(parser->ctx, attrs[i + 1]);
}
xmpp_free(parser->ctx, attrs);
strophe_free(parser->ctx, attrs);
}
static void _start_element(void *userdata,
@@ -140,7 +140,8 @@ static void _start_element(void *userdata,
if (!parser->stanza && parser->depth != 1) {
/* something terrible happened */
/* FIXME: we should probably trigger a disconnect */
xmpp_error(parser->ctx, "parser", "oops, where did our stanza go?");
strophe_error(parser->ctx, "parser",
"oops, where did our stanza go?");
} else if (!parser->stanza) {
/* starting a new toplevel stanza */
parser->stanza = xmpp_stanza_new(parser->ctx);
@@ -235,7 +236,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
{
parser_t *parser;
parser = xmpp_alloc(ctx, sizeof(parser_t));
parser = strophe_alloc(ctx, sizeof(parser_t));
if (parser != NULL) {
parser->ctx = ctx;
parser->xmlctx = NULL;
@@ -259,7 +260,7 @@ parser_t *parser_new(xmpp_ctx_t *ctx,
char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
{
return xmpp_strdup(ctx, nsname);
return strophe_strdup(ctx, nsname);
}
static void _free_parent_stanza(xmpp_stanza_t *stanza)
@@ -278,7 +279,7 @@ void parser_free(parser_t *parser)
xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
_free_parent_stanza(parser->stanza);
xmpp_free(parser->ctx, parser);
strophe_free(parser->ctx, parser);
}
/* shuts down and restarts XML parser. true on success */

View File

@@ -23,12 +23,20 @@
#include <string.h> /* memeset */
#include <time.h> /* clock, time */
#include "common.h" /* xmpp_alloc, xmpp_free */
#include "ostypes.h" /* uint8_t, uint32_t, size_t */
#include "sha1.h"
#include "snprintf.h" /* xmpp_snprintf */
#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 "rand.h" /* xmpp_rand_t */
#include "common.h" /* strophe_alloc, strophe_free */
#include "ostypes.h" /* uint8_t, uint32_t, size_t */
#ifndef USE_GETRANDOM
#include "sha1.h"
#define outlen SHA1_DIGEST_SIZE
#define seedlen (440 / 8)
@@ -261,7 +269,7 @@ static void xmpp_rand_reseed(xmpp_rand_t *rand)
xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
{
xmpp_rand_t *out = xmpp_alloc(ctx, sizeof(*out));
xmpp_rand_t *out = strophe_alloc(ctx, sizeof(*out));
if (out != NULL) {
memset(out, 0, sizeof(*out));
}
@@ -270,21 +278,72 @@ xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx)
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand)
{
xmpp_free(ctx, rand);
strophe_free(ctx, rand);
}
void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len)
{
int rc;
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
if (rc == RESEED_NEEDED) {
xmpp_rand_reseed(rand);
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output, len);
assert(rc == 0);
size_t gen, tot = 0;
while (tot < 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) {
xmpp_rand_reseed(rand);
rc = Hash_DRBG_Generate(&rand->ctx, (uint8_t *)output + tot, gen);
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 result;

View File

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

View File

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

View File

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

View File

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

View File

@@ -33,8 +33,7 @@
#include <fcntl.h>
#endif
#include "sock.h"
#include "snprintf.h"
#include "common.h"
void sock_initialize(void)
{
@@ -69,14 +68,14 @@ static int _in_progress(int error)
#endif
}
sock_t sock_connect(const char *host, unsigned short port)
sock_t sock_connect(xmpp_conn_t *conn, const char *host, unsigned short port)
{
sock_t sock;
char service[6];
struct addrinfo *res, *ainfo, hints;
int err;
xmpp_snprintf(service, 6, "%u", port);
strophe_snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
@@ -95,6 +94,14 @@ sock_t sock_connect(const char *host, unsigned short port)
if (sock < 0)
continue;
if (conn->sockopt_cb != NULL)
err = (conn->sockopt_cb)(conn, &sock);
if (err != 0) {
sock_close(sock);
continue;
}
err = sock_set_nonblocking(sock);
if (err == 0) {
err = connect(sock, ainfo->ai_addr, ainfo->ai_addrlen);
@@ -109,12 +116,17 @@ sock_t sock_connect(const char *host, unsigned short port)
return sock;
}
int sock_set_keepalive(sock_t sock, int timeout, int interval)
int sock_set_keepalive(sock_t sock,
int timeout,
int interval,
int count,
unsigned int user_timeout)
{
int ret;
int optval = (timeout && interval) ? 1 : 0;
/* This function doesn't change maximum number of keepalive probes */
UNUSED(count);
UNUSED(user_timeout);
#ifdef _WIN32
struct tcp_keepalive ka;
@@ -149,11 +161,57 @@ int sock_set_keepalive(sock_t sock, int timeout, int interval)
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;
}
/** 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)
{
#ifdef _WIN32

View File

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

View File

@@ -39,7 +39,7 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
stanza = strophe_alloc(ctx, sizeof(xmpp_stanza_t));
if (stanza != NULL) {
stanza->ref = 1;
stanza->ctx = ctx;
@@ -124,7 +124,7 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t *stanza)
copy->type = stanza->type;
if (stanza->data) {
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
copy->data = strophe_strdup(stanza->ctx, stanza->data);
if (!copy->data)
goto copy_error;
}
@@ -188,8 +188,8 @@ int xmpp_stanza_release(xmpp_stanza_t *stanza)
if (stanza->attributes)
hash_release(stanza->attributes);
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
xmpp_free(stanza->ctx, stanza);
strophe_free(stanza->ctx, stanza->data);
strophe_free(stanza->ctx, stanza);
released = 1;
}
@@ -263,7 +263,7 @@ static char *_escape_xml(xmpp_ctx_t *ctx, char *text)
len++;
}
}
if ((buf = xmpp_alloc(ctx, (len + 1) * sizeof(char))) == NULL)
if ((buf = strophe_alloc(ctx, (len + 1) * sizeof(char))) == NULL)
return NULL; /* Error */
dst = buf;
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);
if (tmp == NULL)
return XMPP_EMEM;
ret = xmpp_snprintf(ptr, left, "%s", tmp);
xmpp_free(stanza->ctx, tmp);
ret = strophe_snprintf(ptr, left, "%s", tmp);
strophe_free(stanza->ctx, tmp);
if (ret < 0)
return XMPP_EMEM;
_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;
/* write beginning of tag and attributes */
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
ret = strophe_snprintf(ptr, left, "<%s", stanza->data);
if (ret < 0)
return XMPP_EMEM;
_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);
return XMPP_EMEM;
}
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
xmpp_free(stanza->ctx, tmp);
ret = strophe_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
strophe_free(stanza->ctx, tmp);
if (ret < 0) {
hash_iter_release(iter);
return XMPP_EMEM;
@@ -387,7 +387,7 @@ _render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
if (!stanza->children) {
/* write end if singleton tag */
ret = xmpp_snprintf(ptr, left, "/>");
ret = strophe_snprintf(ptr, left, "/>");
if (ret < 0)
return XMPP_EMEM;
_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 */
/* write end of start tag */
ret = xmpp_snprintf(ptr, left, ">");
ret = strophe_snprintf(ptr, left, ">");
if (ret < 0)
return XMPP_EMEM;
_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 */
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
ret = strophe_snprintf(ptr, left, "</%s>", stanza->data);
if (ret < 0)
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 */
length = 1024;
buffer = xmpp_alloc(stanza->ctx, length);
buffer = strophe_alloc(stanza->ctx, length);
if (!buffer) {
*buf = NULL;
*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);
if (ret < 0) {
xmpp_free(stanza->ctx, buffer);
strophe_free(stanza->ctx, buffer);
*buf = NULL;
*buflen = 0;
return ret;
}
if ((size_t)ret > length - 1) {
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
tmp = strophe_realloc(stanza->ctx, buffer, ret + 1);
if (!tmp) {
xmpp_free(stanza->ctx, buffer);
strophe_free(stanza->ctx, buffer);
*buf = NULL;
*buflen = 0;
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);
if ((size_t)ret > length - 1) {
xmpp_free(stanza->ctx, buffer);
strophe_free(stanza->ctx, buffer);
*buf = NULL;
*buflen = 0;
return XMPP_EMEM;
@@ -506,10 +506,10 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *name)
return XMPP_EINVOP;
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
strophe_free(stanza->ctx, stanza->data);
stanza->type = XMPP_STANZA_TAG;
stanza->data = xmpp_strdup(stanza->ctx, name);
stanza->data = strophe_strdup(stanza->ctx, name);
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
}
@@ -615,19 +615,19 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t *stanza,
return XMPP_EINVOP;
if (!stanza->attributes) {
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
stanza->attributes = hash_new(stanza->ctx, 8, strophe_free);
if (!stanza->attributes)
return XMPP_EMEM;
}
val = xmpp_strdup(stanza->ctx, value);
val = strophe_strdup(stanza->ctx, value);
if (!val) {
return XMPP_EMEM;
}
rc = hash_add(stanza->attributes, key, val);
if (rc < 0) {
xmpp_free(stanza->ctx, val);
strophe_free(stanza->ctx, val);
return XMPP_EMEM;
}
@@ -728,8 +728,8 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *text)
stanza->type = XMPP_STANZA_TEXT;
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
stanza->data = xmpp_strdup(stanza->ctx, text);
strophe_free(stanza->ctx, stanza->data);
stanza->data = strophe_strdup(stanza->ctx, text);
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;
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
stanza->data = xmpp_alloc(stanza->ctx, size + 1);
strophe_free(stanza->ctx, stanza->data);
stanza->data = strophe_alloc(stanza->ctx, size + 1);
if (!stanza->data)
return XMPP_EMEM;
@@ -844,6 +844,82 @@ const char *xmpp_stanza_get_from(xmpp_stanza_t *stanza)
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.
* This function searches all the immediate children of stanza for a child
* stanza that matches the name. The first matching child is returned.
@@ -977,7 +1053,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t *stanza)
if (stanza->type == XMPP_STANZA_TEXT) {
if (stanza->data)
return xmpp_strdup(stanza->ctx, stanza->data);
return strophe_strdup(stanza->ctx, stanza->data);
else
return NULL;
}
@@ -990,7 +1066,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t *stanza)
if (len == 0)
return NULL;
text = (char *)xmpp_alloc(stanza->ctx, len + 1);
text = (char *)strophe_alloc(stanza->ctx, len + 1);
if (!text)
return NULL;
@@ -1137,8 +1213,8 @@ int xmpp_stanza_del_attribute(xmpp_stanza_t *stanza, const char *name)
}
/** Create a stanza object in reply to another.
* This function makes a copy of a stanza object with the attribute to set
* its original from.
* This function makes a copy of a stanza object with the attribute "to" set
* its original "from".
* The stanza will have a reference count of one, so the caller does not
* need to clone it.
*
@@ -1165,7 +1241,7 @@ xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t *stanza)
copy->type = stanza->type;
if (stanza->data) {
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
copy->data = strophe_strdup(stanza->ctx, stanza->data);
if (!copy->data)
goto copy_error;
}
@@ -1195,7 +1271,7 @@ copy_error:
* Check https://tools.ietf.org/html/rfc6120#section-8.3 for details.
*
* @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 text optional description, may be NULL
*
@@ -1310,7 +1386,7 @@ static xmpp_stanza_t *_stanza_new_with_attrs(xmpp_ctx_t *ctx,
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.
*
* @param ctx a Strophe context object
@@ -1330,13 +1406,13 @@ xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
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
* 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)
*
* @ingroup Stanza
@@ -1355,9 +1431,10 @@ char *xmpp_message_get_body(xmpp_stanza_t *msg)
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
* (XMPP_EMEM, XMPP_EINVOP)
@@ -1372,7 +1449,7 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text)
const char *name;
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);
body = xmpp_stanza_get_child_by_name(msg, "body");
if (!name || strcmp(name, "message") != 0 || body)
@@ -1399,7 +1476,7 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text)
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.
*
* @param ctx a Strophe context object
@@ -1415,7 +1492,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);
}
/** Create a <presence/> stanza object.
/** Create a `<presence/>` stanza object.
*
* @param ctx a Strophe context object
*
@@ -1432,7 +1509,7 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
* The error text is optional and may be NULL.
*
* @param ctx a Strophe context object
* @param type enum of xmpp_error_type_t
* @param type enum of strophe_error_type_t
* @param text content of a 'text'
*
* @return a new Strophe stanza object
@@ -1563,8 +1640,11 @@ static void _stub_stream_end(char *name, void *userdata)
static void _stream_stanza(xmpp_stanza_t *stanza, void *userdata)
{
stanza = xmpp_stanza_clone(stanza);
*(xmpp_stanza_t **)userdata = stanza;
xmpp_stanza_t **dest = userdata;
if (*dest == NULL) {
stanza = xmpp_stanza_clone(stanza);
*dest = stanza;
}
}
/** Create a stanza object from the string.

View File

@@ -103,7 +103,7 @@ 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)
{
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return cert->elements[elmnt];
}
@@ -112,7 +112,6 @@ const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
*
* c.f. \ref xmpp_cert_element_t for details.
*
* @param cert a Strophe TLS certificate object
* @param elmnt which element
*
* @return a string with the description
@@ -133,7 +132,7 @@ const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
"Fingerprint SHA-1",
"Fingerprint SHA-256",
};
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
if (elmnt < 0 || elmnt >= XMPP_CERT_ELEMENT_MAX)
return NULL;
return descriptions[elmnt];
}
@@ -146,14 +145,14 @@ const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
*/
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
{
xmpp_tlscert_t *tlscert = xmpp_alloc(ctx, sizeof(*tlscert));
xmpp_tlscert_t *tlscert = strophe_alloc(ctx, sizeof(*tlscert));
if (!tlscert)
return NULL;
memset(tlscert, 0, sizeof(*tlscert));
tlscert->dnsnames = xmpp_alloc(ctx, sizeof(*tlscert->dnsnames));
tlscert->dnsnames = strophe_alloc(ctx, sizeof(*tlscert->dnsnames));
if (!tlscert->dnsnames) {
xmpp_free(ctx, tlscert);
strophe_free(ctx, tlscert);
return NULL;
}
memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
@@ -174,19 +173,19 @@ void xmpp_tlscert_free(xmpp_tlscert_t *cert)
size_t n;
for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
if (cert->elements[n])
xmpp_free(cert->ctx, 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])
xmpp_free(cert->ctx, cert->dnsnames->data[n]);
strophe_free(cert->ctx, cert->dnsnames->data[n]);
}
}
xmpp_free(cert->ctx, cert->dnsnames->data);
xmpp_free(cert->ctx, cert->dnsnames);
strophe_free(cert->ctx, cert->dnsnames->data);
strophe_free(cert->ctx, cert->dnsnames);
if (cert->pem)
xmpp_free(cert->ctx, cert->pem);
xmpp_free(cert->ctx, cert);
strophe_free(cert->ctx, cert->pem);
strophe_free(cert->ctx, cert);
}
/** Add a dnsName to the Strophe TLS certificate object.
@@ -200,15 +199,52 @@ int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
{
if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
char **dnsnames =
xmpp_realloc(cert->ctx, cert->dnsnames->data,
(cert->dnsnames->max + tlscert_dnsnames_increment) *
sizeof(char **));
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++] =
xmpp_strdup(cert->ctx, dnsname);
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_key;
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

@@ -62,4 +62,7 @@ int tls_is_recoverable(int error);
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__ */

View File

@@ -17,6 +17,8 @@
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/x509-ext.h>
#include <gnutls/pkcs11.h>
#include <gnutls/pkcs12.h>
#include "common.h"
#include "tls.h"
@@ -47,27 +49,131 @@ void tls_shutdown(void)
gnutls_global_deinit();
}
static gnutls_x509_crt_t _tls_load_cert(xmpp_conn_t *conn)
static int _tls_password_callback(void *userdata,
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_datum_t data;
int res;
if (gnutls_x509_crt_init(&cert) < 0)
return NULL;
if (gnutls_load_file(conn->tls_client_cert, &data) < 0)
goto LBL_ERR;
goto error_out;
res = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
gnutls_free(data.data);
if (res < 0)
goto LBL_ERR;
goto error_out;
return cert;
LBL_ERR:
error_out:
gnutls_x509_crt_deinit(cert);
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_key, &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)
{
if (conn->tls && conn->tls->client_cert == cert)
@@ -93,7 +199,7 @@ static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
* https://gitlab.com/gnutls/gnutls/-/merge_requests/1397
*/
if (ret) {
*ret = xmpp_strdup(conn->ctx, name);
*ret = strophe_strdup(conn->ctx, name);
}
return GNUTLS_SAN_OTHERNAME_XMPP;
}
@@ -112,7 +218,7 @@ static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
return GNUTLS_E_MEMORY_ERROR;
}
if (ret) {
*ret = xmpp_strdup(conn->ctx, (char *)xmpp_addr.data);
*ret = strophe_strdup(conn->ctx, (char *)xmpp_addr.data);
}
gnutls_free(xmpp_addr.data);
return GNUTLS_SAN_OTHERNAME_XMPP;
@@ -181,51 +287,53 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
gnutls_x509_crt_export2(cert, GNUTLS_X509_FMT_PEM, &data);
tlscert->pem = xmpp_alloc(ctx, data.size + 1);
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] = xmpp_strdup(ctx, buf);
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] = xmpp_strdup(ctx, buf);
tlscert->elements[XMPP_CERT_ISSUER] = strophe_strdup(ctx, buf);
time_val = gnutls_x509_crt_get_activation_time(cert);
tlscert->elements[XMPP_CERT_NOTBEFORE] = xmpp_strdup(ctx, ctime(&time_val));
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] = xmpp_strdup(ctx, ctime(&time_val));
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] = xmpp_strdup(ctx, buf);
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] = xmpp_strdup(ctx, buf);
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = strophe_strdup(ctx, buf);
xmpp_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
tlscert->elements[XMPP_CERT_VERSION] = xmpp_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] =
xmpp_strdup(ctx, gnutls_pk_algorithm_get_name(algo));
strophe_strdup(ctx, gnutls_pk_algorithm_get_name(algo));
algo = gnutls_x509_crt_get_signature_algorithm(cert);
tlscert->elements[XMPP_CERT_SIGALG] =
xmpp_strdup(ctx, gnutls_sign_get_name(algo));
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] = xmpp_strdup(ctx, buf);
tlscert->elements[XMPP_CERT_SERIALNUMBER] = strophe_strdup(ctx, buf);
for (n = 0, m = 0, res = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
++n) {
@@ -233,7 +341,8 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
res = gnutls_x509_crt_get_subject_alt_name(cert, n, buf, &size, NULL);
if (res == GNUTLS_SAN_DNSNAME) {
if (tlscert_add_dnsname(tlscert, buf))
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", m, buf);
strophe_debug(ctx, "tls", "Can't store dnsName(%zu): %s", m,
buf);
m++;
}
}
@@ -254,24 +363,27 @@ static int _tls_verify(gnutls_session_t session)
return -1;
if (gnutls_certificate_verify_peers2(session, &status) < 0) {
xmpp_error(tls->ctx, "tls", "Verify peers failed");
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) {
xmpp_error(tls->ctx, "tls", "Status print failed");
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)
if (status == 0 || tls->conn->tls_trust) {
gnutls_free(out.data);
return 0;
}
if (!tls->conn->certfail_handler) {
xmpp_error(tls->ctx, "tls",
"No certfail handler set, canceling connection attempt");
strophe_error(tls->ctx, "tls",
"No certfail handler set, canceling connection attempt");
gnutls_free(out.data);
return -1;
}
@@ -310,7 +422,7 @@ static int _tls_verify(gnutls_session_t session)
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
tls_t *tls = strophe_alloc(conn->ctx, sizeof(tls_t));
if (tls) {
memset(tls, 0, sizeof(*tls));
@@ -321,19 +433,55 @@ tls_t *tls_new(xmpp_conn_t *conn)
gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, NULL);
if (conn->password_callback)
gnutls_certificate_set_pin_function(tls->cred,
_tls_password_callback, conn);
if (conn->tls_client_cert && conn->tls_client_key) {
unsigned int retries = 0;
tls->client_cert = _tls_load_cert(conn);
if (!tls->client_cert) {
xmpp_error(tls->ctx, "tls",
"could not read client certificate");
gnutls_certificate_free_credentials(tls->cred);
gnutls_deinit(tls->session);
xmpp_free(tls->ctx, tls);
return NULL;
strophe_error(tls->ctx, "tls",
"could not read client certificate");
goto error_out;
}
while (retries++ < conn->password_retries) {
int err = gnutls_certificate_set_x509_key_file(
tls->cred, conn->tls_client_cert, conn->tls_client_key,
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_key) {
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_key, 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_x509_key_file(
tls->cred, conn->tls_client_cert, conn->tls_client_key,
GNUTLS_X509_FMT_PEM);
}
gnutls_certificate_set_verify_function(tls->cred, _tls_verify);
@@ -346,6 +494,13 @@ tls_t *tls_new(xmpp_conn_t *conn)
}
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)
@@ -354,7 +509,7 @@ void tls_free(tls_t *tls)
gnutls_x509_crt_deinit(tls->client_cert);
gnutls_deinit(tls->session);
gnutls_certificate_free_credentials(tls->cred);
xmpp_free(tls->ctx, tls);
strophe_free(tls->ctx, tls);
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)

View File

@@ -26,6 +26,7 @@
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
#include "common.h"
#include "tls.h"
@@ -47,6 +48,12 @@
#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
static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
{
@@ -54,6 +61,30 @@ static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
}
#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
static int GENERAL_NAME_get0_otherName(const GENERAL_NAME *gen,
ASN1_OBJECT **poid,
@@ -90,6 +121,8 @@ static void _tls_set_error(tls_t *tls, int error);
static void _tls_log_error(xmpp_ctx_t *ctx);
static void _tls_dump_cert_info(tls_t *tls);
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_xmppaddr_to_string(GENERAL_NAME *name, char **res);
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res);
@@ -202,9 +235,11 @@ const char *cert_errors[] = {
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_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_FAILED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN),
#endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */
#endif /* !LIBRESSL_VERSION_NUMBER */
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
};
@@ -258,8 +293,10 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
char *ret = NULL;
int i, j;
GENERAL_NAMES *names = _tls_conn_get_names(conn);
if (!names)
if (!names) {
_tls_log_error(conn->ctx);
return NULL;
}
int num_names = sk_GENERAL_NAME_num(names);
for (i = j = 0; i < num_names; ++i) {
char *res;
@@ -269,9 +306,9 @@ char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
if (_tls_xmppaddr_to_string(name, &res))
continue;
if (j == (int)n) {
xmpp_debug(conn->ctx, "tls", "extracted jid %s from id-on-xmppAddr",
res);
ret = xmpp_strdup(conn->ctx, res);
strophe_debug(conn->ctx, "tls",
"extracted jid %s from id-on-xmppAddr", res);
ret = strophe_strdup(conn->ctx, res);
OPENSSL_free(res);
break;
}
@@ -286,8 +323,10 @@ unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
unsigned int ret = 0;
GENERAL_NAMES *names = _tls_conn_get_names(conn);
if (!names)
if (!names) {
_tls_log_error(conn->ctx);
return 0;
}
int j, num_names = sk_GENERAL_NAME_num(names);
for (j = 0; j < num_names; ++j) {
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
@@ -321,7 +360,7 @@ 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 xmpp_strdup(ctx, buf);
return strophe_strdup(ctx, buf);
}
return NULL;
}
@@ -345,7 +384,7 @@ _get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
if (X509_digest(err_cert, digest, buf, &len) != 0) {
char fingerprint[4 * EVP_MAX_MD_SIZE];
hex_encode(fingerprint, buf, len);
return xmpp_strdup(ctx, fingerprint);
return strophe_strdup(ctx, fingerprint);
}
return NULL;
}
@@ -353,7 +392,7 @@ _get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
static char *
_get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
{
int rc, alg_nid = NID_undef;
int alg_nid = NID_undef;
switch (el) {
case XMPP_CERT_KEYALG: {
@@ -362,8 +401,7 @@ _get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
#else
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(err_cert);
ASN1_OBJECT *ppkalg = NULL;
rc = X509_PUBKEY_get0_param(&ppkalg, NULL, NULL, NULL, pubkey);
if (rc) {
if (X509_PUBKEY_get0_param(&ppkalg, NULL, NULL, NULL, pubkey)) {
alg_nid = OBJ_obj2nid(ppkalg);
}
#endif
@@ -383,7 +421,7 @@ _get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
if (alg_nid != NID_undef) {
const char *alg = OBJ_nid2ln(alg_nid);
if (alg) {
return xmpp_strdup(ctx, alg);
return strophe_strdup(ctx, alg);
}
}
return NULL;
@@ -398,26 +436,26 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
BIO *b = BIO_new(BIO_s_mem());
if (!b)
goto ERR_OUT;
goto error_out;
PEM_write_bio_X509(b, cert);
BUF_MEM *bptr;
BIO_get_mem_ptr(b, &bptr);
tlscert->pem = xmpp_alloc(ctx, bptr->length + 1);
tlscert->pem = strophe_alloc(ctx, bptr->length + 1);
if (!tlscert->pem)
goto ERR_OUT;
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 ERR_OUT;
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, 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 ERR_OUT;
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, issuer);
goto error_out;
tlscert->elements[XMPP_CERT_ISSUER] = strophe_strdup(ctx, issuer);
OPENSSL_free(issuer);
tlscert->elements[XMPP_CERT_NOTBEFORE] =
@@ -430,8 +468,8 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
xmpp_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
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);
@@ -442,7 +480,7 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
char *serialnumber = BN_bn2hex(bn);
if (serialnumber) {
tlscert->elements[XMPP_CERT_SERIALNUMBER] =
xmpp_strdup(ctx, serialnumber);
strophe_strdup(ctx, serialnumber);
OPENSSL_free(serialnumber);
}
BN_free(bn);
@@ -458,7 +496,8 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
if (_tls_dnsname_to_string(name, &res))
continue;
if (tlscert_add_dnsname(tlscert, res))
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", n, res);
strophe_debug(ctx, "tls", "Can't store dnsName(%zu): %s", n,
res);
n++;
OPENSSL_free(res);
}
@@ -466,7 +505,7 @@ static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
}
return tlscert;
ERR_OUT:
error_out:
xmpp_tlscert_free(tlscert);
return NULL;
}
@@ -481,8 +520,8 @@ static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
xmpp_conn_t *conn = SSL_get_app_data(ssl);
if (!conn->certfail_handler) {
xmpp_error(conn->ctx, "tls",
"No certfail handler set, canceling connection attempt");
strophe_error(conn->ctx, "tls",
"No certfail handler set, canceling connection attempt");
return 0;
}
@@ -493,9 +532,9 @@ static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
if (!tlscert)
return 0;
xmpp_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
tlscert->elements[XMPP_CERT_ISSUER]);
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,
@@ -506,9 +545,15 @@ static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
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 = xmpp_alloc(conn->ctx, sizeof(*tls));
tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls));
if (tls) {
int ret;
@@ -536,18 +581,56 @@ 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_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) {
unsigned int retries = 0;
tls->client_cert = _tls_cert_read(conn);
if (!tls->client_cert) {
xmpp_error(tls->ctx, "tls",
"could not read client certificate");
strophe_error(tls->ctx, "tls",
"could not read client certificate");
goto err_free_ctx;
}
SSL_CTX_use_certificate_file(tls->ssl_ctx, conn->tls_client_cert,
SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(tls->ssl_ctx, conn->tls_client_key,
SSL_FILETYPE_PEM);
while (retries++ < conn->password_retries) {
if (SSL_CTX_use_PrivateKey_file(
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_key) {
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 {
/* If the server asks for a client certificate, don't send one. */
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
@@ -562,17 +645,16 @@ tls_t *tls_new(xmpp_conn_t *conn)
* location is still treated as a success.
* Ignore errors when XMPP_CONN_FLAG_TRUST_TLS is set.
*/
xmpp_error(tls->ctx, "tls",
"SSL_CTX_set_default_verify_paths() failed");
strophe_error(tls->ctx, "tls",
"SSL_CTX_set_default_verify_paths() failed");
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) {
xmpp_error(tls->ctx, "tls",
"SSL_CTX_load_verify_locations() failed");
_tls_log_error(tls->ctx);
strophe_error(tls->ctx, "tls",
"SSL_CTX_load_verify_locations() failed");
goto err_free_cert;
}
}
@@ -623,7 +705,7 @@ err_free_cert:
err_free_ctx:
SSL_CTX_free(tls->ssl_ctx);
err:
xmpp_free(conn->ctx, tls);
strophe_free(conn->ctx, tls);
_tls_log_error(conn->ctx);
return NULL;
}
@@ -633,7 +715,7 @@ void tls_free(tls_t *tls)
SSL_free(tls->ssl);
X509_free(tls->client_cert);
SSL_CTX_free(tls->ssl_ctx);
xmpp_free(tls->ctx, tls);
strophe_free(tls->ctx, tls);
}
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
@@ -680,13 +762,13 @@ int tls_start(tls_t *tls)
x509_res = SSL_get_verify_result(tls->ssl);
if (x509_res == X509_V_OK) {
xmpp_debug(tls->ctx, "tls", "Certificate verification passed");
strophe_debug(tls->ctx, "tls", "Certificate verification passed");
} else {
xmpp_debug(tls->ctx, "tls",
"Certificate verification FAILED, result=%s(%ld)",
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
strophe_debug(tls->ctx, "tls",
"Certificate verification FAILED, result=%s(%ld)",
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
if (ret > 0)
xmpp_debug(tls->ctx, "tls", "User decided to connect anyways");
strophe_debug(tls->ctx, "tls", "User decided to connect anyways");
}
_tls_dump_cert_info(tls);
@@ -801,9 +883,13 @@ static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
static void _tls_set_error(tls_t *tls, int error)
{
if (error != 0 && !tls_is_recoverable(error)) {
xmpp_debug(tls->ctx, "tls", "error=%s(%d) errno=%d",
TLS_ERROR_STR(error, tls_errors), error, errno);
strophe_debug(tls->ctx, "tls", "error=%s(%d) errno=%d lasterror=%d",
TLS_ERROR_STR(error, tls_errors), error, errno,
tls->lasterror);
_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;
}
@@ -811,13 +897,13 @@ static void _tls_set_error(tls_t *tls, int error)
static void _tls_log_error(xmpp_ctx_t *ctx)
{
unsigned long e;
char buf[256];
do {
e = ERR_get_error();
if (e != 0) {
ERR_error_string_n(e, buf, sizeof(buf));
xmpp_debug(ctx, "tls", "%s", buf);
strophe_debug(
ctx, "tls", "error:%08X:%s:%s:%s", e, ERR_lib_error_string(e),
STROPHE_ERR_func_error_string(e), ERR_reason_error_string(e));
}
} while (e != 0);
}
@@ -829,43 +915,131 @@ static void _tls_dump_cert_info(tls_t *tls)
cert = SSL_get_peer_certificate(tls->ssl);
if (cert == NULL)
xmpp_debug(tls->ctx, "tls", "Certificate was not presented by peer");
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else {
name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (name != NULL) {
xmpp_debug(tls->ctx, "tls", "Subject=%s", name);
strophe_debug(tls->ctx, "tls", "Subject=%s", name);
OPENSSL_free(name);
}
name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (name != NULL) {
xmpp_debug(tls->ctx, "tls", "Issuer=%s", name);
strophe_debug(tls->ctx, "tls", "Issuer=%s", name);
OPENSSL_free(name);
}
X509_free(cert);
}
}
static X509 *_tls_cert_read(xmpp_conn_t *conn)
static X509 *_tls_cert_read_x509(xmpp_conn_t *conn)
{
if (conn->tls && conn->tls->client_cert)
return conn->tls->client_cert;
BIO *f = BIO_new_file(conn->tls_client_cert, "r");
if (!f) {
xmpp_debug(conn->ctx, "tls", "f == NULL");
strophe_debug(conn->ctx, "tls", "f == NULL");
return NULL;
}
X509 *c = PEM_read_bio_X509(f, NULL, NULL, NULL);
BIO_free(f);
if (!c) {
unsigned long error;
while ((error = ERR_get_error()) != 0) {
xmpp_debug(conn->ctx, "tls", "c == NULL: %s",
ERR_error_string(error, NULL));
}
_tls_log_error(conn->ctx);
}
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_key, "r");
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 xaddr_nid = NID_undef;

View File

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

View File

@@ -15,6 +15,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
@@ -38,9 +39,9 @@
*
* @return a newly allocated string with the same data as s or NULL on error
*/
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s)
char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s)
{
return xmpp_strndup(ctx, s, SIZE_MAX);
return strophe_strndup(ctx, s, SIZE_MAX);
}
/** Duplicate a string with a maximum length.
@@ -54,7 +55,7 @@ char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s)
* @return a newly allocated string that contains at most `len` symbols
* of the original string or NULL on error
*/
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
{
char *copy;
size_t l;
@@ -63,9 +64,9 @@ char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
if (l > len)
l = len;
copy = xmpp_alloc(ctx, l + 1);
copy = strophe_alloc(ctx, l + 1);
if (!copy) {
xmpp_error(ctx, "xmpp", "failed to allocate required memory");
strophe_error(ctx, "xmpp", "failed to allocate required memory");
return NULL;
}
@@ -80,7 +81,7 @@ char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
* For example, visual studio older than 2005 doesn't provide strtok_r()
* nor strtok_s().
*/
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
char *strophe_strtok_r(char *s, const char *delim, char **saveptr)
{
size_t len;
@@ -157,10 +158,17 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
*/
void disconnect_mem_error(xmpp_conn_t *conn)
{
xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
strophe_error(conn->ctx, "xmpp", "Memory allocation error");
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;

View File

@@ -26,13 +26,14 @@
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))
/* string functions */
char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
char *strophe_strtok_r(char *s, const char *delim, char **saveptr);
/* timing functions */
uint64_t time_stamp(void);
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__ */

View File

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

213
strophe.h
View File

@@ -79,6 +79,10 @@ extern "C" {
* Namespace definition for '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 */
/** @def XMPP_EOK
@@ -168,6 +172,7 @@ xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level);
/* opaque connection object */
typedef struct _xmpp_conn_t xmpp_conn_t;
typedef struct _xmpp_stanza_t xmpp_stanza_t;
typedef struct _xmpp_sm_t xmpp_sm_state_t;
/* connection flags */
#define XMPP_CONN_FLAG_DISABLE_TLS (1UL << 0)
@@ -181,6 +186,10 @@ typedef struct _xmpp_stanza_t xmpp_stanza_t;
* Enable legacy authentication support.
*/
#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 */
typedef enum {
@@ -269,6 +278,81 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t *conn,
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);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
@@ -284,6 +368,11 @@ 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,
const char *cert,
const char *key);
@@ -294,10 +383,24 @@ void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
void xmpp_conn_disable_tls(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
int xmpp_conn_is_connecting(xmpp_conn_t *conn);
int xmpp_conn_is_connected(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,
const char *altdomain,
@@ -406,6 +509,9 @@ 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,
const char *name,
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);
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child);
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza,
@@ -532,6 +638,111 @@ void xmpp_base64_decode_bin(xmpp_ctx_t *ctx,
unsigned char **out,
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
}
#endif

13
testbuild.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/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

BIN
tests/cert.emptypass.pfx Normal file

Binary file not shown.

BIN
tests/cert.nopass.pfx Normal file

Binary file not shown.

BIN
tests/cert.pfx Normal file

Binary file not shown.

8
tests/key_encrypted.pem Normal file
View File

@@ -0,0 +1,8 @@
-----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

@@ -34,17 +34,17 @@
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#define COMPARE(v1, v2) \
do { \
const char *__v1 = v1; \
const char *__v2 = v2; \
if (strcmp(__v1, __v2) != 0) { \
printf("Error: %s\n" \
"Expected: %s\n" \
"Got: %s\n", \
#v1 " != " #v2, __v1, __v2); \
exit(1); \
} \
#define COMPARE(v1, v2) \
do { \
const char *__v1 = v1; \
const char *__v2 = v2; \
if (!__v1 || !__v2 || strcmp(__v1, __v2) != 0) { \
printf("Error: %s\n" \
"Expected: %s\n" \
"Got: %s\n", \
#v1 " != " #v2, __v1, __v2); \
exit(1); \
} \
} while (0)
#define COMPARE_BUF(v1, len1, v2, len2) \
@@ -61,6 +61,19 @@
} \
} 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);
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;
ctx = xmpp_ctx_new(&mymem, &mylog);
xmpp_debug(ctx, "test", "hello");
strophe_debug(ctx, "test", "hello");
testptr1 = xmpp_alloc(ctx, 1024);
testptr1 = strophe_alloc(ctx, 1024);
if (testptr1 == NULL) {
xmpp_ctx_free(ctx);
return 1;
}
testptr2 = xmpp_realloc(ctx, testptr1, 2048);
testptr2 = strophe_realloc(ctx, testptr1, 2048);
if (testptr2 == NULL) {
xmpp_free(ctx, testptr1);
strophe_free(ctx, testptr1);
xmpp_ctx_free(ctx);
return 1;
}
xmpp_free(ctx, testptr2);
strophe_free(ctx, testptr2);
xmpp_ctx_free(ctx);

View File

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

View File

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

View File

@@ -21,21 +21,21 @@
#include "rand.c"
/* stubs to build test without whole libstrophe */
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size)
{
(void)ctx;
(void)size;
return NULL;
}
void xmpp_free(const xmpp_ctx_t *ctx, void *p)
void strophe_free(const xmpp_ctx_t *ctx, void *p)
{
(void)ctx;
(void)p;
}
#ifndef HAVE_SNPRINTF
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
int strophe_snprintf(char *str, size_t count, const char *fmt, ...)
{
(void)str;
(void)count;
@@ -49,6 +49,8 @@ uint64_t time_stamp(void)
return 0;
}
#ifndef USE_GETRANDOM
static struct {
const char *entropy_input;
const char *nonce;
@@ -160,3 +162,19 @@ int main()
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,7 +13,6 @@
#include <stdio.h>
#include "strophe.h"
#include "rand.h"
#include "resolver.h"
#include "test.h"
@@ -217,14 +216,14 @@ int main()
rand = xmpp_rand_new(ctx);
assert(rand != NULL);
assert(sizeof(data2) > 64);
buf = xmpp_alloc(ctx, sizeof(data2));
buf = strophe_alloc(ctx, sizeof(data2));
assert(buf != NULL);
memcpy(buf, data2, 64);
xmpp_rand_bytes(rand, &buf[64], sizeof(data2) - 64);
ret = resolver_srv_lookup_buf(ctx, buf, sizeof(data2), &srv_rr_list);
if (ret == XMPP_DOMAIN_FOUND && srv_rr_list != NULL)
resolver_srv_free(ctx, srv_rr_list);
xmpp_free(ctx, buf);
strophe_free(ctx, buf);
xmpp_rand_free(ctx, rand);
printf("ok\n");

View File

@@ -29,23 +29,6 @@ static const char response_md5[] =
"MDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL3NvbWVyZWFsbSIscmVz"
"cG9uc2U9NGVhNmU4N2JjMDkzMzUwNzQzZGIyOGQ3MDIwOGNhZmIsY2hhcnNl"
"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)
{
@@ -60,7 +43,7 @@ int test_plain(xmpp_ctx_t *ctx)
/* SASL PLAIN returned incorrect string! */
return 2;
}
xmpp_free(ctx, result);
strophe_free(ctx, result);
return 0;
}

92
tests/test_send_queue.c Normal file
View File

@@ -0,0 +1,92 @@
/* 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 (y = 0; fp_nums[y] != 0; y++) {
xmpp_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
strophe_snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
sprintf(buf2, fp_fmt[x], fp_nums[y]);
if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: "
@@ -50,7 +50,7 @@ int main(void)
for (x = 0; int_fmt[x] != NULL; x++)
for (y = 0; int_nums[y] != 0; y++) {
xmpp_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
strophe_snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
sprintf(buf2, int_fmt[x], int_nums[y]);
if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: "

View File

@@ -99,7 +99,7 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
size_t buflen;
int ret;
static const char *str =
const char *str =
"<signcrypt xmlns=\"urn:xmpp:openpgp:0\"><to "
"jid=\"user@domain.com\"/><time "
"stamp=\"2020-06-03T21:26:24+0200\"/><rpad/><payload><body "
@@ -113,6 +113,22 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
xmpp_free(ctx, buf);
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);
@@ -123,6 +139,7 @@ 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];
@@ -135,12 +152,29 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
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));
@@ -151,6 +185,46 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
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);
@@ -163,6 +237,7 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
COMPARE(str_error, buf);
xmpp_free(ctx, buf);
xmpp_stanza_release(mood);
xmpp_stanza_release(stanza);
xmpp_stanza_release(error);
}

View File

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

View File

@@ -18,50 +18,77 @@
#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()
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
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"},
};
char xmppaddr_num[] = "0";
unsigned int n;
unsigned int m, n;
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_client_cert(conn, "tests/cert.pem", "tests/key.pem");
for (m = 0; m < sizeof(client_cert) / sizeof(client_cert[0]); ++m) {
conn = xmpp_conn_new(ctx);
xmppaddr_num[0] = xmppaddr_num[0] + xmpp_conn_cert_xmppaddr_num(conn);
if (client_cert[m].needs_callback)
xmpp_conn_set_password_callback(conn, password_callback, NULL);
COMPARE("2", xmppaddr_num);
xmpp_conn_set_client_cert(conn, client_cert[m].pem, client_cert[m].key);
for (n = 0; n < 3; ++n) {
char *r = xmpp_conn_cert_xmppaddr(conn, n);
switch (n) {
case 0:
COMPARE("very.long.username@so.the.asn1.length.is.a.valid.ascii."
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);
COMPARE("2", xmppaddr_num);
for (n = 0; n < 3; ++n) {
char *r = xmpp_conn_cert_xmppaddr(conn, n);
switch (n) {
case 0:
COMPARE(
"very.long.username@so.the.asn1.length.is.a.valid.ascii."
"character",
r);
break;
case 1:
COMPARE("second@xmpp.jid", r);
break;
default:
if (r != NULL) {
printf("\nThere shall only be two id-on-xmppAddr SANs!\nFound "
"another one: %s\n",
r);
exit(1);
break;
case 1:
COMPARE("second@xmpp.jid", r);
break;
default:
if (r != NULL) {
printf("\nThere shall only be two id-on-xmppAddr SANs!\n"
"Found another one: %s\n",
r);
exit(1);
}
break;
}
break;
free(r);
}
free(r);
xmpp_conn_release(conn);
}
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();

View File

@@ -1,6 +1,6 @@
#!/bin/sh
if [ "x$LIBRESSL" = "xyes" ]; then
if [ "x$LIBRESSL_COMMIT" != "x" ]; then
cd "$HOME"
git clone https://github.com/libressl-portable/portable.git libressl-git
cd libressl-git