106 Commits

Author SHA1 Message Date
Dmitry Podgorny
06cb1459f1 tls/securetransport: add client cert stub functions 2021-03-30 00:46:13 +03:00
Dmitry Podgorny
82f372fa49 Add tls_securetransport.c to EXTRA_DIST 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
9ddc881102 tls/securetransport: tls_new() accepts xmpp_conn_t object 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
f6ef50d134 tls/securetransport: fix indentation 2021-03-30 00:30:30 +03:00
Chris A. Taylor
bd87653c76 Add Secure Transport implementation of TLS 2021-03-30 00:30:30 +03:00
Dmitry Podgorny
2f491e0250 travis-ci: update travis config
- add gnutls option
- fix style stage: 'matrix' and 'jobs' don't work together
- switch to Ubuntu 20.04 (focal), because there is issue with
  gnutls-3.4.10 from Ubuntu 16.04 (see #177)
2021-03-27 22:35:10 +02:00
Steffen Jaeckel
2509ed8424 fixup minor gnutls things
* gcc complained about missing include
* remove unnecessary debug statement

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-24 14:47:18 +02:00
Dmitry Podgorny
f3e3e64a17 docs: remove footer.html
Use default footer instead.
2021-03-23 19:51:57 +02:00
Dmitry Podgorny
d7a28f97a6 ChangeLog: update with upcoming features 2021-03-23 02:30:11 +02:00
Dmitry Podgorny
2199d8d088 examples/basic: fix arguments check 2021-03-23 02:17:35 +02:00
Dmitry Podgorny
d1ce4b35ae tests/xmppaddr: improve error reports
COMPARE() assumes that the first argument is the reference. Swap
arguments to report right expected value.
2021-03-23 02:14:25 +02:00
Dmitry Podgorny
e77cd53215 conn: fix segfault in xmpp_connect_client() when jid not set 2021-03-23 02:12:55 +02:00
Dmitry Podgorny
588aea4f54 tls/gnutls: zeroize allocated tls object
Initialize tls object with 0. This also sets tls->client_cert to NULL.
2021-03-23 02:11:09 +02:00
Dmitry Podgorny
ee5f9fb77b tls/openssl: fix openssl-3.0.0 support
3.0.0 includes the "id-on-xmppAddr" object and OBJ_create() returns
NID_undef if we try to create a new one.
2021-03-23 02:08:22 +02:00
Dmitry Podgorny
4790a61437 tls/openssl: fix openssl-0.9.8 support
0.9.8 doesn't implement GENERAL_NAME_get0_otherName().
2021-03-23 02:07:00 +02:00
Steffen Jaeckel
25d3a2d459 add test for new API's
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-23 02:04:59 +02:00
Steffen Jaeckel
27be6acaeb add tls_id_on_xmppaddr() for GnuTLS
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-23 02:04:59 +02:00
Steffen Jaeckel
9a0e070c24 add missing API to other TLS implementations
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-23 02:04:59 +02:00
Steffen Jaeckel
e490011b68 add option to build against gnutls
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-23 02:04:59 +02:00
Steffen Jaeckel
3b4b664c28 add client-cert support to basic example
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-23 02:04:59 +02:00
Steffen Jaeckel
18c95fa7bd add support for client authentication via certificates
The SASL EXTERNAL method is implemented to make this possible.

Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2021-03-23 02:04:59 +02:00
Dmitry Podgorny
cf2f7147d9 tests/rand: don't define xmpp_snprintf when HAVE_SNPRINTF is set
If HAVE_SNPRINTF is set, xmpp_snprintf is replaced with snprintf symbol
and it can cause issues (e.g. on MacOS system).
2021-03-23 00:30:09 +02:00
Dmitry Podgorny
ecf6457cdb conn: send stream attribute "from" after TLS negotiation
RFC6120 states that client SHOULD send the "from" attribute in <stream>.

Because of privacy concerns attribute "from" should be sent only after
TLS negotiation. This step ensures that the server is verified by its
certificate and protects JID from MITM attack.

Fixes #163.
Also should be helpful for #162.
2021-03-21 17:09:35 +02:00
Dmitry Podgorny
db8a511f68 style: remove extra const keyword from interfaces
Const variables in prototypes don't add much value, but make the code
larger and redundant. Remove these const keywords.
Note, this doesn't apply to pointers to const memory.
2021-03-19 22:12:15 +02:00
Dmitry Podgorny
2d5424bcff Release libstrophe-0.10.1 2020-12-24 16:04:21 +02:00
Dmitry Podgorny
5792d52461 doxygen: set correct version number 2020-12-19 02:33:14 +02:00
Dmitry Podgorny
09229e2cd5 conn: remove extra ; symbol 2020-10-07 20:18:20 +03:00
Dmitry Podgorny
c07ac0a68d conn: don't crash when user sets password to NULL
Make it possible to reset password to NULL. It is not required for
ANONYMOUS authentication. Also, report an error and disconnect if
password is not set and libstrophe should try authentication mechanisms
other than ANONYMOUS.
2020-09-30 20:56:52 +03:00
Dmitry Podgorny
60ce94c267 auth: add missed space in log message 2020-09-30 20:43:32 +03:00
Dmitry Podgorny
99f2d4fe54 travis-ci: build libstrophe against LibreSSL 2020-09-24 15:07:15 +03:00
Dmitry Podgorny
acced31192 tls/openssl: Fix undefined error codes for LibreSSL
LibreSSL doesn't define all error codes which OpenSSL defines. Wrap them
with #ifndef.

Reference: https://bugs.gentoo.org/744127
2020-09-24 13:34:49 +03:00
Dmitry Podgorny
9ee08f8f2a Release libstrophe-0.10.0 2020-09-16 00:27:34 +03:00
Dmitry Podgorny
7c1061ccbb autotools: remove rpm files 2020-09-16 00:27:34 +03:00
Dmitry Podgorny
7eab7c3f5e Android: add missed files and -DHAVE_DECL_VA_COPY 2020-09-16 00:21:01 +03:00
Dmitry Podgorny
4d93b6c0d6 Check for va_copy declaration
ctx.c contains a workaround for systems without va_copy() support.
Improve this workaround in the way which is described in the autoconf
manual.

Also check for va_copy declaration in configure time.

Fixes #160.
2020-09-16 00:07:41 +03:00
Dmitry Podgorny
65b3a0996f README: mention about license 2020-09-15 03:14:54 +03:00
Dmitry Podgorny
4dd78be10d tls/openssl: fix compilation with older openssl
Not all error codes are present in older versions of openssl.
2020-09-15 03:07:02 +03:00
Dmitry Podgorny
8c076ac969 stanza: remove attribute xmlns in xmpp_stanza_reply() 2020-09-15 02:21:18 +03:00
Dmitry Podgorny
7c68aced35 stanza: add xmpp_stanza_reply_error()
This function makes an error reply stanza as described in
https://tools.ietf.org/html/rfc6120#section-8.3
2020-09-15 02:19:20 +03:00
Dmitry Podgorny
197896ba1b tls/openssl: improve logging
Log error names and codes to increase verbosity in debug mode.
2020-06-18 22:18:59 +03:00
Dmitry Podgorny
bef411f319 sha1: fix zeroing storage
Compilers remove dead assignments in optimization phase. But SHA1 code
uses them for wiping of sensitive data.  Fix this with the trick used
by openssl.
2020-06-18 22:14:04 +03:00
Dmitry Podgorny
7f5ce7d2ae sha1: remove SHA1HANDSOFF
We don't support configuration when SHA1 functions overwrite user's
data. So remove this code not to confuse.
2020-06-19 00:51:33 +03:00
Dmitry Podgorny
47e27c837a examples/basic: add new conn flags
Add options:
  --trust-tls
  --legacy-auth
2020-06-07 20:43:41 +03:00
Dmitry Podgorny
50a4a983cd handler: add documentation for global timed handlers 2020-06-06 00:11:24 +03:00
Dmitry Podgorny
428681a185 stanza: add xmpp_stanza_new_from_string()
This function creates a stanza object from a string. The string must
contain a single complete stanza. Multiple stanzas will lead to memory
leak and this is not handled in the patch.
2020-06-04 03:44:21 +03:00
Dmitry Podgorny
3dcc5a60f2 Introduce global timed handlers
There are situations when applications need more predictable timed
handlers that don't depend on connection status. Other usecase of
the global handlers is to manage offline connections, for example,
reconnect after a disconnection.
2020-06-03 02:11:40 +03:00
Dmitry Podgorny
cba21b5598 examples/register: replace getline() with fgets()
getline(3) doesn't exist on all systems.
2020-05-31 22:05:21 +03:00
Dmitry Podgorny
a65dd1059d resolver: don't build legacy win32 code with c-ares
Fix ifdef macros to exclude legacy win32 code when it is not needed.
2020-05-31 21:43:09 +03:00
Dmitry Podgorny
7c83eb0efa windows: rewrite headers in lower case
Otherwise, compilation fails on systems that are case sensitive.

Reference: #159.
2020-05-31 21:03:44 +03:00
Steffen Jaeckel
f2c658723f clean-up 2020-04-30 12:03:57 +02:00
Dmitry Podgorny
7ac4b1cc12 Update ChangeLog 2020-04-29 00:24:42 +03:00
Dmitry Podgorny
1c4cb66f5a conn: remove ternary operator
Remove ternary operator where it is redundant.
2020-04-28 23:40:46 +03:00
Dmitry Podgorny
6a50c9cea6 ChangeLog: mention about fixed IPv6 issue 2020-04-02 22:14:15 +03:00
Dmitry Podgorny
37b12ad788 configure: enable check for snprintf()
b2e64587 adds the check but it is commented for unknown reason. Enable
it to use advantage of system snprintf() implementation.
2020-04-02 22:12:30 +03:00
Dmitry Podgorny
5530ac690f rpm: remove libstrophe.spec
Major Linux distributions have added libstrophe to their repositories.
We don't have to support our own spec file. If someone needs spec to
build rpm manually, refer to Linux distributions, for example:

https://build.opensuse.org/package/show/network/libstrophe
https://copr-dist-git.fedorainfracloud.org/cgit/linkdupont/fedora-link-extras/libstrophe.git
2020-04-02 19:38:52 +03:00
Dmitry Podgorny
3063d886bd sasl: remove unused argument
_add_key() is a static function which is used only for DIGEST_MD5. Its
argument 'len' is not used and remains 0. Remove it.
2020-03-31 18:58:36 +03:00
Oleg Synelnykov
198bdd77d0 Remove -Wno-unused-parameter
Introduced UNUSED macro with cast to void in commoh.h for internal
use. Used cast to void directly in those files which do not
include common.h. Although this change doesn't fix semantic issues
with unused function parameters, it does explicitly mark all those
places, which might require attention in future.
2020-03-31 17:37:12 +03:00
Dmitry Podgorny
20c039fdb8 sock: replace sockaddr with sockaddr_storage
sockaddr structure may be insufficient to hold IPv6 address. Replace it
with sockaddr_storage structure.

Fixes #153.
2020-03-31 16:29:09 +03:00
Dmitry Podgorny
c92fc849e7 Remove C++ files
Libstrophe used to provide incomplete C++ API which missed connection
class and wasn't supported for a long time. Remove this API.
2020-02-22 23:19:40 +02:00
Dmitry Podgorny
6fdac3ae72 tests/sha512: add test case for a million of a 2020-01-31 01:59:42 +02:00
Dmitry Podgorny
623ff164de tests/scram: add HMAC test vector
Add test for HMAC and make other tests independent from SHA1.
2020-01-31 01:59:42 +02:00
Dmitry Podgorny
faa46d28a5 scram: fix HMAC-SHA-512
HMAC was originally implemented for SHA1 digest according to RFC2104.
The RFC defined blocksize for all digests as 64 bytes. But RFC4868
requires blocksize for SHA384/SHA512 to be 128 bytes.

Extend HMAC implementation to support variable blocksize and fix it for
SHA384/SHA512.
2020-01-31 01:59:42 +02:00
Dmitry Podgorny
1ca10fd167 Fix SASL SCRAM implementation
* Add SCRAM_DIGEST_SIZE macro for maximum possible digest size. It will
  avoid new buffer overflow errors when new digests are added.
* Fix buffer overflow in sasl_scram(). Buffers were allocated for SHA1
  digest size.
* Fix bug with handler re-registration when a SASL SCRAM mechanism
  fails.
2020-01-31 01:59:42 +02:00
Steffen Jaeckel
709e41fd10 add SHA256&SHA512 tests 2020-01-31 01:59:42 +02:00
Steffen Jaeckel
771d5865ae add SCRAM-SHA-256 and SCRAM-SHA-512 support 2020-01-31 01:59:42 +02:00
Steffen Jaeckel
fc064bc883 re-factor SCRAM to be independent of the hash 2020-01-31 01:34:23 +02:00
Steffen Jaeckel
2ca2fcfedd add stripped-down & slightly-modified version of LibTomCrypt SHA512 2020-01-31 01:34:09 +02:00
Steffen Jaeckel
d78b02ee24 add stripped-down & slightly-modified version of LibTomCrypt SHA256 2020-01-31 01:33:51 +02:00
Steffen Jaeckel
2a94a49cef add required LibTomCrypt load/store functions 2020-01-31 01:32:45 +02:00
Dmitry Podgorny
562a06425b Unify coding style
@sjaeckel integrated clang-format with formal coding style. Run his
script and commit changes.

There are pros and cons of this commit.

Mixed coding style is a "broken window". A good single style simplifies
reading and writing code.

On the other hand, this is a big change which will lead to conflicts.
2020-01-31 01:16:50 +02:00
Steffen Jaeckel
eef07cef36 add code style check to travis 2020-01-31 01:14:32 +02:00
Steffen Jaeckel
2e21d5a021 add new format make target 2020-01-31 01:14:32 +02:00
Steffen Jaeckel
abd1b08a97 trim trailing spaces 2020-01-31 01:14:32 +02:00
Steffen Jaeckel
3feed16e2e ignore eclipse related stuff 2020-01-31 01:14:32 +02:00
Dmitry Podgorny
6b38216124 util: replace time_stamp() implementation
Replace Windows/Xbox implementation with solution from NetXMS project.
2020-01-26 00:52:54 +02:00
Dmitry Podgorny
8cfb2d2a03 XEP-0077: add examples/register
XEP-0077 will not be implemented as part of libstrophe's API, but an
example is provided. The example shows how to use the "raw" connection
to register a user.

Closes #54.
2020-01-25 22:59:19 +02:00
Michael Vetter
1b10e8f987 resolver: include headers for select(2)
C-ares implementation uses select(2) but doesn't include required
headers.

Fixes #149.
2020-01-25 22:06:07 +02:00
Dmitry Podgorny
178f566ae2 Unify include of strophe.h 2020-01-10 01:28:47 +02:00
Dmitry Podgorny
0326e5c5e2 handler: avoid unnamed union
Unnamed unions appeared only in C11 standard. Don't use them to
increase portability.
2020-01-10 01:22:53 +02:00
Dmitry Podgorny
212df6d036 tests: add test for stanza functions
Check reference counting in xmpp_stanza_add_child() amd
xmpp_stanza_add_child_ex().
2020-01-10 00:50:22 +02:00
Dmitry Podgorny
4b04db6b2d stanza: add xmpp_stanza_add_child_ex()
This function is introduced by NetXMS project.
2020-01-10 00:49:45 +02:00
Dmitry Podgorny
fb327d4bd1 parser/expat: provide memory handling suite for 1 ctx
Libstrophe doesn't override memory allocation functions in XML libraries
and default allocators are used as result.

Current patch solves this issue partially for expat module. The module
caches 1st strophe context and overrides expat's allocator for parsers
within this context. For all other contexts, fallback to default
allocator.

This is modified version of solution from UnrealEngine project.
2020-01-07 22:45:15 +02:00
Dmitry Podgorny
a811c868ff util: add time_stamp() implementation for XBOX
Backported from UnrealEngine project.
2020-01-07 22:24:10 +02:00
Dmitry Podgorny
3f05bafffb event: move buffer size to a macro
Move buffer size for incoming messages to a macro. So it can be changed
in one place.
2020-01-07 22:20:12 +02:00
Dmitry Podgorny
133abd096d conn: disconnect if user destroys an active connection object
Backported from UnrealEngine project.
2020-01-07 22:16:11 +02:00
Dmitry Podgorny
cecd6b20e8 stanza: add xmpp_stanza_get_context()
This function is backported from UnrealEngine project.
2020-01-07 22:13:39 +02:00
Dmitry Podgorny
2272681ea2 conn: add state checking API
New boolean functions:
  xmpp_conn_is_connecting()
  xmpp_conn_is_connected()
  xmpp_conn_is_disconnected()

These functions are backported from UnrealEngine project.
2020-01-07 22:12:11 +02:00
Dmitry Podgorny
17f79cbbb8 auth: replace stricmp() with _stricmp()
Newer visual studios deprecate stricmp(). Replace it to fix compilation.
2020-01-07 00:24:57 +02:00
Dmitry Podgorny
2570084cae event: don't redefine error codes
Error codes can be defined in visual studio. Unconditional redefine
causes warnings.
2020-01-07 00:14:59 +02:00
Dmitry Podgorny
b2e6458736 autotools: check for snprintf and vsnprintf
src/snprinf.[ch] rely on HAVE_SNPRINTF macro. The check is missed in
configure script and libstrophe always use internal implementation
of snprinf() which may be inefficient. Add check to configure.ac.
2020-01-05 01:14:22 +02:00
Dmitry Podgorny
c192a2b181 md5: remove unused parameter 2020-01-05 00:30:11 +02:00
Dmitry Podgorny
2e325e5e68 tests/sha1: fix type mismatch warning 2020-01-05 00:28:01 +02:00
Manuel Kasper
f0436490b0 Enable SNI with OpenSSL 0.9.8f as well 2019-12-24 09:07:51 +01:00
Manuel Kasper
243664926f Enable TLS SNI 2019-12-23 14:34:19 +01:00
Dmitry Podgorny
466fa2adbf sha1: don't clean local variable i on exit
In this place value of variable i is constant and predictable. No point
to clean it. Furthermore, since the value is not used after assignment,
compiler will optimize and remove the assignment.

This patch fixes a warning from the clang static analyzer.
2019-11-10 16:04:17 +02:00
Dmitry Podgorny
284e8f4421 tls/openssl: check return code
Check return code of SSL_CTX_set_default_verify_paths() and fail TLS on
an error. However, ignore the error when XMPP_CONN_FLAG_TRUST_TLS is
set.
2019-11-10 15:57:23 +02:00
Dmitry Podgorny
6852da97ae ChangeLog: xmpp_stanza_get_child_by_name_and_ns() 2019-11-30 20:39:17 +02:00
Dmitry Podgorny
35f37e8c23 autotools: link against libm with manually detected libxml2
Fixes build on QNX.
2019-11-30 20:36:34 +02:00
Michael Vetter
cbe6701c14 Add xmpp_stanza_get_child_by_name_and_ns()
I think it's fairly common in the XMPP world to actually want a stanza
by it's NS but also want a certain name.

For example this was needed in Profanity:
68af0aad65
2019-11-25 13:58:05 +00:00
Dmitry Podgorny
296df2fca9 tls/openssl: don't use deprecated function in 1.1.0+
SSLv23_client_method() was deprecated in OpenSSL 1.1.0. It is left as
macro to TLS_client_method.
2019-11-25 13:45:51 +00:00
Dmitry Podgorny
7caf88a6a8 rand: avoid VLA in xmpp_rand_nonce()
Don't use additional buffer. Instead, use half of the output buffer.
2019-11-19 01:46:35 +02:00
Dmitry Podgorny
ebaad72a35 ChangeLog: mention recent changes 2019-11-19 01:11:56 +02:00
François Revol
962bf4de5e Haiku: skip -Wextra -Wno-unused-parameter for GCC 2.95
This is needed to compile for the primary arch.
2019-11-17 15:34:27 +01:00
François Revol
884dace400 Haiku: link with libnetwork 2019-11-17 14:29:24 +01:00
François Revol
234bef4025 Haiku: C89 2019-11-17 14:28:26 +01:00
François Revol
45cbd51633 Haiku: fake va_copy for now 2019-11-17 14:21:37 +01:00
92 changed files with 7415 additions and 4596 deletions

11
.gitignore vendored
View File

@@ -1,4 +1,5 @@
*.swp
*.orig
Makefile
test-driver
.libs
@@ -34,6 +35,7 @@ examples/active
examples/basic
examples/bot
examples/component
examples/register
examples/roster
examples/uuid
examples/vcard
@@ -53,11 +55,18 @@ tests/test_resolver
tests/test_sasl
tests/test_scram
tests/test_sha1
tests/test_sha256
tests/test_sha512
tests/test_snprintf
tests/test_string
tests/test_sock
tests/test_stanza
tests/test_string
tests/test_xmppaddr
m4/
libstrophe.project
libs/
obj/
expat/
.settings/
.project
.cproject

View File

@@ -1,15 +1,26 @@
language: c
dist: focal
install:
- sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libc-ares-dev
before_script:
- ./bootstrap.sh
script:
- ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
- 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"
matrix:
fast_finish: true
- 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,42 @@
0.11.0
- SASL EXTERNAL support (XEP-0178)
- Client certificate can be provided for TLS negotiation. If the
certificate contains a single xmppAddr and JID is not provided with
xmpp_conn_set_jid(), the xmppAddr is chosen as JID
- <stream> element contains "from" attribute over TLS connections now
- GnuTLS can be selected optionally with configure script
- New API:
- xmpp_conn_set_client_cert()
- xmpp_conn_cert_xmppaddr_num()
- xmpp_conn_cert_xmppaddr()
0.10.1
- Fixed compilation error when LibreSSL is used
- Fixed crash when NULL is provided as password
0.10.0
- Coding style has been unified
- SCRAM-SHA-256 and SCRAM-SHA-512 support
- c-ares support
- LibreSSL support
- Introduced global timed handlers that fire periodically regardless of
connections status, such a handler can be used to implement deferred
re-connection
- examples/register implements XEP-0077
- Fixed issue with IPv6 on Windows (#153)
- Improved portability across systems such as Haiku, Windows
- New API:
- xmpp_stanza_get_child_by_name_and_ns()
- xmpp_conn_is_connecting()
- xmpp_conn_is_connected()
- xmpp_conn_is_disconnected()
- xmpp_stanza_new_from_string()
- xmpp_stanza_add_child_ex()
- xmpp_stanza_get_context()
- xmpp_stanza_reply_error()
- xmpp_global_timed_handler_add()
- xmpp_global_timed_handler_delete()
0.9.3
- PLAIN mechanism is used only when no other mechanisms are supported
- Legacy authentication is disabled by default, can be enabled with

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 0.9
PROJECT_NUMBER = 0.10
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -1047,7 +1047,7 @@ HTML_HEADER =
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER = docs/footer.html
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of

View File

@@ -5,13 +5,19 @@ ACLOCAL_AMFLAGS = -I m4
PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@
if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@
else
SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@
endif
RESOLV_CFLAGS = @RESOLV_CFLAGS@
RESOLV_LIBS = @RESOLV_LIBS@
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter
WARNING_FLAGS = @WARNING_FLAGS@
STROPHE_FLAGS = -I$(top_srcdir) $(WARNING_FLAGS)
STROPHE_LIBS = libstrophe.la
## Main build targets
@@ -37,6 +43,8 @@ libstrophe_la_SOURCES = \
src/sasl.c \
src/scram.c \
src/sha1.c \
src/sha256.c \
src/sha512.c \
src/snprintf.c \
src/sock.c \
src/stanza.c \
@@ -52,7 +60,10 @@ libstrophe_la_SOURCES += \
src/resolver.h \
src/sasl.h \
src/scram.h \
src/sha.h \
src/sha1.h \
src/sha256.h \
src/sha512.h \
src/snprintf.h \
src/sock.h \
src/tls.h \
@@ -61,8 +72,12 @@ libstrophe_la_SOURCES += \
if DISABLE_TLS
libstrophe_la_SOURCES += src/tls_dummy.c
else
if TLS_WITH_GNUTLS
libstrophe_la_SOURCES += src/tls_gnutls.c
else
libstrophe_la_SOURCES += src/tls_openssl.c
endif
endif
if PARSER_EXPAT
libstrophe_la_SOURCES += src/parser_expat.c
@@ -71,11 +86,11 @@ libstrophe_la_SOURCES += src/parser_libxml2.c
endif
include_HEADERS = strophe.h
noinst_HEADERS = strophepp.h
pkgconfig_DATA = libstrophe.pc
EXTRA_DIST = \
_clang-format \
Doxyfile \
GPL-LICENSE.txt \
LICENSE.txt \
@@ -86,12 +101,16 @@ EXTRA_DIST = \
examples/README.md \
jni/Android.mk \
jni/Application.mk \
rpm/README \
rpm/libstrophe.spec \
src/tls_gnutls.c \
src/tls_schannel.c \
src/tls_securetransport.c \
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 \
@@ -100,7 +119,8 @@ noinst_PROGRAMS = \
examples/component \
examples/roster \
examples/uuid \
examples/vcard
examples/vcard \
examples/register
examples_active_SOURCES = examples/active.c
examples_active_CFLAGS = $(STROPHE_FLAGS)
@@ -123,12 +143,17 @@ 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
TESTS = \
tests/check_parser \
tests/test_sha1 \
tests/test_sha256 \
tests/test_sha512 \
tests/test_md5 \
tests/test_rand \
tests/test_scram \
@@ -138,8 +163,13 @@ TESTS = \
tests/test_jid \
tests/test_snprintf \
tests/test_string \
tests/test_stanza \
tests/test_resolver
if !DISABLE_TLS
TESTS += tests/test_xmppaddr
endif
check_PROGRAMS = $(TESTS)
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
@@ -176,12 +206,19 @@ tests_test_resolver_LDFLAGS = -static
tests_test_rand_SOURCES = tests/test_rand.c tests/test.c src/sha1.c
tests_test_rand_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c
tests_test_scram_SOURCES = tests/test_scram.c tests/test.c src/sha1.c \
src/sha256.c src/sha512.c
tests_test_scram_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_sha1_SOURCES = tests/test_sha1.c src/sha1.c
tests_test_sha1_CFLAGS = -I$(top_srcdir)/src
tests_test_sha256_SOURCES = tests/test_sha256.c tests/test.c src/sha256.c
tests_test_sha256_CFLAGS = -I$(top_srcdir)/src
tests_test_sha512_SOURCES = tests/test_sha512.c tests/test.c src/sha512.c
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
@@ -192,3 +229,18 @@ tests_test_string_SOURCES = tests/test_string.c tests/test.h
tests_test_string_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_string_LDADD = $(STROPHE_LIBS)
tests_test_string_LDFLAGS = -static
tests_test_stanza_SOURCES = tests/test_stanza.c
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS)
tests_test_stanza_LDADD = $(STROPHE_LIBS)
tests_test_stanza_LDFLAGS = -static
tests_test_xmppaddr_SOURCES = tests/test_xmppaddr.c
tests_test_xmppaddr_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
tests_test_xmppaddr_LDADD = $(STROPHE_LIBS)
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

View File

@@ -5,11 +5,7 @@ libstrophe is a lightweight XMPP client library written in C. It has
minimal dependencies and is configurable for various environments. It
runs well on Linux, Unix and Windows based platforms.
Its goals are:
- usable quickly
- well documented
- reliable
libstrophe is dual licensed under MIT and GPLv3.
Build Instructions
------------------

17
_clang-format Normal file
View File

@@ -0,0 +1,17 @@
---
AlignConsecutiveAssignments: 'false'
AlignEscapedNewlines: Left
AllowShortBlocksOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: 'false'
BinPackParameters: 'false'
BreakBeforeBraces: Linux
ColumnLimit: '80'
DerivePointerAlignment: 'false'
IndentWidth: '4'
PointerAlignment: Right
SortIncludes: 'false'
TabWidth: '4'
UseTab: Never
...

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.9.3], [jack@metajack.im])
AC_INIT([libstrophe], [0.10.1], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen])
@@ -15,16 +15,39 @@ AS_CASE([$host_os],
[*nto*|*qnx*], [PLATFORM="qnx"],
[*solaris*], [PLATFORM="solaris"],
[*android*], [PLATFORM="android"],
[*haiku*], [PLATFORM="haiku"],
[PLATFORM="nix"])
WARNING_FLAGS="-Wall"
AS_CASE([$PLATFORM],
[haiku], [],
[WARNING_FLAGS="$WARNING_FLAGS -Wextra"])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_WITH([gnutls],
[AS_HELP_STRING([--with-gnutls], [use GnuTLS for TLS support, OpenSSL is the default])])
AC_ARG_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])])
if test "x$enable_tls" != xno; then
AC_SEARCH_LIBS([socket], [network socket])
AC_CHECK_FUNCS([snprintf vsnprintf])
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
PKG_CHECK_MODULES([gnutls], [gnutls],
[PC_REQUIRES="gnutls ${PC_REQUIRES}"],
[AC_CHECK_HEADER([gnutls/gnutls.h],
[
gnutls_LIBS="-lgnutls"
PC_LIBS="${gnutls_LIBS} ${PC_LIBS}"
],
[AC_MSG_ERROR([gnutls not found; gnutls required])]
)])
elif test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl],
[PC_REQUIRES="openssl ${PC_REQUIRES}"],
[AC_CHECK_HEADER([openssl/ssl.h],
@@ -64,7 +87,7 @@ if test "x$with_libxml2" != xno -a "x$with_parser" = x; then
[
with_parser="libxml2"
libxml2_CFLAGS="-I${includedir}/libxml2"
libxml2_LIBS="-lxml2"
libxml2_LIBS="-lxml2 -lm"
PC_LIBS="${libxml2_LIBS} ${PC_LIBS}"
PC_CFLAGS="${libxml2_CFLAGS} ${PC_CFLAGS}"
])
@@ -84,8 +107,6 @@ fi
AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
AC_SEARCH_LIBS([socket], [socket])
if test "x$enable_cares" = xyes; then
PKG_CHECK_MODULES([libcares], [libcares >= 1.7.0],
[
@@ -103,6 +124,7 @@ AS_CASE([$PLATFORM],
[qnx], [RESOLV_LIBS="-lsocket"],
[solaris], [RESOLV_LIBS="-lresolv -lsocket -lnsl"],
[android], [RESOLV_LIBS=""],
[haiku], [RESOLV_LIBS="-lnetwork"],
[RESOLV_LIBS="-lresolv"])
LIBS_TMP="${LIBS}"
@@ -135,6 +157,7 @@ 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([TLS_WITH_GNUTLS], [test x$with_gnutls = xyes])
AC_SUBST([PC_REQUIRES], [${PC_REQUIRES}])
AC_SUBST([PC_CFLAGS], [${PC_CFLAGS}])
@@ -144,5 +167,6 @@ AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS)
AC_SUBST(WARNING_FLAGS)
AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT

0
docs/.keep Normal file
View File

View File

@@ -1,2 +0,0 @@
</body>
</html>

View File

@@ -19,13 +19,13 @@
#include <strophe.h>
int handle_reply(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
int handle_reply(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *query, *item;
const char *type;
(void)userdata;
type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0)
fprintf(stderr, "ERROR: query failed\n");
@@ -44,13 +44,18 @@ int handle_reply(xmpp_conn_t * const conn,
return 0;
}
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
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;
xmpp_stanza_t *iq, *query;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n");

View File

@@ -10,6 +10,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strophe.h>
@@ -19,65 +20,97 @@
#define KA_INTERVAL 1
/* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
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");
xmpp_disconnect(conn);
}
else {
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
}
static void usage(int exit_code)
{
fprintf(stderr,
"Usage: basic [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.\n\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"
" --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, *pass, *host = NULL;
char *jid = NULL, *password = NULL, *cert = NULL, *key = NULL, *host = NULL;
long flags = 0;
int tcp_keepalive = 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], "--disable-tls") == 0)
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], "--tcp-keepalive") == 0)
tcp_keepalive = 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
break;
}
if ((argc - i) < 2 || (argc - i) > 3) {
fprintf(stderr, "Usage: basic [options] <jid> <pass> [<host>]\n\n"
"Options:\n"
" --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n"
" --legacy-ssl Use old style SSL.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
return 1;
if ((!jid && (!cert || !key)) || (argc - i) > 2) {
usage(1);
}
jid = argv[i];
pass = argv[i + 1];
if (i + 2 < argc)
host = argv[i + 2];
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
@@ -87,8 +120,9 @@ int main(int argc, char **argv)
/* init library */
xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log);
/* create a connection */
@@ -97,18 +131,25 @@ int main(int argc, char **argv)
/* 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);
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);
xmpp_conn_set_pass(conn, pass);
if (password)
xmpp_conn_set_pass(conn, password);
/* initiate connection */
xmpp_connect_client(conn, host, 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);
}
/* release our connection and context */
xmpp_conn_release(conn);

View File

@@ -22,8 +22,7 @@
#include <strophe.h>
int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *reply, *query, *name, *version, *text;
const char *ns;
@@ -69,8 +68,7 @@ int version_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
return 1;
}
int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata)
int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *body, *reply;
@@ -87,7 +85,8 @@ int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
intext = xmpp_stanza_get_text(body);
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza), intext);
printf("Incoming message from %s: %s\n", xmpp_stanza_get_from(stanza),
intext);
reply = xmpp_stanza_reply(stanza);
if (xmpp_stanza_get_type(reply) == NULL)
@@ -115,24 +114,29 @@ int message_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void
}
/* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
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;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) {
xmpp_stanza_t *pres;
fprintf(stderr, "DEBUG: connected\n");
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL, ctx);
xmpp_handler_add(conn, version_handler, "jabber:iq:version", "iq", NULL,
ctx);
xmpp_handler_add(conn, message_handler, NULL, "message", NULL, ctx);
/* Send initial <presence/> so that we appear online to contacts */
pres = xmpp_presence_new(ctx);
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
}
else {
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
@@ -157,8 +161,9 @@ int main(int argc, char **argv)
/* init library */
xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log);
/* create a connection */

View File

@@ -19,19 +19,22 @@
#include <strophe.h>
/* define a handler for connection events */
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
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;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n");
xmpp_disconnect(conn);
}
else {
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
@@ -67,8 +70,9 @@ int main(int argc, char **argv)
/* init library */
xmpp_initialize();
/* pass NULL instead to silence output */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
/* create a context */
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG); /* pass NULL instead to silence output */
ctx = xmpp_ctx_new(NULL, log);
/* create a connection */
@@ -94,4 +98,3 @@ int main(int argc, char **argv)
return 0;
}

363
examples/register.c Normal file
View File

@@ -0,0 +1,363 @@
/* register.c
* strophe XMPP client library -- In-band registration (XEP-0077)
*
* Copyright (C) 2020 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.
*/
/*
* This example uses a "raw" connection to establish connection to a server
* without account. Then it queries server to register new account according
* to XEP-0077.
*
* How to use it. After the application connects and receives instructions
* from the server, user will be prompted to type information such as
* username, password, etc. Press enter without typing if you want to skip
* a field and not to send it to the server.
*
* Notice, the example doesn't implement forms. Therefore, it won't work
* in complicated scenarios.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *jid;
} xmpp_reg_t;
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
static void
iq_reg_send_form(xmpp_reg_t *reg, xmpp_conn_t *conn, xmpp_stanza_t *stanza)
{
xmpp_ctx_t *ctx = reg->ctx;
xmpp_stanza_t *query;
xmpp_stanza_t *next;
xmpp_stanza_t *elem;
xmpp_stanza_t *text;
xmpp_stanza_t *iq;
const char *name;
size_t len;
char buf[256];
char *s;
query = xmpp_stanza_get_child_by_name(stanza, "query");
if (!query) {
xmpp_disconnect(conn);
return;
}
next = xmpp_stanza_get_children(query);
query = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_REGISTER);
while (next) {
name = xmpp_stanza_get_name(next);
if (name && strcmp(name, "instructions") == 0) {
s = xmpp_stanza_get_text(next);
printf("instructions: %s\n", s);
xmpp_free(ctx, s);
} else {
printf("%s: ", name);
s = fgets(buf, sizeof(buf), stdin);
if (s != NULL) {
len = strlen(s);
if (len > 0 && s[len - 1] == '\n') {
s[len - 1] = '\0';
--len;
}
if (len > 0) {
elem = xmpp_stanza_new(ctx);
text = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(text, s);
xmpp_stanza_set_name(elem, name);
xmpp_stanza_add_child(elem, text);
xmpp_stanza_add_child(query, elem);
xmpp_stanza_release(text);
xmpp_stanza_release(elem);
}
}
}
next = xmpp_stanza_get_next(next);
}
if (xmpp_stanza_get_children(query) == NULL) {
fprintf(stderr, "DEBUG: nothing to send\n");
xmpp_disconnect(conn);
} else {
iq = xmpp_iq_new(ctx, "set", "reg2");
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
}
}
static int iq_reg2_cb(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *type;
(void)userdata;
type = xmpp_stanza_get_type(stanza);
if (!type || strcmp(type, "error") == 0) {
fprintf(stderr, "DEBUG: error during registration\n");
goto quit;
}
if (strcmp(type, "result") != 0) {
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
goto quit;
}
fprintf(stderr, "DEBUG: successful registration\n");
quit:
xmpp_disconnect(conn);
return 0;
}
static int iq_reg_cb(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
xmpp_stanza_t *registered = NULL;
xmpp_stanza_t *query;
const char *type;
type = xmpp_stanza_get_type(stanza);
if (!type || strcmp(type, "error") == 0) {
fprintf(stderr, "DEBUG: error during registration\n");
xmpp_disconnect(conn);
goto quit;
}
if (strcmp(type, "result") != 0) {
fprintf(stderr, "DEBUG: expected type 'result', but got %s\n", type);
xmpp_disconnect(conn);
goto quit;
}
query = xmpp_stanza_get_child_by_name(stanza, "query");
if (query)
registered = xmpp_stanza_get_child_by_name(query, "registered");
if (registered != NULL) {
fprintf(stderr, "DEBUG: already registered\n");
xmpp_disconnect(conn);
goto quit;
}
xmpp_id_handler_add(conn, iq_reg2_cb, "reg2", reg);
iq_reg_send_form(reg, conn, stanza);
quit:
return 0;
}
static int
_handle_error(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
(void)stanza;
(void)userdata;
fprintf(stderr, "DEBUG: received stream error\n");
xmpp_disconnect(conn);
return 0;
}
static int _handle_proceedtls_default(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
const char *name = xmpp_stanza_get_name(stanza);
(void)userdata;
if (strcmp(name, "proceed") == 0) {
fprintf(stderr, "DEBUG: proceeding with TLS\n");
if (xmpp_conn_tls_start(conn) == 0) {
xmpp_handler_delete(conn, _handle_error);
xmpp_conn_open_stream_default(conn);
} else {
fprintf(stderr, "DEBUG: TLS failed\n");
/* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn);
}
}
return 0;
}
static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
fprintf(stderr, "DEBUG: timeout\n");
xmpp_disconnect(conn);
return 0;
}
static int
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
xmpp_ctx_t *ctx = reg->ctx;
xmpp_stanza_t *child;
xmpp_stanza_t *iq;
char *domain;
xmpp_timed_handler_delete(conn, _handle_missing_features);
/* secure connection if possible */
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
fprintf(stderr, "DEBUG: server supports TLS, try to establish\n");
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(child, "starttls");
xmpp_stanza_set_ns(child, XMPP_NS_TLS);
xmpp_handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL,
NULL, NULL);
xmpp_send(conn, child);
xmpp_stanza_release(child);
return 0;
}
/* check whether server supports in-band registration */
child = xmpp_stanza_get_child_by_name(stanza, "register");
if (child && strcmp(xmpp_stanza_get_ns(child), XMPP_NS_REGISTER) == 0) {
fprintf(stderr, "DEBUG: server doesn't support in-band registration\n");
xmpp_disconnect(conn);
return 0;
}
fprintf(stderr, "DEBUG: server supports in-band registration\n");
domain = xmpp_jid_domain(ctx, reg->jid);
iq = xmpp_iq_new(ctx, "get", "reg1");
xmpp_stanza_set_to(iq, domain);
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(child, "query");
xmpp_stanza_set_ns(child, XMPP_NS_REGISTER);
xmpp_stanza_add_child(iq, child);
xmpp_handler_add(conn, iq_reg_cb, XMPP_NS_REGISTER, "iq", NULL, reg);
xmpp_send(conn, iq);
xmpp_free(ctx, domain);
xmpp_stanza_release(child);
xmpp_stanza_release(iq);
return 0;
}
static void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *userdata)
{
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
int secured;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_RAW_CONNECT) {
fprintf(stderr, "DEBUG: raw connection established\n");
xmpp_conn_open_stream_default(conn);
} else if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: stream opened\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
/* setup handler for stream:error */
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL,
NULL);
/* setup handlers for incoming <stream:features> */
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS, "features",
NULL, reg);
xmpp_timed_handler_add(conn, _handle_missing_features, FEATURES_TIMEOUT,
NULL);
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(reg->ctx);
}
}
xmpp_reg_t *xmpp_reg_new(void)
{
xmpp_reg_t *reg;
reg = malloc(sizeof(*reg));
if (reg != NULL) {
memset(reg, 0, sizeof(*reg));
}
return reg;
}
void xmpp_reg_release(xmpp_reg_t *reg)
{
free(reg);
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
xmpp_reg_t *reg;
const char *jid;
const char *host = NULL;
char *domain;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: %s <jid> [<host>]\n", argv[0]);
return 1;
}
jid = argv[1];
if (argc > 2)
host = argv[2];
/*
* Note, this example doesn't handle errors. Applications should check
* return values of non-void functions.
*/
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
/* jid can be a jid or domain for "raw" connection */
domain = xmpp_jid_domain(ctx, jid);
xmpp_conn_set_jid(conn, domain);
xmpp_free(ctx, domain);
/* private data */
reg = xmpp_reg_new();
reg->ctx = ctx;
reg->jid = jid;
xmpp_connect_raw(conn, host, 0, conn_handler, reg);
xmpp_run(ctx);
/* release private data */
xmpp_reg_release(reg);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -18,13 +18,13 @@
#include <strophe.h>
int handle_reply(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
int handle_reply(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *query, *item;
const char *type, *name;
(void)userdata;
type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0)
fprintf(stderr, "ERROR: query failed\n");
@@ -34,13 +34,11 @@ int handle_reply(xmpp_conn_t * const conn,
for (item = xmpp_stanza_get_children(query); item;
item = xmpp_stanza_get_next(item))
if ((name = xmpp_stanza_get_attribute(item, "name")))
printf("\t %s (%s) sub=%s\n",
name,
printf("\t %s (%s) sub=%s\n", name,
xmpp_stanza_get_attribute(item, "jid"),
xmpp_stanza_get_attribute(item, "subscription"));
else
printf("\t %s sub=%s\n",
xmpp_stanza_get_attribute(item, "jid"),
printf("\t %s sub=%s\n", xmpp_stanza_get_attribute(item, "jid"),
xmpp_stanza_get_attribute(item, "subscription"));
printf("END OF LIST\n");
}
@@ -51,13 +49,18 @@ int handle_reply(xmpp_conn_t * const conn,
return 0;
}
void conn_handler(xmpp_conn_t * const conn, const xmpp_conn_event_t status,
const int error, xmpp_stream_error_t * const stream_error,
void * const userdata)
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;
xmpp_stanza_t *iq, *query;
(void)error;
(void)stream_error;
if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: connected\n");

View File

@@ -1,7 +1,7 @@
#include <stdio.h>
#include <strophe.h>
int main(int argc, char **argv)
int main()
{
xmpp_ctx_t *ctx;
char *uuid;

View File

@@ -76,8 +76,8 @@ static void vcard_photo(vcard_t *vc, xmpp_stanza_t *stanza)
xmpp_free(vc->ctx, img);
}
static void vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza,
const char *info)
static void
vcard_print_string(vcard_t *vc, xmpp_stanza_t *stanza, const char *info)
{
char *s = xmpp_stanza_get_text(stanza);
@@ -140,14 +140,9 @@ static vcard_cb_t vcard_cb_get(xmpp_stanza_t *stanza)
const char *tag;
vcard_cb_t cb;
} vcard_tbl[] = {
{ "PHOTO", vcard_photo },
{ "BDAY", vcard_bday },
{ "DESC", vcard_desc },
{ "EMAIL", vcard_email },
{ "FN", vcard_fn },
{ "N", vcard_name },
{ "NICKNAME", vcard_nick },
{ "URL", vcard_url },
{"PHOTO", vcard_photo}, {"BDAY", vcard_bday}, {"DESC", vcard_desc},
{"EMAIL", vcard_email}, {"FN", vcard_fn}, {"N", vcard_name},
{"NICKNAME", vcard_nick}, {"URL", vcard_url},
};
tag = xmpp_stanza_get_name(stanza);
@@ -165,16 +160,17 @@ exit:
return cb;
}
static int timedout(xmpp_conn_t * const conn, void * const userdata)
static int timedout(xmpp_conn_t *conn, void *userdata)
{
(void)userdata;
fprintf(stderr, "Timeout reached.\n");
xmpp_disconnect(conn);
return 0;
}
static int recv_vcard(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
void * const userdata)
static int recv_vcard(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
vcard_t *vc = userdata;
vcard_cb_t cb;
@@ -213,16 +209,17 @@ exit:
static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
{
printf("Requesting vCard from %s.\n", to);
xmpp_send_raw_string(conn, "<iq from='%s' to='%s' type='get' id='%s'>"
xmpp_send_raw_string(conn,
"<iq from='%s' to='%s' type='get' id='%s'>"
"<vCard xmlns='vcard-temp'/></iq>",
xmpp_conn_get_bound_jid(conn), to, id);
}
static void conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata)
static void conn_handler(xmpp_conn_t *conn,
xmpp_conn_event_t status,
int error,
xmpp_stream_error_t *stream_error,
void *userdata)
{
vcard_t *vc = userdata;
@@ -253,7 +250,8 @@ int main(int argc, char **argv)
if (argc < 4 || argc > 5) {
prog = argc > 0 ? strdup(argv[0]) : NULL;
printf("Usage: %s <login-jid> <password> <recipient-jid> "
"[image-file]\n\n", prog == NULL ? "vcard" : basename(prog));
"[image-file]\n\n",
prog == NULL ? "vcard" : basename(prog));
printf("If vCard contains a photo it will be stored to "
"image-file. If you don't provide the image-file "
"default filename will be generated.\n");
@@ -281,4 +279,3 @@ int main(int argc, char **argv)
return 0;
}

View File

@@ -23,7 +23,7 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE := libstrophe
LOCAL_CFLAGS :=
LOCAL_CFLAGS := -DHAVE_DECL_VA_COPY
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
$(LOCAL_PATH)/../src \
@@ -45,6 +45,8 @@ LOCAL_SRC_FILES := \
../src/sasl.c \
../src/scram.c \
../src/sha1.c \
../src/sha256.c \
../src/sha512.c \
../src/snprintf.c \
../src/sock.c \
../src/stanza.c \

View File

@@ -1,31 +0,0 @@
1. Setup
yum install gcc make autoconf automake expat-devel openssl-devel
Fedora:
yum install fedora-packager
cd ~
rpmdev-setuptree
CentOS:
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
Then make a tarball of sources:
tar czf libstrophe_git.tar.gz libstrophe
2. Build
cp libstrophe.spec ~/rpmbuild/SPECS
cp libstrophe_git.tar.gz ~/rpmbuild/SOURCES
rpmbuild -bb ~/rpmbuild/SPECS/libstrophe.spec
3. Install
yum localinstall ~/rpmbuild/RPMS/<arch>/libstrophe-1.1<dist>.<arch>.rpm
Or, if localinstall is not recognised:
rpm -i ~/rpmbuild/RPMS/<arch>/libstrophe-1.1<dist>.<arch>.rpm

View File

@@ -1,59 +0,0 @@
Name: libstrophe
Version: 1
Release: 1%{?dist}_git
Summary: xmpp library in C
Group: Application/System
License: MIT/GPLv3
URL: http://strophe.im/libstrophe/
Source0: libstrophe_git.tar.gz
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: openssl-devel
BuildRequires: expat-devel
Requires: openssl
Requires: expat
%description
XMPP library in C
%package devel
Summary: Headers and libraries for building apps that use libstrophe
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
%description devel
This package contains headers and libraries required to build applications that
use the strophe XMPP library.
%prep
%setup -n libstrophe
./bootstrap.sh
%build
%configure
make %{?_smp_mflags}
%install
make install DESTDIR=%{buildroot}
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files
%defattr(-,root,root,-)
%{_libdir}/libstrophe.so*
%doc
%files devel
%defattr(-,root,root,-)
%{_libdir}/libstrophe.a
%{_libdir}/libstrophe.la
%{_libdir}/pkgconfig/libstrophe.pc
%{_includedir}/strophe.h
%doc
%changelog

View File

@@ -24,7 +24,7 @@
#include "rand.h"
#ifdef _MSC_VER
#define strcasecmp stricmp
#define strcasecmp _stricmp
#endif
/* TODO: these should configurable at runtime on a per connection basis */
@@ -60,56 +60,49 @@
#define HANDSHAKE_TIMEOUT 15000 /* 15 seconds */
#endif
static void _auth(xmpp_conn_t * const conn);
static void _auth(xmpp_conn_t *conn);
static void _auth_legacy(xmpp_conn_t *conn);
static void _handle_open_sasl(xmpp_conn_t * const conn);
static void _handle_open_tls(xmpp_conn_t * const conn);
static void _handle_open_sasl(xmpp_conn_t *conn);
static void _handle_open_tls(xmpp_conn_t *conn);
static int _handle_component_auth(xmpp_conn_t * const conn);
static int _handle_component_hs_response(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_component_auth(xmpp_conn_t *conn);
static int _handle_component_hs_response(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata);
static int _handle_features_sasl(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_sasl_result(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn);
static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int
_handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata);
static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata);
static int _handle_scram_challenge(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata);
static char *_make_scram_init_msg(xmpp_conn_t *conn);
static int _handle_missing_features_sasl(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_missing_bind(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_bind(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_session(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_missing_session(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_missing_handshake(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata);
static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata);
static int
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int
_handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_missing_session(xmpp_conn_t *conn, void *userdata);
static int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata);
/* stream:error handler */
static int _handle_error(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_error(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *child;
const char *name;
UNUSED(userdata);
/* free old stream error if it's still there */
if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza);
@@ -119,7 +112,8 @@ static int _handle_error(xmpp_conn_t * const conn,
}
/* create stream error structure */
conn->stream_error = (xmpp_stream_error_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_stream_error_t));
conn->stream_error = (xmpp_stream_error_t *)xmpp_alloc(
conn->ctx, sizeof(xmpp_stream_error_t));
conn->stream_error->text = NULL;
conn->stream_error->type = XMPP_SE_UNDEFINED_CONDITION;
@@ -197,9 +191,10 @@ static int _handle_error(xmpp_conn_t * const conn,
}
/* stream:features handlers */
static int _handle_missing_features(xmpp_conn_t * const conn,
void * const userdata)
static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
{
UNUSED(userdata);
xmpp_debug(conn->ctx, "xmpp", "didn't get stream features");
/* legacy auth will be attempted */
@@ -208,16 +203,15 @@ static int _handle_missing_features(xmpp_conn_t * const conn,
return 0;
}
static int _handle_features(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *child, *mech;
const char *ns;
char *text;
UNUSED(userdata);
/* remove the handler that detects missing stream:features */
xmpp_timed_handler_delete(conn, _handle_missing_features);
@@ -240,17 +234,25 @@ static int _handle_features(xmpp_conn_t * const conn,
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) {
for (mech = xmpp_stanza_get_children(child); mech;
mech = xmpp_stanza_get_next(mech)) {
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
if (xmpp_stanza_get_name(mech) &&
strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
text = xmpp_stanza_get_text(mech);
if (text == NULL)
continue;
if (strcasecmp(text, "PLAIN") == 0)
conn->sasl_support |= SASL_MASK_PLAIN;
else if (strcasecmp(text, "EXTERNAL") == 0 &&
conn->tls_client_cert)
conn->sasl_support |= SASL_MASK_EXTERNAL;
else if (strcasecmp(text, "DIGEST-MD5") == 0)
conn->sasl_support |= SASL_MASK_DIGESTMD5;
else if (strcasecmp(text, "SCRAM-SHA-1") == 0)
conn->sasl_support |= SASL_MASK_SCRAMSHA1;
else if (strcasecmp(text, "SCRAM-SHA-256") == 0)
conn->sasl_support |= SASL_MASK_SCRAMSHA256;
else if (strcasecmp(text, "SCRAM-SHA-512") == 0)
conn->sasl_support |= SASL_MASK_SCRAMSHA512;
else if (strcasecmp(text, "ANONYMOUS") == 0)
conn->sasl_support |= SASL_MASK_ANONYMOUS;
@@ -270,25 +272,28 @@ static int _handle_features(xmpp_conn_t * const conn,
/* returns the correct auth id for a component or a client.
* returned string must be freed by caller */
static char *_get_authid(xmpp_conn_t * const conn)
static char *_get_authid(xmpp_conn_t *conn)
{
char *authid = NULL;
if (conn->type == XMPP_CLIENT) {
/* authid is the node portion of jid */
if (!conn->jid) return NULL;
if (!conn->jid)
return NULL;
authid = xmpp_jid_node(conn->ctx, conn->jid);
}
return authid;
}
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int _handle_proceedtls_default(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
const char *name;
UNUSED(userdata);
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp", "handle proceedtls called for %s", name);
@@ -307,9 +312,8 @@ static int _handle_proceedtls_default(xmpp_conn_t * const conn,
return 0;
}
static int _handle_sasl_result(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *name;
@@ -317,8 +321,7 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
/* the server should send a <success> or <failure> stanza */
if (strcmp(name, "failure") == 0) {
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed",
(char *)userdata);
xmpp_debug(conn->ctx, "xmpp", "SASL %s auth failed", (char *)userdata);
/* fall back to next auth method */
_auth(conn);
@@ -334,8 +337,9 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
conn_open_stream(conn);
} else {
/* got unexpected reply */
xmpp_error(conn->ctx, "xmpp", "Got unexpected reply to SASL %s"\
"authentication.", (char *)userdata);
xmpp_error(conn->ctx, "xmpp",
"Got unexpected reply to SASL %s authentication.",
(char *)userdata);
xmpp_disconnect(conn);
}
@@ -343,18 +347,20 @@ static int _handle_sasl_result(xmpp_conn_t * const conn,
}
/* handle the challenge phase of digest auth */
static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int _handle_digestmd5_challenge(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
char *text;
char *response;
xmpp_stanza_t *auth, *authdata;
const char *name;
UNUSED(userdata);
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",\
"handle digest-md5 (challenge) called for %s", name);
xmpp_debug(conn->ctx, "xmpp", "handle digest-md5 (challenge) called for %s",
name);
if (strcmp(name, "challenge") == 0) {
text = xmpp_stanza_get_text(stanza);
@@ -385,8 +391,8 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
handler_add(conn, _handle_digestmd5_rspauth,
XMPP_NS_SASL, NULL, NULL, NULL);
handler_add(conn, _handle_digestmd5_rspauth, XMPP_NS_SASL, NULL, NULL,
NULL);
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
@@ -400,17 +406,18 @@ static int _handle_digestmd5_challenge(xmpp_conn_t * const conn,
}
/* handle the rspauth phase of digest auth */
static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int _handle_digestmd5_rspauth(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
xmpp_stanza_t *auth;
const char *name;
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",
"handle digest-md5 (rspauth) called for %s", name);
UNUSED(userdata);
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp", "handle digest-md5 (rspauth) called for %s",
name);
if (strcmp(name, "challenge") == 0) {
/* assume it's an rspauth response */
@@ -430,21 +437,28 @@ static int _handle_digestmd5_rspauth(xmpp_conn_t * const conn,
return 1;
}
struct scram_user_data {
char *scram_init;
const struct hash_alg *alg;
};
/* handle the challenge phase of SCRAM-SHA-1 auth */
static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int _handle_scram_challenge(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
char *text;
char *response;
xmpp_stanza_t *auth, *authdata;
xmpp_stanza_t *auth;
xmpp_stanza_t *authdata;
const char *name;
char *challenge;
char *scram_init = (char *)userdata;
struct scram_user_data *scram_ctx = (struct scram_user_data *)userdata;
int rc;
name = xmpp_stanza_get_name(stanza);
xmpp_debug(conn->ctx, "xmpp",
"handle SCRAM-SHA-1 (challenge) called for %s", name);
xmpp_debug(conn->ctx, "xmpp", "handle %s (challenge) called for %s",
scram_ctx->alg->scram_name, name);
if (strcmp(name, "challenge") == 0) {
text = xmpp_stanza_get_text(stanza);
@@ -456,8 +470,8 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
if (!challenge)
goto err;
response = sasl_scram_sha1(conn->ctx, challenge, scram_init,
conn->jid, conn->pass);
response = sasl_scram(conn->ctx, scram_ctx->alg, challenge,
scram_ctx->scram_init, conn->jid, conn->pass);
xmpp_free(conn->ctx, challenge);
if (!response)
goto err;
@@ -480,24 +494,37 @@ static int _handle_scram_sha1_challenge(xmpp_conn_t * const conn,
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
rc = 1; /* Keep handler */
} else {
xmpp_free(conn->ctx, scram_init);
return _handle_sasl_result(conn, stanza, "SCRAM-SHA-1");
/*
* Free scram_ctx after calling _handle_sasl_result(). If authentication
* fails, we want to try other mechanism which may be different SCRAM
* mechanism. If we freed scram_ctx before the function, _auth() would
* be able to allocate new scram_ctx object with the same address and
* handler_add() would consider new SCRAM handler as duplicate, because
* current handler is not removed yet. As result, libstrophe wouldn't
* handle incoming challenge stanza.
*/
rc = _handle_sasl_result(conn, stanza,
(void *)scram_ctx->alg->scram_name);
xmpp_free(conn->ctx, scram_ctx->scram_init);
xmpp_free(conn->ctx, scram_ctx);
}
return 1;
return rc;
err_release_auth:
xmpp_stanza_release(auth);
err_free_response:
xmpp_free(conn->ctx, response);
err:
xmpp_free(conn->ctx, scram_init);
xmpp_free(conn->ctx, scram_ctx->scram_init);
xmpp_free(conn->ctx, scram_ctx);
disconnect_mem_error(conn);
return 0;
}
static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
static char *_make_scram_init_msg(xmpp_conn_t *conn)
{
xmpp_ctx_t *ctx = conn->ctx;
size_t message_len;
@@ -520,7 +547,7 @@ static char *_make_scram_sha1_init_msg(xmpp_conn_t * const conn)
return message;
}
static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn)
static xmpp_stanza_t *_make_starttls(xmpp_conn_t *conn)
{
xmpp_stanza_t *starttls;
@@ -534,8 +561,7 @@ static xmpp_stanza_t *_make_starttls(xmpp_conn_t * const conn)
return starttls;
}
static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
const char * const mechanism)
static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t *conn, const char *mechanism)
{
xmpp_stanza_t *auth;
@@ -555,12 +581,12 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
* this will get called again until one auth method succeeds or every
* method fails
*/
static void _auth(xmpp_conn_t * const conn)
static void _auth(xmpp_conn_t *conn)
{
xmpp_stanza_t *auth;
xmpp_stanza_t *authdata;
struct scram_user_data *scram_ctx;
char *authid;
char *scram_init;
char *str;
int anonjid;
@@ -592,8 +618,8 @@ static void _auth(xmpp_conn_t * const conn)
return;
}
handler_add(conn, _handle_proceedtls_default,
XMPP_NS_TLS, NULL, NULL, NULL);
handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL, NULL,
NULL);
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
@@ -605,7 +631,8 @@ static void _auth(xmpp_conn_t * const conn)
}
if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) {
xmpp_error(conn->ctx, "xmpp", "TLS is not supported, but set as "
xmpp_error(conn->ctx, "xmpp",
"TLS is not supported, but set as "
"mandatory for this connection");
conn_disconnect(conn);
return;
@@ -619,37 +646,94 @@ static void _auth(xmpp_conn_t * const conn)
return;
}
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL,
NULL, NULL, "ANONYMOUS");
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"ANONYMOUS");
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
/* SASL ANONYMOUS was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_ANONYMOUS;
} else if (conn->sasl_support & SASL_MASK_EXTERNAL) {
/* more crap here */
auth = _make_sasl_auth(conn, "EXTERNAL");
if (!auth) {
disconnect_mem_error(conn);
return;
}
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) {
xmpp_stanza_release(auth);
disconnect_mem_error(conn);
return;
}
str = tls_id_on_xmppaddr(conn, 0);
if (!str || (tls_id_on_xmppaddr_num(conn) == 1 &&
strcmp(str, conn->jid) == 0)) {
xmpp_stanza_set_text(authdata, "=");
} else {
xmpp_free(conn->ctx, str);
str = xmpp_base64_encode(conn->ctx, (void *)conn->jid,
strlen(conn->jid));
if (!str) {
xmpp_stanza_release(authdata);
xmpp_stanza_release(auth);
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_text(authdata, str);
}
xmpp_free(conn->ctx, str);
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"EXTERNAL");
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
/* SASL EXTERNAL was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_EXTERNAL;
} else if (anonjid) {
xmpp_error(conn->ctx, "auth",
"No node in JID, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAMSHA1) {
auth = _make_sasl_auth(conn, "SCRAM-SHA-1");
} else if (conn->pass == NULL) {
xmpp_error(conn->ctx, "auth",
"Password hasn't been set, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAM) {
scram_ctx = xmpp_alloc(conn->ctx, sizeof(*scram_ctx));
if (conn->sasl_support & SASL_MASK_SCRAMSHA512)
scram_ctx->alg = &scram_sha512;
else if (conn->sasl_support & SASL_MASK_SCRAMSHA256)
scram_ctx->alg = &scram_sha256;
else if (conn->sasl_support & SASL_MASK_SCRAMSHA1)
scram_ctx->alg = &scram_sha1;
auth = _make_sasl_auth(conn, scram_ctx->alg->scram_name);
if (!auth) {
disconnect_mem_error(conn);
return;
}
/* don't free scram_init on success */
scram_init = _make_scram_sha1_init_msg(conn);
if (!scram_init) {
scram_ctx->scram_init = _make_scram_init_msg(conn);
if (!scram_ctx->scram_init) {
xmpp_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth);
disconnect_mem_error(conn);
return;
}
str = xmpp_base64_encode(conn->ctx, (unsigned char *)scram_init,
strlen(scram_init));
str = xmpp_base64_encode(conn->ctx,
(unsigned char *)scram_ctx->scram_init,
strlen(scram_ctx->scram_init));
if (!str) {
xmpp_free(conn->ctx, scram_init);
xmpp_free(conn->ctx, scram_ctx->scram_init);
xmpp_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth);
disconnect_mem_error(conn);
return;
@@ -658,7 +742,8 @@ static void _auth(xmpp_conn_t * const conn)
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) {
xmpp_free(conn->ctx, str);
xmpp_free(conn->ctx, scram_init);
xmpp_free(conn->ctx, scram_ctx->scram_init);
xmpp_free(conn->ctx, scram_ctx);
xmpp_stanza_release(auth);
disconnect_mem_error(conn);
return;
@@ -668,24 +753,23 @@ static void _auth(xmpp_conn_t * const conn)
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
handler_add(conn, _handle_scram_sha1_challenge,
XMPP_NS_SASL, NULL, NULL, (void *)scram_init);
handler_add(conn, _handle_scram_challenge, XMPP_NS_SASL, NULL, NULL,
(void *)scram_ctx);
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
/* SASL SCRAM-SHA-1 was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_SCRAMSHA1;
conn->sasl_support &= ~scram_ctx->alg->mask;
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) {
auth = _make_sasl_auth(conn, "DIGEST-MD5");
if (!auth) {
disconnect_mem_error(conn);
return;
}
handler_add(conn, _handle_digestmd5_challenge,
XMPP_NS_SASL, NULL, NULL, NULL);
handler_add(conn, _handle_digestmd5_challenge, XMPP_NS_SASL, NULL, NULL,
NULL);
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
@@ -720,8 +804,8 @@ static void _auth(xmpp_conn_t * const conn)
xmpp_stanza_add_child(auth, authdata);
xmpp_stanza_release(authdata);
handler_add(conn, _handle_sasl_result,
XMPP_NS_SASL, NULL, NULL, "PLAIN");
handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL,
"PLAIN");
xmpp_send(conn, auth);
xmpp_stanza_release(auth);
@@ -737,7 +821,6 @@ static void _auth(xmpp_conn_t * const conn)
}
}
/** Set up handlers at stream start.
* This function is called internally to Strophe for handling the opening
* of an XMPP stream. It's called by the parser when a stream is opened
@@ -747,7 +830,7 @@ static void _auth(xmpp_conn_t * const conn)
*
* @param conn a Strophe connection object
*/
void auth_handle_open(xmpp_conn_t * const conn)
void auth_handle_open(xmpp_conn_t *conn)
{
/* reset all timed handlers */
handler_reset_timed(conn, 0);
@@ -757,40 +840,41 @@ void auth_handle_open(xmpp_conn_t * const conn)
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
/* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features,
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add(conn, _handle_features, XMPP_NS_STREAMS, "features", NULL,
NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
/* called when stream:stream tag received after TLS establishment */
static void _handle_open_tls(xmpp_conn_t * const conn)
static void _handle_open_tls(xmpp_conn_t *conn)
{
/* setup handlers for incoming <stream:features> */
handler_add(conn, _handle_features,
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add(conn, _handle_features, XMPP_NS_STREAMS, "features", NULL,
NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}
/* called when stream:stream tag received after SASL auth */
static void _handle_open_sasl(xmpp_conn_t * const conn)
static void _handle_open_sasl(xmpp_conn_t *conn)
{
xmpp_debug(conn->ctx, "xmpp", "Reopened stream successfully.");
/* setup stream:features handlers */
handler_add(conn, _handle_features_sasl,
XMPP_NS_STREAMS, "features", NULL, NULL);
handler_add_timed(conn, _handle_missing_features_sasl,
FEATURES_TIMEOUT, NULL);
handler_add(conn, _handle_features_sasl, XMPP_NS_STREAMS, "features", NULL,
NULL);
handler_add_timed(conn, _handle_missing_features_sasl, FEATURES_TIMEOUT,
NULL);
}
static int _handle_features_sasl(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *bind, *session, *iq, *res, *text, *opt;
const char *ns;
char *resource;
UNUSED(userdata);
/* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
@@ -810,8 +894,8 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
ns = xmpp_stanza_get_ns(session);
opt = xmpp_stanza_get_child_by_name(session, "optional");
if (!opt)
conn->session_required = ns != NULL &&
strcmp(ns, XMPP_NS_SESSION) == 0;
conn->session_required =
ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
}
/* if bind is required, go ahead and start it */
@@ -820,8 +904,7 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
/* setup response handlers */
handler_add_id(conn, _handle_bind, "_xmpp_bind1", NULL);
handler_add_timed(conn, _handle_missing_bind,
BIND_TIMEOUT, NULL);
handler_add_timed(conn, _handle_missing_bind, BIND_TIMEOUT, NULL);
/* send bind request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_bind1");
@@ -880,7 +963,8 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
xmpp_stanza_release(iq);
} else {
/* can't bind, disconnect */
xmpp_error(conn->ctx, "xmpp", "Stream features does not allow "\
xmpp_error(conn->ctx, "xmpp",
"Stream features does not allow "
"resource bind.");
xmpp_disconnect(conn);
}
@@ -888,22 +972,25 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
return 0;
}
static int _handle_missing_features_sasl(xmpp_conn_t * const conn,
void * const userdata)
static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
{
xmpp_error(conn->ctx, "xmpp", "Did not receive stream features "\
UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp",
"Did not receive stream features "
"after SASL authentication.");
xmpp_disconnect(conn);
return 0;
}
static int _handle_bind(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *type;
xmpp_stanza_t *iq, *session;
UNUSED(userdata);
/* delete missing bind handler */
xmpp_timed_handler_delete(conn, _handle_missing_bind);
@@ -917,8 +1004,8 @@ static int _handle_bind(xmpp_conn_t * const conn,
xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
if (binding) {
xmpp_stanza_t *jid_stanza = xmpp_stanza_get_child_by_name(binding,
"jid");
xmpp_stanza_t *jid_stanza =
xmpp_stanza_get_child_by_name(binding, "jid");
if (jid_stanza) {
conn->bound_jid = xmpp_stanza_get_text(jid_stanza);
}
@@ -928,8 +1015,8 @@ static int _handle_bind(xmpp_conn_t * const conn,
if (conn->session_required) {
/* setup response handlers */
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
handler_add_timed(conn, _handle_missing_session,
SESSION_TIMEOUT, NULL);
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT,
NULL);
/* send session request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
@@ -969,20 +1056,22 @@ static int _handle_bind(xmpp_conn_t * const conn,
return 0;
}
static int _handle_missing_bind(xmpp_conn_t * const conn,
void * const userdata)
static int _handle_missing_bind(xmpp_conn_t *conn, void *userdata)
{
UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp", "Server did not reply to bind request.");
xmpp_disconnect(conn);
return 0;
}
static int _handle_session(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *type;
UNUSED(userdata);
/* delete missing session handler */
xmpp_timed_handler_delete(conn, _handle_missing_session);
@@ -1006,30 +1095,34 @@ static int _handle_session(xmpp_conn_t * const conn,
return 0;
}
static int _handle_missing_session(xmpp_conn_t * const conn,
void * const userdata)
static int _handle_missing_session(xmpp_conn_t *conn, void *userdata)
{
UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp", "Server did not reply to session request.");
xmpp_disconnect(conn);
return 0;
}
static int _handle_missing_legacy(xmpp_conn_t * const conn,
void * const userdata)
static int _handle_missing_legacy(xmpp_conn_t *conn, void *userdata)
{
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp",
"Server did not reply to legacy "
"authentication request.");
xmpp_disconnect(conn);
return 0;
}
static int _handle_legacy(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
static int
_handle_legacy(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
const char *type;
const char *name;
UNUSED(userdata);
/* delete missing handler */
xmpp_timed_handler_delete(conn, _handle_missing_legacy);
@@ -1037,7 +1130,8 @@ static int _handle_legacy(xmpp_conn_t * const conn,
type = xmpp_stanza_get_type(stanza);
name = xmpp_stanza_get_name(stanza);
if (!type || strcmp(name, "iq") != 0) {
xmpp_error(conn->ctx, "xmpp", "Server sent us an unexpected response "\
xmpp_error(conn->ctx, "xmpp",
"Server sent us an unexpected response "
"to legacy authentication request.");
xmpp_disconnect(conn);
} else if (strcmp(type, "error") == 0) {
@@ -1051,7 +1145,8 @@ static int _handle_legacy(xmpp_conn_t * const conn,
conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} else {
xmpp_error(conn->ctx, "xmpp", "Server sent us a legacy authentication "\
xmpp_error(conn->ctx, "xmpp",
"Server sent us a legacy authentication "
"response with a bad type.");
xmpp_disconnect(conn);
}
@@ -1152,7 +1247,7 @@ err:
disconnect_mem_error(conn);
}
void auth_handle_component_open(xmpp_conn_t * const conn)
void auth_handle_component_open(xmpp_conn_t *conn)
{
int rc;
@@ -1160,8 +1255,8 @@ void auth_handle_component_open(xmpp_conn_t * const conn)
handler_reset_timed(conn, 0);
handler_add(conn, _handle_error, XMPP_NS_STREAMS, "error", NULL, NULL);
handler_add(conn, _handle_component_hs_response, NULL,
"handshake", NULL, NULL);
handler_add(conn, _handle_component_hs_response, NULL, "handshake", NULL,
NULL);
handler_add_timed(conn, _handle_missing_handshake, HANDSHAKE_TIMEOUT, NULL);
rc = _handle_component_auth(conn);
@@ -1172,7 +1267,7 @@ void auth_handle_component_open(xmpp_conn_t * const conn)
}
/* Will compute SHA1 and authenticate the component to the server */
int _handle_component_auth(xmpp_conn_t * const conn)
int _handle_component_auth(xmpp_conn_t *conn)
{
uint8_t md_value[SHA1_DIGEST_SIZE];
SHA1_CTX mdctx;
@@ -1200,16 +1295,18 @@ int _handle_component_auth(xmpp_conn_t * const conn)
xmpp_snprintf(digest + i * 2, 3, "%02x", md_value[i]);
digest[2 * sizeof(md_value)] = '\0';
xmpp_debug(conn->ctx, "auth", "Digest: %s, len: %d",
digest, strlen(digest));
xmpp_debug(conn->ctx, "auth", "Digest: %s, len: %d", digest,
strlen(digest));
/* Send the digest to the server */
xmpp_send_raw_string(conn, "<handshake xmlns='%s'>%s</handshake>",
XMPP_NS_COMPONENT, digest);
xmpp_debug(conn->ctx, "auth", "Sent component handshake to the server.");
xmpp_debug(conn->ctx, "auth",
"Sent component handshake to the server.");
xmpp_free(conn->ctx, digest);
} else {
xmpp_debug(conn->ctx, "auth", "Couldn't allocate memory for component "\
xmpp_debug(conn->ctx, "auth",
"Couldn't allocate memory for component "
"handshake digest.");
return XMPP_EMEM;
}
@@ -1220,12 +1317,14 @@ int _handle_component_auth(xmpp_conn_t * const conn)
/* Check if the received stanza is <handshake/> and set auth to true
* and fire connection handler.
*/
int _handle_component_hs_response(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
int _handle_component_hs_response(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
const char *name;
UNUSED(userdata);
xmpp_timed_handler_delete(conn, _handle_missing_handshake);
name = xmpp_stanza_get_name(stanza);
@@ -1250,14 +1349,16 @@ int _handle_component_hs_response(xmpp_conn_t * const conn,
return 0;
}
int _handle_missing_handshake(xmpp_conn_t * const conn, void * const userdata)
int _handle_missing_handshake(xmpp_conn_t *conn, void *userdata)
{
UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp", "Server did not reply to handshake request.");
xmpp_disconnect(conn);
return 0;
}
void auth_handle_open_raw(xmpp_conn_t * const conn)
void auth_handle_open_raw(xmpp_conn_t *conn)
{
handler_reset_timed(conn, 0);
/* user handlers are not called before authentication is completed. */
@@ -1265,7 +1366,7 @@ void auth_handle_open_raw(xmpp_conn_t * const conn)
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
}
void auth_handle_open_stub(xmpp_conn_t * const conn)
void auth_handle_open_stub(xmpp_conn_t *conn)
{
xmpp_warn(conn->ctx, "auth", "Stub callback is called.");
}

View File

@@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdarg.h>
#include "strophe.h"
#include "ostypes.h"
#include "sock.h"
@@ -30,78 +29,7 @@
#include "rand.h"
#include "snprintf.h"
/** run-time context **/
typedef enum {
XMPP_LOOP_NOTSTARTED,
XMPP_LOOP_RUNNING,
XMPP_LOOP_QUIT
} xmpp_loop_status_t;
typedef struct _xmpp_connlist_t {
xmpp_conn_t *conn;
struct _xmpp_connlist_t *next;
} xmpp_connlist_t;
struct _xmpp_ctx_t {
const xmpp_mem_t *mem;
const xmpp_log_t *log;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist;
unsigned long timeout;
};
/* convenience functions for accessing the context */
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size);
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size);
char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s);
void xmpp_log(const xmpp_ctx_t * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
va_list ap);
/* wrappers for xmpp_log at specific levels */
void xmpp_error(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
void xmpp_warn(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
void xmpp_info(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...);
/** connection **/
/* opaque connection object */
typedef enum {
XMPP_STATE_DISCONNECTED,
XMPP_STATE_CONNECTING,
XMPP_STATE_CONNECTED
} xmpp_conn_state_t;
typedef struct _xmpp_send_queue_t xmpp_send_queue_t;
struct _xmpp_send_queue_t {
char *data;
size_t len;
size_t written;
xmpp_send_queue_t *next;
};
/** handlers **/
typedef struct _xmpp_handlist_t xmpp_handlist_t;
struct _xmpp_handlist_t {
@@ -130,15 +58,83 @@ struct _xmpp_handlist_t {
char *name;
char *type;
};
} u;
};
/** run-time context **/
typedef enum {
XMPP_LOOP_NOTSTARTED,
XMPP_LOOP_RUNNING,
XMPP_LOOP_QUIT
} xmpp_loop_status_t;
typedef struct _xmpp_connlist_t {
xmpp_conn_t *conn;
struct _xmpp_connlist_t *next;
} xmpp_connlist_t;
struct _xmpp_ctx_t {
const xmpp_mem_t *mem;
const xmpp_log_t *log;
xmpp_rand_t *rand;
xmpp_loop_status_t loop_status;
xmpp_connlist_t *connlist;
xmpp_handlist_t *timed_handlers;
unsigned long timeout;
};
/* 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);
void xmpp_log(const xmpp_ctx_t *ctx,
const xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap);
/* wrappers for xmpp_log at specific levels */
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
/** connection **/
/* opaque connection object */
typedef enum {
XMPP_STATE_DISCONNECTED,
XMPP_STATE_CONNECTING,
XMPP_STATE_CONNECTED
} xmpp_conn_state_t;
typedef struct _xmpp_send_queue_t xmpp_send_queue_t;
struct _xmpp_send_queue_t {
char *data;
size_t len;
size_t written;
xmpp_send_queue_t *next;
};
#define UNUSED(x) ((void)(x))
#define MAX_DOMAIN_LEN 256
#define SASL_MASK_PLAIN (1 << 0)
#define SASL_MASK_DIGESTMD5 (1 << 1)
#define SASL_MASK_ANONYMOUS (1 << 2)
#define SASL_MASK_SCRAMSHA1 (1 << 3)
#define SASL_MASK_SCRAMSHA256 (1 << 4)
#define SASL_MASK_SCRAMSHA512 (1 << 5)
#define SASL_MASK_EXTERNAL (1 << 6)
#define SASL_MASK_SCRAM \
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
enum {
XMPP_PORT_CLIENT = 5222,
@@ -146,7 +142,7 @@ enum {
XMPP_PORT_COMPONENT = 5347,
};
typedef void (*xmpp_open_handler)(xmpp_conn_t * const conn);
typedef void (*xmpp_open_handler)(xmpp_conn_t *conn);
struct _xmpp_conn_t {
unsigned int ref;
@@ -160,7 +156,6 @@ struct _xmpp_conn_t {
xmpp_stream_error_t *stream_error;
sock_t sock;
xmpp_sock_t *xsock;
int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */
@@ -170,6 +165,8 @@ struct _xmpp_conn_t {
int tls_mandatory;
int tls_legacy_ssl;
int tls_trust;
char *tls_client_cert;
char *tls_client_key;
int tls_failed; /* set when tls fails, so we don't try again */
int sasl_support; /* if true, field is a bitfield of supported
mechanisms */
@@ -219,14 +216,13 @@ struct _xmpp_conn_t {
xmpp_handlist_t *handlers;
};
void conn_disconnect(xmpp_conn_t * const conn);
void conn_disconnect_clean(xmpp_conn_t * const conn);
void conn_established(xmpp_conn_t * const conn);
void conn_open_stream(xmpp_conn_t * const conn);
int conn_tls_start(xmpp_conn_t * const conn);
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler);
void conn_parser_reset(xmpp_conn_t * const conn);
void conn_disconnect(xmpp_conn_t *conn);
void conn_disconnect_clean(xmpp_conn_t *conn);
void conn_established(xmpp_conn_t *conn);
void conn_open_stream(xmpp_conn_t *conn);
int conn_tls_start(xmpp_conn_t *conn);
void conn_prepare_reset(xmpp_conn_t *conn, xmpp_open_handler handler);
void conn_parser_reset(xmpp_conn_t *conn);
typedef enum {
XMPP_STANZA_UNKNOWN,
@@ -251,33 +247,32 @@ struct _xmpp_stanza_t {
};
/* handler management */
void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza);
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx);
void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza);
uint64_t handler_fire_timed(xmpp_ctx_t *ctx);
void handler_reset_timed(xmpp_conn_t *conn, int user_only);
void handler_add_timed(xmpp_conn_t * const conn,
void handler_add_timed(xmpp_conn_t *conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
void handler_add_id(xmpp_conn_t * const conn,
unsigned long period,
void *userdata);
void handler_add_id(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id,
void * const userdata);
void handler_add(xmpp_conn_t * const conn,
const char *id,
void *userdata);
void handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
const char *ns,
const char *name,
const char *type,
void *userdata);
void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */
void disconnect_mem_error(xmpp_conn_t * const conn);
void disconnect_mem_error(xmpp_conn_t *conn);
/* auth functions */
void auth_handle_open(xmpp_conn_t * const conn);
void auth_handle_component_open(xmpp_conn_t * const conn);
void auth_handle_open_raw(xmpp_conn_t * const conn);
void auth_handle_open_stub(xmpp_conn_t * const conn);
void auth_handle_open(xmpp_conn_t *conn);
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);
#endif /* __LIBSTROPHE_COMMON_H__ */

View File

@@ -48,32 +48,35 @@
#define CONNECT_TIMEOUT 5000 /* 5 seconds */
#endif
static int _disconnect_cleanup(xmpp_conn_t * const conn,
void * const userdata);
static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
char **attributes, size_t attributes_len);
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
char ***attributes, size_t *attributes_len);
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata);
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len);
static void _handle_stream_start(char *name, char **attrs,
void * const userdata);
static void _handle_stream_end(char *name,
void * const userdata);
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
void * const userdata);
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
static int _conn_open_stream_with_attributes(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len);
static void _conn_attributes_new(xmpp_conn_t *conn,
char **attrs,
char ***attributes,
size_t *attributes_len);
static void _conn_attributes_destroy(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len);
static void _handle_stream_start(char *name, char **attrs, void *userdata);
static void _handle_stream_end(char *name, void *userdata);
static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *userdata);
static unsigned short _conn_default_port(xmpp_conn_t *conn,
xmpp_conn_type_t type);
static void _conn_reset(xmpp_conn_t * const conn);
static int _conn_connect(xmpp_conn_t * const conn,
const char * const domain,
const char * const host,
static void _conn_reset(xmpp_conn_t *conn);
static int _conn_connect(xmpp_conn_t *conn,
const char *domain,
const char *host,
unsigned short port,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void * const userdata);
void *userdata);
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text)
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text)
{
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
@@ -90,12 +93,13 @@ void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, cha
*
* @ingroup Connections
*/
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
{
xmpp_conn_t *conn = NULL;
xmpp_connlist_t *tail, *item;
if (ctx == NULL) return NULL;
if (ctx == NULL)
return NULL;
conn = xmpp_alloc(ctx, sizeof(xmpp_conn_t));
if (conn != NULL) {
@@ -139,6 +143,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
conn->tls_legacy_ssl = 0;
conn->tls_trust = 0;
conn->tls_failed = 0;
conn->tls_client_cert = NULL;
conn->tls_client_key = NULL;
conn->sasl_support = 0;
conn->auth_legacy_enabled = 0;
conn->secured = 0;
@@ -146,11 +152,9 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
conn->bind_required = 0;
conn->session_required = 0;
conn->parser = parser_new(conn->ctx,
_handle_stream_start,
_handle_stream_end,
_handle_stream_stanza,
conn);
conn->parser =
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
_handle_stream_stanza, conn);
conn->reset_parser = 0;
conn->authenticated = 0;
@@ -166,7 +170,8 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
/* add connection to ctx->connlist */
tail = conn->ctx->connlist;
while (tail && tail->next) tail = tail->next;
while (tail && tail->next)
tail = tail->next;
item = xmpp_alloc(conn->ctx, sizeof(xmpp_connlist_t));
if (!item) {
@@ -179,8 +184,10 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
item->conn = conn;
item->next = NULL;
if (tail) tail->next = item;
else conn->ctx->connlist = item;
if (tail)
tail->next = item;
else
conn->ctx->connlist = item;
}
}
@@ -196,7 +203,7 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
*
* @ingroup Connections
*/
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn)
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn)
{
conn->ref++;
return conn;
@@ -214,7 +221,7 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval)
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
{
int ret = 0;
@@ -240,7 +247,7 @@ void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval
*
* @ingroup Connections
*/
int xmpp_conn_release(xmpp_conn_t * const conn)
int xmpp_conn_release(xmpp_conn_t *conn)
{
xmpp_ctx_t *ctx;
xmpp_connlist_t *item, *prev;
@@ -254,6 +261,11 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
else {
ctx = conn->ctx;
if (conn->state == XMPP_STATE_CONNECTING ||
conn->state == XMPP_STATE_CONNECTED) {
conn_disconnect(conn);
}
/* remove connection from context's connlist */
if (ctx->connlist->conn == conn) {
item = ctx->connlist;
@@ -299,7 +311,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
while (hlitem) {
thli = hlitem;
hlitem = hlitem->next;
xmpp_free(conn->ctx, thli->id);
xmpp_free(conn->ctx, thli->u.id);
xmpp_free(conn->ctx, thli);
}
}
@@ -311,17 +323,27 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
thli = hlitem;
hlitem = hlitem->next;
if (thli->ns) xmpp_free(ctx, thli->ns);
if (thli->name) xmpp_free(ctx, thli->name);
if (thli->type) xmpp_free(ctx, thli->type);
if (thli->u.ns)
xmpp_free(ctx, thli->u.ns);
if (thli->u.name)
xmpp_free(ctx, thli->u.name);
if (thli->u.type)
xmpp_free(ctx, thli->u.type);
xmpp_free(ctx, thli);
}
parser_free(conn->parser);
if (conn->jid) xmpp_free(ctx, conn->jid);
if (conn->pass) xmpp_free(ctx, conn->pass);
if (conn->lang) xmpp_free(ctx, conn->lang);
if (conn->jid)
xmpp_free(ctx, conn->jid);
if (conn->pass)
xmpp_free(ctx, conn->pass);
if (conn->lang)
xmpp_free(ctx, conn->lang);
if (conn->tls_client_cert)
xmpp_free(ctx, conn->tls_client_cert);
if (conn->tls_client_key)
xmpp_free(ctx, conn->tls_client_key);
xmpp_free(ctx, conn);
released = 1;
}
@@ -337,7 +359,7 @@ int xmpp_conn_release(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn)
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn)
{
return conn->jid;
}
@@ -355,7 +377,7 @@ const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn)
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn)
{
return conn->bound_jid;
}
@@ -371,12 +393,65 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid)
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
if (conn->jid) xmpp_free(conn->ctx, conn->jid);
if (conn->jid)
xmpp_free(conn->ctx, conn->jid);
conn->jid = xmpp_strdup(conn->ctx, jid);
}
/** Set the Client Certificate and Private Key that will be bound to the
* connection. If any of the both was previously set, it will be discarded.
* This should not be used after a connection is created. The function will
* make a copy of the strings passed in.
* Currently only non-encrypted Private Keys are supported.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file
* @param key path to a private key file
*
* @ingroup Connections
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
xmpp_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (conn->tls_client_cert)
xmpp_free(conn->ctx, conn->tls_client_cert);
conn->tls_client_cert = xmpp_strdup(conn->ctx, cert);
if (conn->tls_client_key)
xmpp_free(conn->ctx, conn->tls_client_key);
conn->tls_client_key = xmpp_strdup(conn->ctx, key);
}
/** Get the number of xmppAddr entries in the client certificate.
*
* @param conn a Strophe connection object
*
* @return the number of xmppAddr entries in the client certificate
*
* @ingroup Connections
*/
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *const conn)
{
return tls_id_on_xmppaddr_num(conn);
}
/** Get a specific xmppAddr entry.
*
* @param conn a Strophe connection object
* @param n the index of the entry, starting at 0
*
* @return a string containing the xmppAddr or NULL if n is out of range
*
* @ingroup Connections
*/
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *const conn, unsigned int n)
{
return tls_id_on_xmppaddr(conn, n);
}
/** Get the password used for authentication of a connection.
*
* @param conn a Strophe connection object
@@ -385,7 +460,7 @@ void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid)
*
* @ingroup Connections
*/
const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn)
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn)
{
return conn->pass;
}
@@ -399,10 +474,11 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass)
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
if (conn->pass) xmpp_free(conn->ctx, conn->pass);
conn->pass = xmpp_strdup(conn->ctx, pass);
if (conn->pass)
xmpp_free(conn->ctx, conn->pass);
conn->pass = pass ? xmpp_strdup(conn->ctx, pass) : NULL;
}
/** Get the strophe context that the connection is associated with.
@@ -412,7 +488,7 @@ void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass)
*
* @ingroup Connections
*/
xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn)
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn)
{
return conn->ctx;
}
@@ -438,11 +514,11 @@ xmpp_ctx_t* xmpp_conn_get_context(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
int xmpp_connect_client(xmpp_conn_t * const conn,
const char * const altdomain,
int xmpp_connect_client(xmpp_conn_t *conn,
const char *altdomain,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata)
void *userdata)
{
resolver_srv_rr_t *srv_rr_list = NULL;
resolver_srv_rr_t *rr;
@@ -452,8 +528,28 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
int found = XMPP_DOMAIN_NOT_FOUND;
int rc;
if (!conn->jid && conn->tls_client_cert) {
if (tls_id_on_xmppaddr_num(conn) != 1) {
xmpp_debug(conn->ctx, "xmpp",
"Client certificate contains multiple or no xmppAddr "
"and no JID was given to be used.");
return XMPP_EINVOP;
}
conn->jid = tls_id_on_xmppaddr(conn, 0);
if (!conn->jid)
return XMPP_EMEM;
xmpp_debug(conn->ctx, "xmpp", "Use jid %s from id-on-xmppAddr.",
conn->jid);
}
if (!conn->jid) {
xmpp_error(conn->ctx, "xmpp", "JID is not set.");
return XMPP_EINVOP;
}
domain = xmpp_jid_domain(conn->ctx, conn->jid);
if (!domain) return XMPP_EMEM;
if (!domain)
return XMPP_EMEM;
if (altdomain != NULL) {
xmpp_debug(conn->ctx, "xmpp", "Connecting via altdomain.");
@@ -469,7 +565,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
}
if (XMPP_DOMAIN_NOT_FOUND == found) {
xmpp_debug(conn->ctx, "xmpp", "SRV lookup failed, "
xmpp_debug(conn->ctx, "xmpp",
"SRV lookup failed, "
"connecting via domain.");
host = domain;
port = altport ? altport : _conn_default_port(conn, XMPP_CLIENT);
@@ -483,8 +580,8 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
port = rr->port;
rr = rr->next;
}
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT,
callback, userdata);
rc = _conn_connect(conn, domain, host, port, XMPP_CLIENT, callback,
userdata);
} while (rc != 0 && rr != NULL);
xmpp_free(conn->ctx, domain);
@@ -516,17 +613,21 @@ int xmpp_connect_client(xmpp_conn_t * const conn,
*
* @ingroup Connections
*/
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
unsigned short port, xmpp_conn_handler callback,
void * const userdata)
int xmpp_connect_component(xmpp_conn_t *conn,
const char *server,
unsigned short port,
xmpp_conn_handler callback,
void *userdata)
{
/* The server domain, jid and password MUST be specified. */
if (!(server && conn->jid && conn->pass)) return XMPP_EINVOP;
if (!(server && conn->jid && conn->pass))
return XMPP_EINVOP;
/* XEP-0114 does not support TLS */
xmpp_conn_disable_tls(conn);
if (!conn->tls_disabled) {
xmpp_error(conn->ctx, "conn", "Failed to disable TLS. "
xmpp_error(conn->ctx, "conn",
"Failed to disable TLS. "
"XEP-0114 does not support TLS");
return XMPP_EINT;
}
@@ -559,18 +660,18 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
*
* @ingroup Connections
*/
int xmpp_connect_raw(xmpp_conn_t * const conn,
const char * const altdomain,
int xmpp_connect_raw(xmpp_conn_t *conn,
const char *altdomain,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata)
void *userdata)
{
conn->is_raw = 1;
return xmpp_connect_client(conn, altdomain, altport, callback, userdata);
}
/* Called when tcp connection is established. */
void conn_established(xmpp_conn_t * const conn)
void conn_established(xmpp_conn_t *conn)
{
if (conn->tls_legacy_ssl && !conn->is_raw) {
xmpp_debug(conn->ctx, "xmpp", "using legacy SSL connection");
@@ -585,7 +686,8 @@ void conn_established(xmpp_conn_t * const conn)
/* we skip authentication for a "raw" connection, but the event loop
ignores user's handlers when conn->authenticated is not set. */
conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL, conn->userdata);
conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL,
conn->userdata);
} else {
/* send stream init */
conn_open_stream(conn);
@@ -603,7 +705,7 @@ void conn_established(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn)
int xmpp_conn_open_stream_default(xmpp_conn_t *conn)
{
if (!conn->is_raw)
return XMPP_EINVOP;
@@ -630,23 +732,16 @@ int xmpp_conn_open_stream_default(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
int xmpp_conn_open_stream(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len)
{
char *tag;
if (!conn->is_raw)
return XMPP_EINVOP;
tag = _conn_build_stream_tag(conn, attributes, attributes_len);
if (!tag)
return XMPP_EMEM;
conn_prepare_reset(conn, auth_handle_open_raw);
xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
xmpp_free(conn->ctx, tag);
return XMPP_EOK;
return _conn_open_stream_with_attributes(conn, attributes, attributes_len);
}
/** Start synchronous TLS handshake with the server.
@@ -655,7 +750,7 @@ int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
*
* @ingroup Connections
*/
int xmpp_conn_tls_start(xmpp_conn_t * const conn)
int xmpp_conn_tls_start(xmpp_conn_t *conn)
{
return conn_tls_start(conn);
}
@@ -666,7 +761,7 @@ int xmpp_conn_tls_start(xmpp_conn_t * const conn)
*
* @param conn a Strophe connection object
*/
void conn_disconnect_clean(xmpp_conn_t * const conn)
void conn_disconnect_clean(xmpp_conn_t *conn)
{
/* remove the timed handler */
xmpp_timed_handler_delete(conn, _disconnect_cleanup);
@@ -680,7 +775,7 @@ void conn_disconnect_clean(xmpp_conn_t * const conn)
*
* @param conn a Strophe connection object
*/
void conn_disconnect(xmpp_conn_t * const conn)
void conn_disconnect(xmpp_conn_t *conn)
{
xmpp_debug(conn->ctx, "xmpp", "Closing socket.");
conn->state = XMPP_STATE_DISCONNECTED;
@@ -689,7 +784,6 @@ void conn_disconnect(xmpp_conn_t * const conn)
tls_free(conn->tls);
conn->tls = NULL;
}
if (conn->sock >= 0)
sock_close(conn->sock);
/* fire off connection handler */
@@ -699,14 +793,14 @@ void conn_disconnect(xmpp_conn_t * const conn)
/* prepares a parser reset. this is called from handlers. we can't
* reset the parser immediately as it is not re-entrant. */
void conn_prepare_reset(xmpp_conn_t * const conn, xmpp_open_handler handler)
void conn_prepare_reset(xmpp_conn_t *conn, xmpp_open_handler handler)
{
conn->reset_parser = 1;
conn->open_handler = handler;
}
/* reset the parser */
void conn_parser_reset(xmpp_conn_t * const conn)
void conn_parser_reset(xmpp_conn_t *conn)
{
conn->reset_parser = 0;
parser_reset(conn->parser);
@@ -721,7 +815,7 @@ void conn_parser_reset(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
void xmpp_disconnect(xmpp_conn_t * const conn)
void xmpp_disconnect(xmpp_conn_t *conn)
{
if (conn->state != XMPP_STATE_CONNECTING &&
conn->state != XMPP_STATE_CONNECTED)
@@ -731,8 +825,7 @@ void xmpp_disconnect(xmpp_conn_t * const conn)
xmpp_send_raw_string(conn, "</stream:stream>");
/* setup timed handler in case disconnect takes too long */
handler_add_timed(conn, _disconnect_cleanup,
DISCONNECT_TIMEOUT, NULL);
handler_add_timed(conn, _disconnect_cleanup, DISCONNECT_TIMEOUT, NULL);
}
/** Send a raw string to the XMPP server.
@@ -748,8 +841,7 @@ void xmpp_disconnect(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
void xmpp_send_raw_string(xmpp_conn_t * const conn,
const char * const fmt, ...)
void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...)
{
va_list ap;
size_t len;
@@ -766,7 +858,8 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
len++; /* account for trailing \0 */
bigbuf = xmpp_alloc(conn->ctx, len);
if (!bigbuf) {
xmpp_debug(conn->ctx, "xmpp", "Could not allocate memory for send_raw_string");
xmpp_debug(conn->ctx, "xmpp",
"Could not allocate memory for send_raw_string");
return;
}
va_start(ap, fmt);
@@ -797,16 +890,17 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
*
* @ingroup Connections
*/
void xmpp_send_raw(xmpp_conn_t * const conn,
const char * const data, const size_t len)
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len)
{
xmpp_send_queue_t *item;
if (conn->state != XMPP_STATE_CONNECTED) return;
if (conn->state != XMPP_STATE_CONNECTED)
return;
/* create send queue item for queue */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
if (!item) return;
if (!item)
return;
item->data = xmpp_alloc(conn->ctx, len);
if (!item->data) {
@@ -840,8 +934,7 @@ void xmpp_send_raw(xmpp_conn_t * const conn,
*
* @ingroup Connections
*/
void xmpp_send(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza)
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
{
char *buf;
size_t len;
@@ -861,23 +954,36 @@ void xmpp_send(xmpp_conn_t * const conn,
*
* @param conn a Strophe connection object
*/
void conn_open_stream(xmpp_conn_t * const conn)
void conn_open_stream(xmpp_conn_t *conn)
{
xmpp_send_raw_string(conn,
"<?xml version=\"1.0\"?>" \
"<stream:stream to=\"%s\" " \
"xml:lang=\"%s\" " \
"version=\"1.0\" " \
"xmlns=\"%s\" " \
"xmlns:stream=\"%s\">",
conn->domain,
conn->lang,
conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT :
XMPP_NS_COMPONENT,
XMPP_NS_STREAMS);
size_t attributes_len;
int rc;
char *from = NULL;
char *ns = conn->type == XMPP_CLIENT ? XMPP_NS_CLIENT : XMPP_NS_COMPONENT;
char *attributes[12] = {
"to", conn->domain, "xml:lang", conn->lang,
"version", "1.0", "xmlns", ns,
"xmlns:stream", XMPP_NS_STREAMS, "from", NULL};
attributes_len = ARRAY_SIZE(attributes);
if (conn->tls && conn->jid && strchr(conn->jid, '@') != NULL)
from = xmpp_jid_bare(conn->ctx, conn->jid);
if (from)
attributes[attributes_len - 1] = from;
else
attributes_len -= 2;
rc = _conn_open_stream_with_attributes(conn, attributes, attributes_len);
if (rc != XMPP_EOK) {
xmpp_error(conn->ctx, "conn", "Cannot build stream tag: memory error");
conn_disconnect(conn);
}
if (from)
xmpp_free(conn->ctx, from);
}
int conn_tls_start(xmpp_conn_t * const conn)
int conn_tls_start(xmpp_conn_t *conn)
{
int rc;
@@ -901,8 +1007,10 @@ int conn_tls_start(xmpp_conn_t * const conn)
}
}
if (rc != 0) {
xmpp_debug(conn->ctx, "conn", "Couldn't start TLS! "
"error %d tls_error %d", rc, conn->error);
xmpp_debug(conn->ctx, "conn",
"Couldn't start TLS! "
"error %d tls_error %d",
rc, conn->error);
}
return rc;
}
@@ -915,7 +1023,7 @@ int conn_tls_start(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
long xmpp_conn_get_flags(const xmpp_conn_t *conn)
{
long flags;
@@ -923,7 +1031,7 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust |
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;;
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
return flags;
}
@@ -950,10 +1058,11 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags)
{
if (conn->state != XMPP_STATE_DISCONNECTED) {
xmpp_error(conn->ctx, "conn", "Flags can be set only "
xmpp_error(conn->ctx, "conn",
"Flags can be set only "
"for disconnected connection");
return XMPP_EINVOP;
}
@@ -984,7 +1093,7 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
*
* @ingroup Connections
*/
void xmpp_conn_disable_tls(xmpp_conn_t * const conn)
void xmpp_conn_disable_tls(xmpp_conn_t *conn)
{
long flags = xmpp_conn_get_flags(conn);
@@ -998,25 +1107,56 @@ void xmpp_conn_disable_tls(xmpp_conn_t * const conn)
*
* @ingroup Connections
*/
int xmpp_conn_is_secured(xmpp_conn_t * const conn)
int xmpp_conn_is_secured(xmpp_conn_t *conn)
{
return conn->secured && !conn->tls_failed && conn->tls != NULL ? 1 : 0;
return conn->secured && !conn->tls_failed && conn->tls != NULL;
}
/**
* @return TRUE if connection is in connecting state and FALSE otherwise
*
* @ingroup Connections
*/
int xmpp_conn_is_connecting(xmpp_conn_t *conn)
{
return conn->state == XMPP_STATE_CONNECTING;
}
/**
* @return TRUE if connection is in connected state and FALSE otherwise
*
* @ingroup Connections
*/
int xmpp_conn_is_connected(xmpp_conn_t *conn)
{
return conn->state == XMPP_STATE_CONNECTED;
}
/**
* @return TRUE if connection is in disconnected state and FALSE otherwise
*
* @ingroup Connections
*/
int xmpp_conn_is_disconnected(xmpp_conn_t *conn)
{
return conn->state == XMPP_STATE_DISCONNECTED;
}
/* timed handler for cleanup if normal disconnect procedure takes too long */
static int _disconnect_cleanup(xmpp_conn_t * const conn,
void * const userdata)
static int _disconnect_cleanup(xmpp_conn_t *conn, void *userdata)
{
xmpp_debug(conn->ctx, "xmpp",
"disconnection forced by cleanup timeout");
UNUSED(userdata);
xmpp_debug(conn->ctx, "xmpp", "disconnection forced by cleanup timeout");
conn_disconnect(conn);
return 0;
}
static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
char **attributes, size_t attributes_len)
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len)
{
char *tag;
size_t len;
@@ -1032,7 +1172,8 @@ static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
for (i = 0; i < attributes_len; ++i)
len += strlen(attributes[i]) + 2;
tag = xmpp_alloc(conn->ctx, len + 1);
if (!tag) return NULL;
if (!tag)
return NULL;
strcpy(tag, tag_head);
for (i = 0; i < attributes_len; ++i) {
@@ -1048,7 +1189,8 @@ static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
strcat(tag, tag_tail);
if (strlen(tag) != len) {
xmpp_error(conn->ctx, "xmpp", "Internal error in "
xmpp_error(conn->ctx, "xmpp",
"Internal error in "
"_conn_build_stream_tag().");
xmpp_free(conn->ctx, tag);
tag = NULL;
@@ -1057,20 +1199,40 @@ static char *_conn_build_stream_tag(xmpp_conn_t * const conn,
return tag;
}
static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
char ***attributes, size_t *attributes_len)
static int _conn_open_stream_with_attributes(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len)
{
char *tag;
tag = _conn_build_stream_tag(conn, attributes, attributes_len);
if (!tag)
return XMPP_EMEM;
xmpp_send_raw_string(conn, "<?xml version=\"1.0\"?>%s", tag);
xmpp_free(conn->ctx, tag);
return XMPP_EOK;
}
static void _conn_attributes_new(xmpp_conn_t *conn,
char **attrs,
char ***attributes,
size_t *attributes_len)
{
char **array = NULL;
size_t nr = 0;
size_t i;
if (attrs) {
for (; attrs[nr]; ++nr);
for (; attrs[nr]; ++nr)
;
array = xmpp_alloc(conn->ctx, sizeof(*array) * nr);
for (i = 0; array && i < nr; ++i) {
array[i] = (i & 1) == 0 ? parser_attr_name(conn->ctx, attrs[i])
: xmpp_strdup(conn->ctx, attrs[i]);
if (array[i] == NULL) break;
if (array[i] == NULL)
break;
}
if (!array || i < nr) {
xmpp_error(conn->ctx, "xmpp", "Memory allocation error.");
@@ -1083,7 +1245,8 @@ static void _conn_attributes_new(xmpp_conn_t *conn, char **attrs,
*attributes_len = nr;
}
static void _conn_attributes_destroy(xmpp_conn_t *conn, char **attributes,
static void _conn_attributes_destroy(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len)
{
size_t i;
@@ -1114,7 +1277,8 @@ static char *_get_stream_attribute(char **attrs, char *name)
{
int i;
if (!attrs) return NULL;
if (!attrs)
return NULL;
for (i = 0; attrs[i]; i += 2)
if (strcmp(name, attrs[i]) == 0)
@@ -1123,14 +1287,14 @@ static char *_get_stream_attribute(char **attrs, char *name)
return NULL;
}
static void _handle_stream_start(char *name, char **attrs,
void * const userdata)
static void _handle_stream_start(char *name, char **attrs, void *userdata)
{
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
char *id;
int failed = 0;
if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id);
if (conn->stream_id)
xmpp_free(conn->ctx, conn->stream_id);
conn->stream_id = NULL;
if (strcmp(name, "stream") == 0) {
@@ -1144,8 +1308,10 @@ static void _handle_stream_start(char *name, char **attrs,
failed = 1;
}
} else {
xmpp_error(conn->ctx, "conn", "Server did not open valid stream."
" name = %s.", name);
xmpp_error(conn->ctx, "conn",
"Server did not open valid stream."
" name = %s.",
name);
failed = 1;
}
@@ -1157,18 +1323,18 @@ static void _handle_stream_start(char *name, char **attrs,
}
}
static void _handle_stream_end(char *name,
void * const userdata)
static void _handle_stream_end(char *name, void *userdata)
{
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
UNUSED(name);
/* stream is over */
xmpp_debug(conn->ctx, "xmpp", "RECV: </stream:stream>");
conn_disconnect_clean(conn);
}
static void _handle_stream_stanza(xmpp_stanza_t *stanza,
void * const userdata)
static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *userdata)
{
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
char *buf;
@@ -1182,13 +1348,13 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza,
handler_fire_stanza(conn, stanza);
}
static unsigned short _conn_default_port(xmpp_conn_t * const conn,
static unsigned short _conn_default_port(xmpp_conn_t *conn,
xmpp_conn_type_t type)
{
switch (type) {
case XMPP_CLIENT:
return conn->tls_legacy_ssl ? XMPP_PORT_CLIENT_LEGACY_SSL :
XMPP_PORT_CLIENT;
return conn->tls_legacy_ssl ? XMPP_PORT_CLIENT_LEGACY_SSL
: XMPP_PORT_CLIENT;
case XMPP_COMPONENT:
return XMPP_PORT_COMPONENT;
default:
@@ -1196,7 +1362,7 @@ static unsigned short _conn_default_port(xmpp_conn_t * const conn,
};
}
static void _conn_reset(xmpp_conn_t * const conn)
static void _conn_reset(xmpp_conn_t *conn)
{
xmpp_ctx_t *ctx = conn->ctx;
xmpp_send_queue_t *sq, *tsq;
@@ -1226,9 +1392,12 @@ static void _conn_reset(xmpp_conn_t * const conn)
conn->stream_error = NULL;
}
if (conn->domain) xmpp_free(ctx, conn->domain);
if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid);
if (conn->stream_id) xmpp_free(ctx, conn->stream_id);
if (conn->domain)
xmpp_free(ctx, conn->domain);
if (conn->bound_jid)
xmpp_free(ctx, conn->bound_jid);
if (conn->stream_id)
xmpp_free(ctx, conn->stream_id);
conn->domain = NULL;
conn->bound_jid = NULL;
conn->stream_id = NULL;
@@ -1244,31 +1413,35 @@ static void _conn_reset(xmpp_conn_t * const conn)
handler_system_delete_all(conn);
}
static int _conn_connect(xmpp_conn_t * const conn,
const char * const domain,
const char * const host,
static int _conn_connect(xmpp_conn_t *conn,
const char *domain,
const char *host,
unsigned short port,
xmpp_conn_type_t type,
xmpp_conn_handler callback,
void * const userdata)
void *userdata)
{
xmpp_open_handler open_handler;
if (conn->state != XMPP_STATE_DISCONNECTED) return XMPP_EINVOP;
if (type != XMPP_CLIENT && type != XMPP_COMPONENT) return XMPP_EINVOP;
if (host == NULL || port == 0) return XMPP_EINT;
if (conn->state != XMPP_STATE_DISCONNECTED)
return XMPP_EINVOP;
if (type != XMPP_CLIENT && type != XMPP_COMPONENT)
return XMPP_EINVOP;
if (host == NULL || port == 0)
return XMPP_EINT;
_conn_reset(conn);
conn->type = type;
conn->domain = xmpp_strdup(conn->ctx, domain);
if (!conn->domain) return XMPP_EMEM;
if (!conn->domain)
return XMPP_EMEM;
conn->xsock = sock_new(conn->ctx, host, port);
conn->sock = sock_connect(conn->xsock);
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
host, port, conn->sock);
if (conn->sock == -1) return XMPP_EINT;
conn->sock = sock_connect(host, port);
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d", host,
port, conn->sock);
if (conn->sock == -1)
return XMPP_EINT;
if (conn->ka_timeout || conn->ka_interval)
sock_set_keepalive(conn->sock, conn->ka_timeout, conn->ka_interval);
@@ -1276,9 +1449,9 @@ static int _conn_connect(xmpp_conn_t * const conn,
conn->conn_handler = callback;
conn->userdata = userdata;
open_handler = conn->is_raw ? auth_handle_open_stub :
type == XMPP_CLIENT ? auth_handle_open :
auth_handle_component_open;
open_handler = conn->is_raw ? auth_handle_open_stub
: type == XMPP_CLIENT ? auth_handle_open
: auth_handle_component_open;
conn_prepare_reset(conn, open_handler);
/* FIXME: it could happen that the connect returns immediately as

View File

@@ -91,7 +91,8 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
*
* @ingroup Digests
*/
void xmpp_sha1_digest(const unsigned char *data, size_t len,
void xmpp_sha1_digest(const unsigned char *data,
size_t len,
unsigned char *digest)
{
crypto_SHA1((const uint8_t *)data, len, digest);
@@ -214,52 +215,43 @@ void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest)
memcpy(digest, sha1->digest, SHA1_DIGEST_SIZE);
}
/* Base64 encoding routines. Implemented according to RFC 3548. */
/* map of all byte values to the base64 values, or to
'65' which indicates an invalid character. '=' is '64' */
static const unsigned char _base64_invcharmap[256] = {
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,62, 65,65,65,63,
52,53,54,55, 56,57,58,59, 60,61,65,65, 65,64,65,65,
65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,65, 65,65,65,65,
65,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65,
65,65,65,65, 65,65,65,65, 65,65,65,65, 65,65,65,65
};
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 62, 65, 65, 65, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, 65, 65, 65, 64, 65, 65, 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 65, 65, 65, 65,
65, 65, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65};
/* map of all 6-bit values to their corresponding byte
in the base64 alphabet. Padding char is the value '64' */
static const char _base64_charmap[65] = {
'A','B','C','D', 'E','F','G','H',
'I','J','K','L', 'M','N','O','P',
'Q','R','S','T', 'U','V','W','X',
'Y','Z','a','b', 'c','d','e','f',
'g','h','i','j', 'k','l','m','n',
'o','p','q','r', 's','t','u','v',
'w','x','y','z', '0','1','2','3',
'4','5','6','7', '8','9','+','/',
'='
};
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '='};
static size_t base64_encoded_len(const size_t len)
static size_t base64_encoded_len(size_t len)
{
/* encoded steam is 4 bytes for every three, rounded up */
return ((len + 2) / 3) << 2;
}
static char *base64_encode(xmpp_ctx_t *ctx,
const unsigned char * const buffer, const size_t len)
static char *
base64_encode(xmpp_ctx_t *ctx, const unsigned char *buffer, size_t len)
{
size_t clen;
char *cbuf, *c;
@@ -311,30 +303,37 @@ static char *base64_encode(xmpp_ctx_t *ctx,
return cbuf;
}
static size_t base64_decoded_len(const char * const buffer, const size_t len)
static size_t base64_decoded_len(const char *buffer, size_t len)
{
size_t nudge = 0;
unsigned char c;
size_t i;
if (len < 4) return 0;
if (len < 4)
return 0;
/* count the padding characters for the remainder */
for (i = len; i > 0; --i) {
c = _base64_invcharmap[(unsigned char)buffer[i - 1]];
if (c < 64) break;
if (c == 64) ++nudge;
if (c > 64) return 0;
if (c < 64)
break;
if (c == 64)
++nudge;
if (c > 64)
return 0;
}
if (nudge > 2) return 0;
if (nudge > 2)
return 0;
/* decoded steam is 3 bytes for every four */
return 3 * (len >> 2) - nudge;
}
static void base64_decode(xmpp_ctx_t *ctx,
const char * const buffer, const size_t len,
unsigned char **out, size_t *outlen)
const char *buffer,
size_t len,
unsigned char **out,
size_t *outlen)
{
size_t dlen;
unsigned char *dbuf, *d;
@@ -342,10 +341,12 @@ static void base64_decode(xmpp_ctx_t *ctx,
size_t i;
/* len must be a multiple of 4 */
if (len & 0x03) goto _base64_error;
if (len & 0x03)
goto _base64_error;
dlen = base64_decoded_len(buffer, len);
if (dlen == 0) goto _base64_error;
if (dlen == 0)
goto _base64_error;
dbuf = xmpp_alloc(ctx, dlen + 1);
if (dbuf != NULL) {
@@ -353,22 +354,27 @@ static void base64_decode(xmpp_ctx_t *ctx,
/* loop over each set of 4 characters, decoding 3 bytes */
for (i = 0; i + 3 < len; i += 4) {
hextet = _base64_invcharmap[(unsigned char)buffer[i]];
if (hextet & 0xC0) break;
if (hextet & 0xC0)
break;
word = hextet << 18;
hextet = _base64_invcharmap[(unsigned char)buffer[i + 1]];
if (hextet & 0xC0) break;
if (hextet & 0xC0)
break;
word |= hextet << 12;
hextet = _base64_invcharmap[(unsigned char)buffer[i + 2]];
if (hextet & 0xC0) break;
if (hextet & 0xC0)
break;
word |= hextet << 6;
hextet = _base64_invcharmap[(unsigned char)buffer[i + 3]];
if (hextet & 0xC0) break;
if (hextet & 0xC0)
break;
word |= hextet;
*d++ = (word & 0x00FF0000) >> 16;
*d++ = (word & 0x0000FF00) >> 8;
*d++ = (word & 0x000000FF);
}
if (hextet > 64) goto _base64_decode_error;
if (hextet > 64)
goto _base64_decode_error;
/* handle the remainder */
switch (dlen % 3) {
case 0:
@@ -377,32 +383,40 @@ static void base64_decode(xmpp_ctx_t *ctx,
case 1:
/* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]];
if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0)
goto _base64_decode_error;
word = hextet << 2;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]];
if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0)
goto _base64_decode_error;
word |= hextet >> 4;
*d++ = word & 0xFF;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]];
if (hextet != 64) goto _base64_decode_error;
if (hextet != 64)
goto _base64_decode_error;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]];
if (hextet != 64) goto _base64_decode_error;
if (hextet != 64)
goto _base64_decode_error;
break;
case 2:
/* redo the last quartet, checking for correctness */
hextet = _base64_invcharmap[(unsigned char)buffer[len - 4]];
if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0)
goto _base64_decode_error;
word = hextet << 10;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 3]];
if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0)
goto _base64_decode_error;
word |= hextet << 4;
hextet = _base64_invcharmap[(unsigned char)buffer[len - 2]];
if (hextet & 0xC0) goto _base64_decode_error;
if (hextet & 0xC0)
goto _base64_decode_error;
word |= hextet >> 2;
*d++ = (word & 0xFF00) >> 8;
*d++ = (word & 0x00FF);
hextet = _base64_invcharmap[(unsigned char)buffer[len - 1]];
if (hextet != 64) goto _base64_decode_error;
if (hextet != 64)
goto _base64_decode_error;
break;
}
*d = '\0';
@@ -484,8 +498,11 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
*
* @ingroup Encodings
*/
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
unsigned char **out, size_t *outlen)
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx,
const char *base64,
size_t len,
unsigned char **out,
size_t *outlen)
{
base64_decode(ctx, base64, len, out, outlen);
}

View File

@@ -50,9 +50,10 @@
#include "resolver.h"
#include "util.h"
/* Workaround for visual studio without va_copy support. */
#if defined(_MSC_VER) && _MSC_VER < 1800
#define va_copy(d,s) ((d) = (s))
/* Workaround for systems without va_copy support. */
#if defined(_MSC_VER) && _MSC_VER < 1800 || \
!defined(_MSC_VER) && !defined(HAVE_DECL_VA_COPY)
#define va_copy(d, s) (memcpy(&d, &s, sizeof(va_list)))
#endif
/** Initialize the Strophe library.
@@ -113,8 +114,7 @@ void xmpp_shutdown(void)
*/
int xmpp_version_check(int major, int minor)
{
return (major == LIBXMPP_VERSION_MAJOR) &&
(minor >= LIBXMPP_VERSION_MINOR);
return (major == LIBXMPP_VERSION_MAJOR) && (minor >= LIBXMPP_VERSION_MINOR);
}
/* We define the global default allocator, logger, and context here. */
@@ -122,35 +122,33 @@ int xmpp_version_check(int major, int minor)
/* Wrap stdlib routines malloc, free, and realloc for default memory
* management.
*/
static void *_malloc(const size_t size, void * const userdata)
static void *_malloc(size_t size, void *userdata)
{
UNUSED(userdata);
return malloc(size);
}
static void _free(void *p, void * const userdata)
static void _free(void *p, void *userdata)
{
UNUSED(userdata);
free(p);
}
static void *_realloc(void *p, const size_t size, void * const userdata)
static void *_realloc(void *p, size_t size, void *userdata)
{
UNUSED(userdata);
return realloc(p, size);
}
/* default memory function map */
static xmpp_mem_t xmpp_default_mem = {
_malloc, /* use the thinly wrapped stdlib routines by default */
_free,
_realloc,
NULL
};
_free, _realloc, NULL};
/* log levels and names */
static const char * const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
XMPP_LEVEL_INFO,
XMPP_LEVEL_WARN,
XMPP_LEVEL_ERROR};
static const char *_xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {
XMPP_LEVEL_DEBUG, XMPP_LEVEL_INFO, XMPP_LEVEL_WARN, XMPP_LEVEL_ERROR};
/** Log a message.
* The default logger writes to stderr.
@@ -161,10 +159,10 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {XMPP_LEVEL_DEBUG,
* @param area the area the log message is for
* @param msg the log message
*/
static void xmpp_default_logger(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
static void xmpp_default_logger(void *userdata,
xmpp_log_level_t level,
const char *area,
const char *msg)
{
xmpp_log_level_t filter_level = *(xmpp_log_level_t *)userdata;
if (level >= filter_level)
@@ -172,11 +170,14 @@ static void xmpp_default_logger(void * const userdata,
}
static const xmpp_log_t _xmpp_default_loggers[] = {
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger, (void*)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}
};
{&xmpp_default_logger,
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
{&xmpp_default_logger,
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
{&xmpp_default_logger,
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
{&xmpp_default_logger,
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}};
/** Get a default logger with filtering.
* The default logger provides a basic logging setup which writes log
@@ -192,7 +193,8 @@ static const xmpp_log_t _xmpp_default_loggers[] = {
xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
{
/* clamp to the known range */
if (level > XMPP_LEVEL_ERROR) level = XMPP_LEVEL_ERROR;
if (level > XMPP_LEVEL_ERROR)
level = XMPP_LEVEL_ERROR;
return (xmpp_log_t *)&_xmpp_default_loggers[level];
}
@@ -209,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 * const ctx, const size_t size)
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
{
return ctx->mem->alloc(size, ctx->mem->userdata);
}
@@ -220,7 +222,7 @@ void *xmpp_alloc(const xmpp_ctx_t * const ctx, const 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 * const ctx, void *p)
void xmpp_free(const xmpp_ctx_t *ctx, void *p)
{
ctx->mem->free(p, ctx->mem->userdata);
}
@@ -234,8 +236,7 @@ void xmpp_free(const xmpp_ctx_t * const ctx, void *p)
*
* @return a pointer to the reallocated memory or NULL on an error
*/
void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
const size_t size)
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
{
return ctx->mem->realloc(p, size, ctx->mem->userdata);
}
@@ -253,10 +254,10 @@ void *xmpp_realloc(const xmpp_ctx_t * const ctx, void *p,
* @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 * const ctx,
const xmpp_log_level_t level,
const char * const area,
const char * const fmt,
void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level,
const char *area,
const char *fmt,
va_list ap)
{
int oldret, ret;
@@ -304,10 +305,7 @@ void xmpp_log(const xmpp_ctx_t * const ctx,
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_error(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
@@ -326,10 +324,7 @@ void xmpp_error(const xmpp_ctx_t * const ctx,
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_warn(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
@@ -348,10 +343,7 @@ void xmpp_warn(const xmpp_ctx_t * const ctx,
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_info(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
@@ -370,10 +362,7 @@ void xmpp_info(const xmpp_ctx_t * const ctx,
* @param fmt a printf-style format string followed by a variable list of
* arguments to format
*/
void xmpp_debug(const xmpp_ctx_t * const ctx,
const char * const area,
const char * const fmt,
...)
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
{
va_list ap;
@@ -396,8 +385,7 @@ void xmpp_debug(const xmpp_ctx_t * const ctx,
*
* @ingroup Context
*/
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log)
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
{
xmpp_ctx_t *ctx = NULL;
@@ -418,6 +406,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
ctx->log = log;
ctx->connlist = NULL;
ctx->timed_handlers = NULL;
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
ctx->rand = xmpp_rand_new(ctx);
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
@@ -436,7 +425,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
*
* @ingroup Context
*/
void xmpp_ctx_free(xmpp_ctx_t * const ctx)
void xmpp_ctx_free(xmpp_ctx_t *ctx)
{
/* mem and log are owned by their suppliers */
xmpp_rand_free(ctx, ctx->rand);
@@ -450,7 +439,7 @@ void xmpp_ctx_free(xmpp_ctx_t * const ctx)
*
* @ingroup Context
*/
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout)
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout)
{
ctx->timeout = timeout;
}

View File

@@ -41,27 +41,24 @@
#define _sleep(x) usleep((x)*1000)
#else
#include <winsock2.h>
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
#ifndef ECONNRESET
#define ECONNRESET WSAECONNRESET
#endif
#ifndef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
#endif
#define _sleep(x) Sleep(x)
#endif
#include <strophe.h>
#include "strophe.h"
#include "common.h"
#include "parser.h"
static int _connect_next(xmpp_conn_t *conn)
{
sock_close(conn->sock);
conn->sock = sock_connect(conn->xsock);
if (conn->sock < 0)
return -1;
conn->timeout_stamp = time_stamp();
return 0;
}
/** Max buffer size for receiving messages. */
#define STROPE_MESSAGE_BUFFER_SIZE 4096
/** Run the event loop once.
* This function will run send any data that has been queued by
@@ -76,7 +73,7 @@ static int _connect_next(xmpp_conn_t *conn)
*
* @ingroup EventLoop
*/
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout)
{
xmpp_connlist_t *connitem;
xmpp_conn_t *conn;
@@ -86,12 +83,13 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
struct timeval tv;
xmpp_send_queue_t *sq, *tsq;
int towrite;
char buf[4096];
char buf[STROPE_MESSAGE_BUFFER_SIZE];
uint64_t next;
uint64_t usec;
int tls_read_bytes = 0;
if (ctx->loop_status == XMPP_LOOP_QUIT) return;
if (ctx->loop_status == XMPP_LOOP_QUIT)
return;
/* send queued data */
connitem = ctx->connlist;
@@ -144,7 +142,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
/* pop the top item */
conn->send_queue_head = sq;
/* if we've sent everything update the tail */
if (!sq) conn->send_queue_tail = NULL;
if (!sq)
conn->send_queue_tail = NULL;
}
/* tear down connection on error */
@@ -165,7 +164,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
conn_parser_reset(connitem->conn);
}
/* fire any ready timed handlers, then make sure we don't wait past
the time when timed handlers need to be called */
next = handler_fire_timed(ctx);
@@ -192,11 +190,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
conn->connect_timeout)
FD_SET(conn->sock, &wfds);
else {
ret = _connect_next(conn);
if (ret == 0) {
FD_SET(conn->sock, &wfds);
break;
}
conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn);
@@ -241,7 +234,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
}
/* no events happened */
if (ret == 0 && tls_read_bytes == 0) return;
if (ret == 0 && tls_read_bytes == 0)
return;
/* process events */
connitem = ctx->connlist;
@@ -255,11 +249,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
/* check for error */
ret = sock_connect_error(conn->sock);
if (ret != 0) {
ret = _connect_next(conn);
if (ret == 0)
break;
}
if (ret != 0) {
/* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
@@ -274,29 +263,35 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
break;
case XMPP_STATE_CONNECTED:
if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) {
if (FD_ISSET(conn->sock, &rfds) ||
(conn->tls && tls_pending(conn->tls))) {
if (conn->tls) {
ret = tls_read(conn->tls, buf, 4096);
ret = tls_read(conn->tls, buf, STROPE_MESSAGE_BUFFER_SIZE);
} else {
ret = sock_read(conn->sock, buf, 4096);
ret =
sock_read(conn->sock, buf, STROPE_MESSAGE_BUFFER_SIZE);
}
if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret);
if (!ret) {
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf);
xmpp_send_error(conn, XMPP_SE_INVALID_XML, "parse error");
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));
xmpp_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.");
xmpp_debug(ctx, "xmpp",
"Socket closed by remote host.");
conn->error = ECONNRESET;
conn_disconnect(conn);
}
@@ -327,7 +322,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
*/
void xmpp_run(xmpp_ctx_t *ctx)
{
if (ctx->loop_status != XMPP_LOOP_NOTSTARTED) return;
if (ctx->loop_status != XMPP_LOOP_NOTSTARTED)
return;
ctx->loop_status = XMPP_LOOP_RUNNING;
while (ctx->loop_status == XMPP_LOOP_RUNNING) {

View File

@@ -24,6 +24,8 @@
#include "common.h"
#include "ostypes.h"
typedef int (*xmpp_void_handler)();
/* Remove item from the list pointed by head, but don't free it.
* There can be a situation when user's handler deletes another handler which
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
@@ -33,19 +35,14 @@
* TODO Convert handler lists to double-linked lists. Current implementation
* works for O(n).
*/
static void _handler_item_remove(xmpp_handlist_t **head,
xmpp_handlist_t *item)
static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
{
xmpp_handlist_t *i = *head;
if (i == item)
while (*head) {
if (*head == item) {
*head = item->next;
else if (i != NULL) {
while (i->next != NULL && i->next != item)
i = i->next;
if (i->next == item) {
i->next = item->next;
break;
}
head = &(*head)->next;
}
}
@@ -56,8 +53,7 @@ static void _handler_item_remove(xmpp_handlist_t **head,
* @param conn a Strophe connection object
* @param stanza a Strophe stanza object
*/
void handler_fire_stanza(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza)
void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza)
{
xmpp_handlist_t *item, *next, *head, *head_old;
const char *id, *ns, *name, *type;
@@ -75,7 +71,8 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
while (item) {
/* don't fire user handlers until authentication succeeds and
and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
if ((item->user_handler && !conn->authenticated) ||
!item->enabled) {
item = item->next;
continue;
}
@@ -90,7 +87,7 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
/* replace old value */
hash_add(conn->id_handlers, id, head);
}
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item->u.id);
xmpp_free(conn->ctx, item);
}
item = next;
@@ -116,10 +113,10 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
}
next = item->next;
if ((!item->ns || (ns && strcmp(ns, item->ns) == 0) ||
xmpp_stanza_get_child_by_ns(stanza, item->ns)) &&
(!item->name || (name && strcmp(name, item->name) == 0)) &&
(!item->type || (type && strcmp(type, item->type) == 0))) {
if ((!item->u.ns || (ns && strcmp(ns, item->u.ns) == 0) ||
xmpp_stanza_get_child_by_ns(stanza, item->u.ns)) &&
(!item->u.name || (name && strcmp(name, item->u.name) == 0)) &&
(!item->u.type || (type && strcmp(type, item->u.type) == 0))) {
ret = ((xmpp_handler)(item->handler))(conn, stanza, item->userdata);
/* list may be changed during execution of a handler */
@@ -127,9 +124,12 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
if (!ret) {
/* handler is one-shot, so delete it */
_handler_item_remove(&conn->handlers, item);
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
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);
}
}
@@ -144,7 +144,7 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
*
* @return the time in milliseconds until the next handler will be ready
*/
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
uint64_t handler_fire_timed(xmpp_ctx_t *ctx)
{
xmpp_connlist_t *connitem;
xmpp_handlist_t *item, *next;
@@ -171,27 +171,28 @@ uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
while (item) {
/* don't fire user handlers until authentication succeeds and
skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
if ((item->user_handler && !conn->authenticated) ||
!item->enabled) {
item = item->next;
continue;
}
next = item->next;
timestamp = time_stamp();
elapsed = time_elapsed(item->last_stamp, timestamp);
if (elapsed >= item->period) {
elapsed = time_elapsed(item->u.last_stamp, timestamp);
if (elapsed >= item->u.period) {
/* fire! */
item->last_stamp = timestamp;
item->u.last_stamp = timestamp;
ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&conn->timed_handlers, item);
xmpp_free(conn->ctx, item);
xmpp_free(ctx, item);
}
} else if (min > (item->period - elapsed))
min = item->period - elapsed;
} else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed;
item = next;
}
@@ -199,6 +200,34 @@ uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
connitem = connitem->next;
}
/*
* Check timed handlers in context. These handlers fire periodically
* regardless of connections state.
* TODO Reduce copy-paste.
*/
item = ctx->timed_handlers;
while (item) {
next = item->next;
timestamp = time_stamp();
elapsed = time_elapsed(item->u.last_stamp, timestamp);
if (elapsed >= item->u.period) {
/* fire! */
item->u.last_stamp = timestamp;
ret =
((xmpp_global_timed_handler)item->handler)(ctx, item->userdata);
/* list may be changed during execution of a handler */
next = item->next;
if (!ret) {
/* delete handler if it returned false */
_handler_item_remove(&ctx->timed_handlers, item);
xmpp_free(ctx, item);
}
} else if (min > (item->u.period - elapsed))
min = item->u.period - elapsed;
item = next;
}
return min;
}
@@ -215,50 +244,63 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
handitem = conn->timed_handlers;
while (handitem) {
if ((user_only && handitem->user_handler) || !user_only)
handitem->last_stamp = time_stamp();
handitem->u.last_stamp = time_stamp();
handitem = handitem->next;
}
}
static void _timed_handler_add(xmpp_conn_t * const conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata,
const int user_handler)
static void _timed_handler_add(xmpp_ctx_t *ctx,
xmpp_handlist_t **handlers_list,
xmpp_void_handler handler,
unsigned long period,
void *userdata,
int user_handler)
{
xmpp_handlist_t *item, *tail;
xmpp_handlist_t *item;
/* check if handler is already in the list */
for (item = conn->timed_handlers; item; item = item->next) {
for (item = *handlers_list; item; item = item->next) {
if (item->handler == handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
xmpp_warn(ctx, "xmpp", "Timed handler already exists.");
break;
}
}
if (item) return;
if (item)
return;
/* build new item */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) return;
item = xmpp_alloc(ctx, sizeof(xmpp_handlist_t));
if (!item)
return;
item->user_handler = user_handler;
item->handler = handler;
item->userdata = userdata;
item->enabled = 0;
item->next = NULL;
item->period = period;
item->last_stamp = time_stamp();
item->u.period = period;
item->u.last_stamp = time_stamp();
/* append item to list */
if (!conn->timed_handlers)
conn->timed_handlers = item;
else {
tail = conn->timed_handlers;
while (tail->next)
tail = tail->next;
tail->next = item;
item->next = *handlers_list;
*handlers_list = item;
}
static void _timed_handler_delete(xmpp_ctx_t *ctx,
xmpp_handlist_t **handlers_list,
xmpp_void_handler handler)
{
xmpp_handlist_t *item;
while (*handlers_list) {
item = *handlers_list;
if (item->handler == handler) {
*handlers_list = item->next;
xmpp_free(ctx, item);
} else {
handlers_list = &item->next;
}
}
}
@@ -269,35 +311,16 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
*
* @ingroup Handlers
*/
void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
xmpp_timed_handler handler)
void xmpp_timed_handler_delete(xmpp_conn_t *conn, xmpp_timed_handler handler)
{
xmpp_handlist_t *item, *prev;
if (!conn->timed_handlers) return;
prev = NULL;
item = conn->timed_handlers;
while (item) {
if (item->handler == handler) {
if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->timed_handlers;
} else {
prev = item;
item = item->next;
}
}
_timed_handler_delete(conn->ctx, &conn->timed_handlers, handler);
}
static void _id_handler_add(xmpp_conn_t * const conn,
static void _id_handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id,
void * const userdata, int user_handler)
const char *id,
void *userdata,
int user_handler)
{
xmpp_handlist_t *item, *tail;
@@ -310,11 +333,13 @@ static void _id_handler_add(xmpp_conn_t * const conn,
}
item = item->next;
}
if (item) return;
if (item)
return;
/* build new item */
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) return;
if (!item)
return;
item->user_handler = user_handler;
item->handler = handler;
@@ -322,8 +347,8 @@ static void _id_handler_add(xmpp_conn_t * const conn,
item->enabled = 0;
item->next = NULL;
item->id = xmpp_strdup(conn->ctx, id);
if (!item->id) {
item->u.id = xmpp_strdup(conn->ctx, id);
if (!item->u.id) {
xmpp_free(conn->ctx, item);
return;
}
@@ -347,15 +372,16 @@ static void _id_handler_add(xmpp_conn_t * const conn,
*
* @ingroup Handlers
*/
void xmpp_id_handler_delete(xmpp_conn_t * const conn,
void xmpp_id_handler_delete(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id)
const char *id)
{
xmpp_handlist_t *item, *prev, *next;
prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!item) return;
if (!item)
return;
while (item) {
next = item->next;
@@ -368,7 +394,7 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
hash_add(conn->id_handlers, id, next);
}
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item->u.id);
xmpp_free(conn->ctx, item);
item = next;
} else {
@@ -379,12 +405,13 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
}
/* add a stanza handler */
static void _handler_add(xmpp_conn_t * const conn,
static void _handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata, int user_handler)
const char *ns,
const char *name,
const char *type,
void *userdata,
int user_handler)
{
xmpp_handlist_t *item, *tail;
@@ -397,11 +424,13 @@ static void _handler_add(xmpp_conn_t * const conn,
break;
}
}
if (item) return;
if (item)
return;
/* build new item */
item = (xmpp_handlist_t *)xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
if (!item) return;
if (!item)
return;
item->user_handler = user_handler;
item->handler = handler;
@@ -410,31 +439,36 @@ static void _handler_add(xmpp_conn_t * const conn,
item->next = NULL;
if (ns) {
item->ns = xmpp_strdup(conn->ctx, ns);
if (!item->ns) {
item->u.ns = xmpp_strdup(conn->ctx, ns);
if (!item->u.ns) {
xmpp_free(conn->ctx, item);
return;
}
} else
item->ns = NULL;
item->u.ns = NULL;
if (name) {
item->name = xmpp_strdup(conn->ctx, name);
if (!item->name) {
if (item->ns) xmpp_free(conn->ctx, item->ns);
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->name = NULL;
item->u.name = NULL;
if (type) {
item->type = xmpp_strdup(conn->ctx, type);
if (!item->type) {
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
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->type = NULL;
item->u.type = NULL;
/* append to list */
if (!conn->handlers)
@@ -454,12 +488,12 @@ static void _handler_add(xmpp_conn_t * const conn,
*
* @ingroup Handlers
*/
void xmpp_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler)
void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler)
{
xmpp_handlist_t *prev, *item;
if (!conn->handlers) return;
if (!conn->handlers)
return;
prev = NULL;
item = conn->handlers;
@@ -470,9 +504,12 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
else
conn->handlers = item->next;
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item);
item = prev ? prev->next : conn->handlers;
} else {
@@ -498,12 +535,13 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
*
* @ingroup Handlers
*/
void xmpp_timed_handler_add(xmpp_conn_t * const conn,
void xmpp_timed_handler_add(xmpp_conn_t *conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
unsigned long period,
void *userdata)
{
_timed_handler_add(conn, handler, period, userdata, 1);
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
userdata, 1);
}
/** Add a timed system handler.
@@ -515,12 +553,13 @@ void xmpp_timed_handler_add(xmpp_conn_t * const conn,
* @param period the time in milliseconds between firings
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add_timed(xmpp_conn_t * const conn,
void handler_add_timed(xmpp_conn_t *conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata)
unsigned long period,
void *userdata)
{
_timed_handler_add(conn, handler, period, userdata, 0);
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
userdata, 0);
}
/** Add an id based stanza handler.
@@ -539,10 +578,10 @@ void handler_add_timed(xmpp_conn_t * const conn,
*
* @ingroup Handlers
*/
void xmpp_id_handler_add(xmpp_conn_t * const conn,
void xmpp_id_handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id,
void * const userdata)
const char *id,
void *userdata)
{
_id_handler_add(conn, handler, id, userdata, 1);
}
@@ -556,10 +595,10 @@ void xmpp_id_handler_add(xmpp_conn_t * const conn,
* @param id a string with the id
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add_id(xmpp_conn_t * const conn,
void handler_add_id(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id,
void * const userdata)
const char *id,
void *userdata)
{
_id_handler_add(conn, handler, id, userdata, 0);
}
@@ -586,12 +625,12 @@ void handler_add_id(xmpp_conn_t * const conn,
*
* @ingroup Handlers
*/
void xmpp_handler_add(xmpp_conn_t * const conn,
void xmpp_handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
const char *ns,
const char *name,
const char *type,
void *userdata)
{
_handler_add(conn, handler, ns, name, type, userdata, 1);
}
@@ -607,12 +646,12 @@ void xmpp_handler_add(xmpp_conn_t * const conn,
* @param type a string with the 'type' attribute value to match
* @param userdata an opaque data pointer that will be passed to the handler
*/
void handler_add(xmpp_conn_t * const conn,
void handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata)
const char *ns,
const char *name,
const char *type,
void *userdata)
{
_handler_add(conn, handler, ns, name, type, userdata, 0);
}
@@ -636,9 +675,12 @@ void handler_system_delete_all(xmpp_conn_t *conn)
if (!item->user_handler) {
next = item->next;
_handler_item_remove(&conn->handlers, item);
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
if (item->u.ns)
xmpp_free(conn->ctx, item->u.ns);
if (item->u.name)
xmpp_free(conn->ctx, item->u.name);
if (item->u.type)
xmpp_free(conn->ctx, item->u.type);
xmpp_free(conn->ctx, item);
item = next;
} else
@@ -665,7 +707,7 @@ 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->id);
xmpp_free(conn->ctx, item->u.id);
xmpp_free(conn->ctx, item);
item = next;
} else
@@ -686,5 +728,56 @@ void handler_system_delete_all(xmpp_conn_t *conn)
xmpp_free(conn->ctx, key2);
}
}
if (iter) hash_iter_release(iter);
if (iter)
hash_iter_release(iter);
}
/** Add a global timed handler.
* The handler will fire for the first time once the period has elapsed,
* and continue firing regularly after that. Strophe will try its best
* to fire handlers as close to the period times as it can, but accuracy
* will vary depending on the resolution of the event loop.
*
* The main difference between global and ordinary handlers:
* - Ordinary handler is related to a connection, fires only when the
* connection is in connected state and is removed once the connection is
* destroyed.
* - Global handler fires regardless of connections state and is related to
* a Strophe context.
*
* The handler is executed in context of the respective event loop.
*
* If the handler function returns true, it will be kept, and if it
* returns false, it will be deleted from the list of handlers.
*
* Notice, the same handler pointer may be added multiple times with different
* userdata pointers. However, xmpp_global_timed_handler_delete() deletes
* all occurrences.
*
* @param ctx a Strophe context object
* @param handler a function pointer to a timed handler
* @param period the time in milliseconds between firings
* @param userdata an opaque data pointer that will be passed to the handler
*
* @ingroup Handlers
*/
void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx,
xmpp_global_timed_handler handler,
unsigned long period,
void *userdata)
{
_timed_handler_add(ctx, &ctx->timed_handlers, handler, period, userdata, 1);
}
/** Delete a global timed handler.
*
* @param ctx a Strophe context object
* @param handler function pointer to the handler
*
* @ingroup Handlers
*/
void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx,
xmpp_global_timed_handler handler)
{
_timed_handler_delete(ctx, &ctx->timed_handlers, handler);
}

View File

@@ -46,8 +46,7 @@ struct _hash_iterator_t {
};
/** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free_func)
hash_t *hash_new(xmpp_ctx_t *ctx, int size, hash_free_func free_func)
{
hash_t *result = NULL;
@@ -72,14 +71,14 @@ hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
}
/** obtain a new reference to an existing hash table */
hash_t *hash_clone(hash_t * const table)
hash_t *hash_clone(hash_t *table)
{
table->ref++;
return table;
}
/** release a hash table that is no longer needed */
void hash_release(hash_t * const table)
void hash_release(hash_t *table)
{
xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry, *next;
@@ -93,7 +92,8 @@ void hash_release(hash_t * const table)
while (entry != NULL) {
next = entry->next;
xmpp_free(ctx, entry->key);
if (table->free) table->free(ctx, entry->value);
if (table->free)
table->free(ctx, entry->value);
xmpp_free(ctx, entry);
entry = next;
}
@@ -114,7 +114,8 @@ static int _hash_key(hash_t *table, const char *key)
/* assume 32 bit ints */
hash ^= ((unsigned)*c++ << shift);
shift += 8;
if (shift > 24) shift = 0;
if (shift > 24)
shift = 0;
}
return hash % (unsigned)table->length;
}
@@ -141,7 +142,7 @@ hashentry_t *_hash_entry_find(hash_t *table, const char *key)
* each key can appear only once; the value of any
* identical key will be replaced
*/
int hash_add(hash_t *table, const char * const key, void *data)
int hash_add(hash_t *table, const char *key, void *data)
{
xmpp_ctx_t *ctx = table->ctx;
hashentry_t *entry = NULL;
@@ -153,7 +154,8 @@ int hash_add(hash_t *table, const char * const key, void *data)
if (entry == NULL) {
/* allocate and fill a new entry */
entry = xmpp_alloc(ctx, sizeof(hashentry_t));
if (!entry) return -1;
if (!entry)
return -1;
entry->key = xmpp_strdup(ctx, key);
if (!entry->key) {
xmpp_free(ctx, entry);
@@ -164,7 +166,8 @@ int hash_add(hash_t *table, const char * const key, void *data)
table->entries[table_index] = entry;
table->num_keys++;
} else {
if (table->free) table->free(ctx, entry->value);
if (table->free)
table->free(ctx, entry->value);
}
entry->value = data;
@@ -196,7 +199,8 @@ int hash_drop(hash_t *table, const char *key)
if (!strcmp(key, entry->key)) {
/* match, remove the entry */
xmpp_free(ctx, entry->key);
if (table->free) table->free(ctx, entry->value);
if (table->free)
table->free(ctx, entry->value);
if (prev == NULL) {
table->entries[table_index] = entry->next;
} else {
@@ -235,7 +239,6 @@ hash_iterator_t *hash_iter_new(hash_t *table)
return iter;
}
/** release an iterator that is no longer needed */
void hash_iter_release(hash_iterator_t *iter)
{
@@ -258,7 +261,8 @@ const char * hash_iter_next(hash_iterator_t *iter)
int i;
/* advance until we find the next entry */
if (entry != NULL) entry = entry->next;
if (entry != NULL)
entry = entry->next;
if (entry == NULL) {
/* we're off the end of list, search for a new entry */
i = iter->index + 1;

View File

@@ -18,23 +18,22 @@
typedef struct _hash_t hash_t;
typedef void (*hash_free_func)(const xmpp_ctx_t * const ctx, void *p);
typedef void (*hash_free_func)(const xmpp_ctx_t *ctx, void *p);
/** allocate and initialize a new hash table */
hash_t *hash_new(xmpp_ctx_t * const ctx, const int size,
hash_free_func free_func);
hash_t *hash_new(xmpp_ctx_t *ctx, int size, hash_free_func free_func);
/** allocate a new reference to an existing hash table */
hash_t *hash_clone(hash_t * const table);
hash_t *hash_clone(hash_t *table);
/** release a hash table when no longer needed */
void hash_release(hash_t * const table);
void hash_release(hash_t *table);
/** add a key, value pair to a hash table.
* each key can appear only once; the value of any
* identical key will be replaced
*/
int hash_add(hash_t *table, const char * const key, void *data);
int hash_add(hash_t *table, const char *key, void *data);
/** look up a key in a hash table */
void *hash_get(hash_t *table, const char *key);

View File

@@ -28,7 +28,8 @@
* @return an allocated string with the full JID or NULL if no domain
* is specified
*/
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
char *xmpp_jid_new(xmpp_ctx_t *ctx,
const char *node,
const char *domain,
const char *resource)
{
@@ -36,7 +37,8 @@ char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
size_t len, nlen, dlen, rlen;
/* jid must at least have a domain */
if (domain == NULL) return NULL;
if (domain == NULL)
return NULL;
/* accumulate lengths */
dlen = strlen(domain);

View File

@@ -43,8 +43,7 @@
(cp)[3] = ((value) >> 24) & 0xFF; \
} while (0)
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
struct MD5Context *ctx);
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64]);
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
@@ -91,7 +90,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
return;
}
memcpy(p, buf, t);
MD5Transform(ctx->buf, ctx->in, ctx);
MD5Transform(ctx->buf, ctx->in);
buf += t;
len -= t;
}
@@ -99,7 +98,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, uint32_t len)
while (len >= 64) {
memcpy(ctx->in, buf, 64);
MD5Transform(ctx->buf, ctx->in, ctx);
MD5Transform(ctx->buf, ctx->in);
buf += 64;
len -= 64;
}
@@ -133,7 +132,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
MD5Transform(ctx->buf, ctx->in, ctx);
MD5Transform(ctx->buf, ctx->in);
/* Now fill the next block with 56 bytes */
memset(ctx->in, 0, 56);
@@ -146,7 +145,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]);
PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]);
MD5Transform(ctx->buf, ctx->in, ctx);
MD5Transform(ctx->buf, ctx->in);
PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]);
PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]);
PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]);
@@ -180,8 +179,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64],
struct MD5Context *ctx)
static void MD5Transform(uint32_t buf[4], const unsigned char inext[64])
{
register uint32_t a, b, c, d, i;
uint32_t in[16];

View File

@@ -21,7 +21,8 @@ struct MD5Context {
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
void MD5Update(struct MD5Context *context,
unsigned char const *buf,
uint32_t len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);

View File

@@ -1,84 +0,0 @@
/* oocontext.cpp
** strophe XMPP client library -- C++ context implementation
**
** 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 <stdlib.h>
#include "strophe.h"
#include "strophepp.h"
XMPP::Context::Context()
{
m_mem.alloc = callAlloc;
m_mem.realloc = callRealloc;
m_mem.free = callFree;
m_mem.userdata = (void *)this;
m_log.handler = callLog;
m_log.userdata = (void *)this;
m_ctx = ::xmpp_ctx_new(&m_mem, &m_log);
}
XMPP::Context::~Context()
{
::xmpp_ctx_free(m_ctx);
}
void *XMPP::Context::alloc(const size_t size)
{
return ::malloc(size);
}
void *XMPP::Context::realloc(void *p, const size_t size)
{
return ::realloc(p, size);
}
void XMPP::Context::free(void *p)
{
::free(p);
}
void XMPP::Context::log(const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
/* do nothing by default */
}
xmpp_ctx_t *XMPP::Context::getContext()
{
return m_ctx;
}
void *XMPP::Context::callAlloc(const size_t size, void * const userdata)
{
return reinterpret_cast<Context *>(userdata)->alloc(size);
}
void *XMPP::Context::callRealloc(void *p, const size_t size,
void * const userdata)
{
return reinterpret_cast<Context *>(userdata)->realloc(p, size);
}
void XMPP::Context::callFree(void *p, void * const userdata)
{
reinterpret_cast<Context *>(userdata)->free(p);
}
void XMPP::Context::callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg)
{
reinterpret_cast<Context *>(userdata)->log(level, area, msg);
}

View File

@@ -1,77 +0,0 @@
/* oostanza.cpp
** strophe XMPP client library -- C++ context implementation
**
** 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 "strophe.h"
#include "strophepp.h"
using namespace XMPP;
void *Stanza::operator new(size_t size, Context *ctx)
{
void *p;
/* we must allocate extra room for the Context object so that the
destructor can access it to free the object. C++ does not allow
us to access normal members in the destructor, so we have to hide
it. This must be prepended as well, since C++ will add stuff to
the end in subclasses. */
p = ctx->alloc(size + sizeof(Context *));
if (!p) return p;
*reinterpret_cast<Context **>(p) = ctx;
p = reinterpret_cast<void *>(reinterpret_cast<char *>(p) +
sizeof(Context *));
return p;
}
void Stanza::operator delete(void *p)
{
Context *ctx;
ctx = *reinterpret_cast<Context **>(reinterpret_cast<char *>(p) - 4);
ctx->free(reinterpret_cast<char *>(p) - 4);
}
Stanza::Stanza(Context *ctx)
{
m_ctx = ctx;
m_stanza = ::xmpp_stanza_new(ctx->getContext());
// TODO: check for errors
}
Stanza::~Stanza()
{
}
Stanza *Stanza::create(Context *ctx)
{
return new (ctx) Stanza(ctx);
}
void Stanza::release()
{
if (::xmpp_stanza_release(m_stanza))
delete this;
}
Stanza *Stanza::clone()
{
::xmpp_stanza_clone(m_stanza);
return this;
}
Stanza *Stanza::copy()
{
// TODO
return NULL;
}

View File

@@ -20,13 +20,9 @@
typedef struct _parser_t parser_t;
typedef void (*parser_start_callback)(char *name,
char **attrs,
void * const userdata);
typedef void (*parser_end_callback)(char *name, void * const userdata);
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza,
void * const userdata);
typedef void (*parser_start_callback)(char *name, char **attrs, void *userdata);
typedef void (*parser_end_callback)(char *name, void *userdata);
typedef void (*parser_stanza_callback)(xmpp_stanza_t *stanza, void *userdata);
parser_t *parser_new(xmpp_ctx_t *ctx,
parser_start_callback startcb,

View File

@@ -19,13 +19,10 @@
#include <expat.h>
#include <strophe.h>
#include "strophe.h"
#include "common.h"
#include "parser.h"
/* Use the Unit Separator to delimit namespace and name in our XML*/
#define NAMESPACE_SEP ('\x1F')
/* Allocate inner text by this number bytes more. Expat splits string
* "new\nline" into 3 strings: "new" "\n" "line". Expecting this pattern,
* we can leave few bytes in the inner_text for "\n". It should reduce
@@ -48,6 +45,46 @@ struct _parser_t {
int inner_text_used;
};
/* Use the Unit Separator to delimit namespace and name in our XML */
const XML_Char namespace_sep = '\x1F';
/*
* Cached strophe ctx. It is used for memory suite.
* Note, expat doesn't support userdata in memory suite, therefore,
* we can support only one strophe context. If user creates more than one
* context, this module will fallback to default library allocator for all
* contexts other than mem_ctx.
*/
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);
else
return NULL;
}
static void *parser_mem_realloc(void *ptr, size_t size)
{
if (mem_ctx != NULL)
return xmpp_realloc(mem_ctx, ptr, size);
else
return NULL;
}
static void parser_mem_free(void *ptr)
{
if (mem_ctx != NULL)
xmpp_free(mem_ctx, ptr);
}
static const XML_Memory_Handling_Suite parser_mem_suite = {
.malloc_fcn = &parser_mem_malloc,
.realloc_fcn = &parser_mem_realloc,
.free_fcn = &parser_mem_free,
};
/* return allocated string with the name from a delimited
* namespace/name string */
static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
@@ -56,8 +93,9 @@ static char *_xml_name(xmpp_ctx_t *ctx, const char *nsname)
const char *c;
size_t len;
c = strchr(nsname, NAMESPACE_SEP);
if (c == NULL) return xmpp_strdup(ctx, nsname);
c = strchr(nsname, namespace_sep);
if (c == NULL)
return xmpp_strdup(ctx, nsname);
c++;
len = strlen(c);
@@ -76,7 +114,7 @@ static char *_xml_namespace(xmpp_ctx_t *ctx, const char *nsname)
char *result = NULL;
const char *c;
c = strchr(nsname, NAMESPACE_SEP);
c = strchr(nsname, namespace_sep);
if (c != NULL) {
result = xmpp_alloc(ctx, (c - nsname) + 1);
if (result != NULL) {
@@ -93,7 +131,8 @@ static void _set_attributes(xmpp_stanza_t *stanza, const XML_Char **attrs)
char *attr;
int i;
if (!attrs) return;
if (!attrs)
return;
for (i = 0; attrs[i]; i += 2) {
/* namespaced attributes aren't used in xmpp, discard namespace */
@@ -123,9 +162,8 @@ static void complete_inner_text(parser_t *parser)
}
}
static void _start_element(void *userdata,
const XML_Char *nsname,
const XML_Char **attrs)
static void
_start_element(void *userdata, const XML_Char *nsname, const XML_Char **attrs)
{
parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *child;
@@ -137,8 +175,7 @@ static void _start_element(void *userdata,
if (parser->depth == 0) {
/* notify the owner */
if (parser->startcb)
parser->startcb(name, (char **)attrs,
parser->userdata);
parser->startcb(name, (char **)attrs, parser->userdata);
} else {
/* build stanzas at depth 1 */
if (!parser->stanza && parser->depth != 1) {
@@ -164,8 +201,10 @@ static void _start_element(void *userdata,
}
}
if (ns) xmpp_free(parser->ctx, ns);
if (name) xmpp_free(parser->ctx, name);
if (ns)
xmpp_free(parser->ctx, ns);
if (name)
xmpp_free(parser->ctx, name);
parser->depth++;
}
@@ -187,8 +226,7 @@ static void _end_element(void *userdata, const XML_Char *name)
parser->stanza = parser->stanza->parent;
} else {
if (parser->stanzacb)
parser->stanzacb(parser->stanza,
parser->userdata);
parser->stanzacb(parser->stanza, parser->userdata);
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}
@@ -200,13 +238,14 @@ static void _characters(void *userdata, const XML_Char *s, int len)
parser_t *parser = (parser_t *)userdata;
char *p;
if (parser->depth < 2) return;
if (parser->depth < 2)
return;
/* Join all parts to a single resulting string. Stanza is created in
* _start_element() and _end_element(). */
if (parser->inner_text_used + len >= parser->inner_text_size) {
parser->inner_text_size = parser->inner_text_used + len + 1 +
INNER_TEXT_PADDING;
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);
if (p == NULL) {
@@ -273,23 +312,38 @@ void parser_free(parser_t *parser)
/* shuts down and restarts XML parser. true on success */
int parser_reset(parser_t *parser)
{
if (parser->expat)
XML_Bool ret;
const XML_Memory_Handling_Suite *mem = NULL;
if (parser->expat) {
ret = XML_ParserReset(parser->expat, NULL);
if (ret != XML_TRUE) {
XML_ParserFree(parser->expat);
parser->expat = NULL;
}
} else {
if (mem_ctx == NULL)
mem_ctx = parser->ctx;
if (parser->ctx == mem_ctx)
mem = &parser_mem_suite;
parser->expat = XML_ParserCreate_MM(NULL, mem, &namespace_sep);
}
if (parser->stanza)
if (parser->stanza) {
xmpp_stanza_release(parser->stanza);
parser->expat = XML_ParserCreateNS(NULL, NAMESPACE_SEP);
if (!parser->expat) return 0;
parser->depth = 0;
parser->stanza = NULL;
}
if (parser->inner_text) {
xmpp_free(parser->ctx, parser->inner_text);
parser->inner_text = NULL;
}
if (!parser->expat)
return 0;
parser->depth = 0;
XML_SetUserData(parser->expat, parser);
XML_SetElementHandler(parser->expat, _start_element, _end_element);
XML_SetCharacterDataHandler(parser->expat, _characters);

View File

@@ -20,7 +20,7 @@
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <strophe.h>
#include "strophe.h"
#include "common.h"
#include "parser.h"
@@ -36,13 +36,14 @@ struct _parser_t {
xmpp_stanza_t *stanza;
};
static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
const xmlChar **attrs)
static void
_set_attributes(xmpp_stanza_t *stanza, int nattrs, const xmlChar **attrs)
{
int i, len;
char *value;
if (!attrs) return;
if (!attrs)
return;
/* SAX2 uses array of localname/prefix/uri/value_begin/value_end */
for (i = 0; i < nattrs * 5; i += 5) {
@@ -59,17 +60,19 @@ static void _set_attributes(xmpp_stanza_t *stanza, int nattrs,
/* SAX2 gives us the attrs in an incredibly inconvenient array,
* convert it to what the start callback is expecting */
static char **_convert_attrs(parser_t *parser, int nattrs,
const xmlChar **attrs)
static char **
_convert_attrs(parser_t *parser, int nattrs, const xmlChar **attrs)
{
int c, i, o, len;
char *value;
char **ret;
if (!attrs) return NULL;
if (!attrs)
return NULL;
ret = xmpp_alloc(parser->ctx, (nattrs + 1) * 2 * sizeof(char *));
if (!ret) return NULL;
if (!ret)
return NULL;
memset(ret, 0, (nattrs + 1) * 2 * sizeof(char *));
for (c = 0; c < nattrs; c++) {
@@ -97,29 +100,39 @@ static void _free_cbattrs(parser_t *parser, char **attrs)
return;
for (i = 0; attrs[i]; i += 2) {
if (attrs[i]) xmpp_free(parser->ctx, attrs[i]);
if (attrs[i+1]) xmpp_free(parser->ctx, attrs[i+1]);
if (attrs[i])
xmpp_free(parser->ctx, attrs[i]);
if (attrs[i + 1])
xmpp_free(parser->ctx, attrs[i + 1]);
}
xmpp_free(parser->ctx, attrs);
}
static void _start_element(void *userdata,
const xmlChar *name, const xmlChar *prefix,
const xmlChar *uri, int nnamespaces,
const xmlChar **namespaces, int nattrs,
int ndefaulted, const xmlChar **attrs)
const xmlChar *name,
const xmlChar *prefix,
const xmlChar *uri,
int nnamespaces,
const xmlChar **namespaces,
int nattrs,
int ndefaulted,
const xmlChar **attrs)
{
parser_t *parser = (parser_t *)userdata;
xmpp_stanza_t *child;
char **cbattrs;
UNUSED(prefix);
UNUSED(nnamespaces);
UNUSED(namespaces);
UNUSED(ndefaulted);
if (parser->depth == 0) {
/* notify the owner */
if (parser->startcb) {
cbattrs = _convert_attrs(parser, nattrs, attrs);
parser->startcb((char *)name, cbattrs,
parser->userdata);
parser->startcb((char *)name, cbattrs, parser->userdata);
_free_cbattrs(parser, cbattrs);
}
} else {
@@ -163,11 +176,16 @@ static void _start_element(void *userdata,
parser->depth++;
}
static void _end_element(void *userdata, const xmlChar *name,
const xmlChar *prefix, const xmlChar *uri)
static void _end_element(void *userdata,
const xmlChar *name,
const xmlChar *prefix,
const xmlChar *uri)
{
parser_t *parser = (parser_t *)userdata;
UNUSED(prefix);
UNUSED(uri);
parser->depth--;
if (parser->depth == 0) {
@@ -180,8 +198,7 @@ static void _end_element(void *userdata, const xmlChar *name,
parser->stanza = parser->stanza->parent;
} else {
if (parser->stanzacb)
parser->stanzacb(parser->stanza,
parser->userdata);
parser->stanzacb(parser->stanza, parser->userdata);
xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
}
@@ -194,7 +211,8 @@ static void _characters(void *userdata, const xmlChar *chr, int len)
xmpp_stanza_t *stanza;
/* skip unimportant whitespace, etc */
if (parser->depth < 2) return;
if (parser->depth < 2)
return;
/* create and populate stanza */
stanza = xmpp_stanza_new(parser->ctx);
@@ -265,8 +283,8 @@ int parser_reset(parser_t *parser)
parser->stanza = NULL;
parser->depth = 0;
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
parser, NULL, 0, NULL);
parser->xmlctx =
xmlCreatePushParserCtxt(&parser->handlers, parser, NULL, 0, NULL);
return parser->xmlctx ? 1 : 0;
}

View File

@@ -62,8 +62,8 @@ struct _xmpp_rand_t {
/* adds two arrays as numbers in big-endian representation and stores
* result in the first one.
*/
static void arr_add(uint8_t *arr1, size_t arr1_len,
uint8_t *arr2, size_t arr2_len)
static void
arr_add(uint8_t *arr1, size_t arr1_len, uint8_t *arr2, size_t arr2_len)
{
size_t i;
uint32_t acc;
@@ -89,8 +89,10 @@ static void store_be32(uint32_t val, uint8_t be[4])
be[3] = (uint8_t)(val & 0xff);
}
static void Hash_df(uint8_t *input_string, size_t input_string_len,
uint8_t *output_string, size_t no_of_bytes_to_return)
static void Hash_df(uint8_t *input_string,
size_t input_string_len,
uint8_t *output_string,
size_t no_of_bytes_to_return)
{
uint8_t counter;
uint8_t temp[round_up(seedlen, outlen)];
@@ -119,7 +121,8 @@ static void Hash_df(uint8_t *input_string, size_t input_string_len,
static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
uint8_t *entropy_input,
size_t entropy_input_len,
uint8_t *nonce, size_t nonce_len)
uint8_t *nonce,
size_t nonce_len)
{
uint8_t seed_material[ENTROPY_MAX + NONCE_MAX];
uint8_t seed0[seedlen + 1];
@@ -162,8 +165,8 @@ static void Hash_DRBG_Reseed(Hash_DRBG_CTX *ctx,
ctx->reseed_counter = 1;
}
static void Hashgen(uint8_t *V, uint8_t *output,
size_t requested_number_of_bytes)
static void
Hashgen(uint8_t *V, uint8_t *output, size_t requested_number_of_bytes)
{
uint8_t data[seedlen];
uint8_t W[GENERATE_MAX];
@@ -187,7 +190,8 @@ static void Hashgen(uint8_t *V, uint8_t *output,
}
/* assume additional_input is zero length string */
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx, uint8_t *output,
static int Hash_DRBG_Generate(Hash_DRBG_CTX *ctx,
uint8_t *output,
size_t requested_number_of_bytes)
{
uint8_t H[outlen];
@@ -289,25 +293,32 @@ int xmpp_rand(xmpp_rand_t *rand)
return result;
}
static void rand_byte2hex(unsigned char byte, char *hex)
{
static const char hex_tbl[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
hex[0] = hex_tbl[(byte >> 4) & 0x0f];
hex[1] = hex_tbl[byte & 0x0f];
}
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len)
{
size_t i;
size_t rand_len = len / 2;
#ifndef _MSC_VER
unsigned char rand_buf[rand_len];
#else
unsigned char *rand_buf = (unsigned char *)_alloca(rand_len);
#endif
const size_t rand_len = len / 2;
/* current implementation returns printable HEX representation of
* a random buffer, however base64 encoding can be used instead;
* the only problem is that base64_encode() allocates memory and
* as result can fail.
/*
* We don't want to use any allocation here, because this function
* can't fail. Also we want to avoid VLA.
* Current implementation uses half of the output buffer for random buffer
* generation and then converts it to HEX representation.
*/
xmpp_rand_bytes(rand, rand_buf, rand_len);
for (i = 0; i < rand_len; ++i) {
xmpp_snprintf(output + i * 2, len, "%02x", rand_buf[i]);
len -= 2;
if (rand_len > 0) {
xmpp_rand_bytes(rand, (unsigned char *)output, rand_len);
for (i = rand_len; i > 0; --i)
rand_byte2hex(output[i - 1], &output[(i - 1) * 2]);
}
if (len > 0)
output[len - 1] = '\0';
}

View File

@@ -16,11 +16,19 @@
#if !defined(_WIN32) && !defined(HAVE_CARES)
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h> /* res_query */
#include <resolv.h>
#endif /* _WIN32 && HAVE_CARES */
#ifdef HAVE_CARES
#include <ares.h>
/* for select(2) */
#ifdef _WIN32
#include <winsock2.h>
#else /* _WIN32 */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif /* !_WIN32 */
#endif /* HAVE_CARES */
#include <string.h> /* strncpy */
@@ -44,7 +52,8 @@ static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
const unsigned char *buf,
size_t len,
resolver_srv_rr_t **srv_rr_list);
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx,
const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
#endif /* HAVE_CARES */
@@ -55,12 +64,14 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
resolver_srv_rr_t **srv_rr_list);
#endif /* !HAVE_CARES */
#ifdef _WIN32
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
#if defined(_WIN32) && !defined(HAVE_CARES)
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx,
const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len);
#endif /* _WIN32 */
unsigned char *buf,
size_t len);
#endif /* _WIN32 && !HAVE_CARES */
/*******************************************************************************
* Implementation.
@@ -110,8 +121,7 @@ static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
*/
if ((rr_current->priority > rr_next->priority) ||
(rr_current->priority == rr_next->priority &&
rr_current->weight < rr_next->weight))
{
rr_current->weight < rr_next->weight)) {
/* Swap node */
swap = 1;
if (rr_prev != NULL) {
@@ -137,8 +147,10 @@ static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
*srv_rr_list = rr_head;
}
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list)
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx,
const unsigned char *buf,
size_t len,
resolver_srv_rr_t **srv_rr_list)
{
int set;
@@ -152,8 +164,11 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
return set;
}
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list)
int resolver_srv_lookup(xmpp_ctx_t *ctx,
const char *service,
const char *proto,
const char *domain,
resolver_srv_rr_t **srv_rr_list)
{
#define RESOLVER_BUF_MAX 65536
unsigned char *buf;
@@ -164,13 +179,15 @@ int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
(void)buf;
(void)len;
xmpp_snprintf(fulldomain, sizeof(fulldomain),
"_%s._%s.%s", service, proto, domain);
xmpp_snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service, proto,
domain);
*srv_rr_list = NULL;
#ifdef HAVE_CARES
set = resolver_ares_srv_lookup(ctx, fulldomain, srv_rr_list);
#else /* HAVE_CARES */
#ifdef _WIN32
@@ -251,9 +268,11 @@ static uint8_t message_header_rcode(const struct message_header *header)
* Returns length of the non-truncated resulting string, may be bigger than
* name_max.
*/
static size_t message_name_append_safe(char *name, size_t name_len,
static size_t message_name_append_safe(char *name,
size_t name_len,
size_t name_max,
const char *tail, size_t tail_len)
const char *tail,
size_t tail_len)
{
size_t copy_len;
@@ -266,9 +285,11 @@ static size_t message_name_append_safe(char *name, size_t name_len,
}
/* Returns length of the compressed name. This is NOT the same as strlen(). */
static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
static unsigned message_name_get(const unsigned char *buf,
size_t buf_len,
unsigned buf_offset,
char *name, size_t name_max)
char *name,
size_t name_max)
{
size_t name_len = 0;
unsigned i = buf_offset;
@@ -276,26 +297,29 @@ static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
unsigned rc;
unsigned char label_len;
while (1) {
if (i >= buf_len) return 0;
if (i >= buf_len)
return 0;
label_len = buf[i++];
if (label_len == 0) break;
if (label_len == 0)
break;
/* Label */
if ((label_len & 0xc0) == 0) {
if (i + label_len - 1 >= buf_len) return 0;
if (i + label_len - 1 >= buf_len)
return 0;
if (name != NULL) {
name_len = message_name_append_safe(name, name_len, name_max,
(char *)&buf[i], label_len);
name_len = message_name_append_safe(name, name_len, name_max,
".", 1);
name_len =
message_name_append_safe(name, name_len, name_max, ".", 1);
}
i += label_len;
/* Pointer */
} else if ((label_len & 0xc0) == 0xc0) {
if (i >= buf_len) return 0;
if (i >= buf_len)
return 0;
pointer = (label_len & 0x3f) << 8 | buf[i++];
if (name != NULL && name_len >= name_max && name_max > 0) {
/* We have filled the name buffer. Don't pass it recursively. */
@@ -303,10 +327,11 @@ static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
name = NULL;
name_max = 0;
}
rc = message_name_get(buf, buf_len, pointer,
name != NULL ? &name[name_len] : NULL,
rc = message_name_get(
buf, buf_len, pointer, name != NULL ? &name[name_len] : NULL,
name_max > name_len ? name_max - name_len : 0);
if (rc == 0) return 0;
if (rc == 0)
return 0;
/* Pointer is always the last. */
break;
@@ -316,7 +341,8 @@ static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
}
}
if (label_len == 0) {
if (name_len == 0) name_len = 1;
if (name_len == 0)
name_len = 1;
/*
* At this point name_len is length of the resulting name,
* including '\0'. This value can be exported to allocate buffer
@@ -334,13 +360,14 @@ static unsigned message_name_get(const unsigned char *buf, size_t buf_len,
return i - buf_offset;
}
static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
unsigned buf_offset)
static unsigned
message_name_len(const unsigned char *buf, size_t buf_len, unsigned buf_offset)
{
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
}
#define BUF_OVERFLOW_CHECK(ptr, len) do { \
#define BUF_OVERFLOW_CHECK(ptr, len) \
do { \
if ((ptr) >= (len)) { \
if (*srv_rr_list != NULL) \
resolver_srv_free(ctx, *srv_rr_list); \
@@ -376,8 +403,7 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
header.nscount = xmpp_ntohs_ptr(&buf[8]);
header.arcount = xmpp_ntohs_ptr(&buf[10]);
if (message_header_qr(&header) != MESSAGE_RESPONSE ||
message_header_rcode(&header) != 0)
{
message_header_rcode(&header) != 0) {
return XMPP_DOMAIN_NOT_FOUND;
}
j = MESSAGE_HEADER_LEN;
@@ -387,7 +413,8 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
BUF_OVERFLOW_CHECK(j, len);
name_len = message_name_len(buf, len, j);
/* error in name format */
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
if (name_len == 0)
return XMPP_DOMAIN_NOT_FOUND;
j += name_len + 4;
}
@@ -395,7 +422,8 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
BUF_OVERFLOW_CHECK(j, len);
name_len = message_name_len(buf, len, j);
/* error in name format */
if (name_len == 0) return XMPP_DOMAIN_NOT_FOUND;
if (name_len == 0)
return XMPP_DOMAIN_NOT_FOUND;
j += name_len;
BUF_OVERFLOW_CHECK(j + 16, len);
type = xmpp_ntohs_ptr(&buf[j]);
@@ -469,11 +497,13 @@ static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
return *srv_rr_list == NULL ? XMPP_DOMAIN_NOT_FOUND : XMPP_DOMAIN_FOUND;
}
static void ares_srv_lookup_callback(void *arg, int status, int timeouts,
unsigned char *buf, int len)
static void ares_srv_lookup_callback(
void *arg, int status, int timeouts, unsigned char *buf, int len)
{
struct resolver_ares_ctx *actx = arg;
(void)timeouts;
if (status != ARES_SUCCESS)
actx->result = XMPP_DOMAIN_NOT_FOUND;
else
@@ -481,7 +511,8 @@ static void ares_srv_lookup_callback(void *arg, int status, int timeouts,
&actx->srv_rr_list);
}
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx,
const char *fulldomain,
resolver_srv_rr_t **srv_rr_list)
{
struct resolver_ares_ctx actx;
@@ -520,7 +551,7 @@ static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
#endif /* HAVE_CARES */
#ifdef _WIN32
#if defined(_WIN32) && !defined(HAVE_CARES)
/*******************************************************************************
* Next part was copied from sock.c and contains old win32 code.
*
@@ -536,10 +567,9 @@ static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windns.h>
#include <Iphlpapi.h>
#include <iphlpapi.h>
struct dnsquery_header
{
struct dnsquery_header {
unsigned short id;
unsigned char qr;
unsigned char opcode;
@@ -555,14 +585,16 @@ struct dnsquery_header
unsigned short arcount;
};
struct dnsquery_question
{
struct dnsquery_question {
char qname[1024];
unsigned short qtype;
unsigned short qclass;
};
static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, unsigned short num)
static void netbuf_add_16bitnum(unsigned char *buf,
int buflen,
int *offset,
unsigned short num)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
@@ -574,8 +606,8 @@ static void netbuf_add_16bitnum(unsigned char *buf, int buflen, int *offset, uns
*offset += 2;
}
static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
char *name)
static void
netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset, char *name)
{
unsigned char *start = buf + *offset;
unsigned char *p = start;
@@ -583,31 +615,26 @@ static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
wordstart = (unsigned char *)name;
while (*wordstart)
{
while (*wordstart) {
int len;
wordend = wordstart;
while (*wordend && *wordend != '.')
{
while (*wordend && *wordend != '.') {
wordend++;
}
len = (int)(wordend - wordstart);
if (len > 0x3F)
{
if (len > 0x3F) {
len = 0x3F;
}
*p++ = len;
while (wordstart != wordend)
{
while (wordstart != wordend) {
*p++ = *wordstart++;
}
if (*wordstart == '.')
{
if (*wordstart == '.') {
wordstart++;
}
}
@@ -617,21 +644,21 @@ static void netbuf_add_domain_name(unsigned char *buf, int buflen, int *offset,
*offset += (int)(p - start);
}
static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offset, struct dnsquery_header *header)
static void netbuf_add_dnsquery_header(unsigned char *buf,
int buflen,
int *offset,
struct dnsquery_header *header)
{
unsigned char *p;
netbuf_add_16bitnum(buf, buflen, offset, header->id);
p = buf + *offset;
*p++ = ((header->qr & 0x01) << 7)
| ((header->opcode & 0x0F) << 3)
| ((header->aa & 0x01) << 2)
| ((header->tc & 0x01) << 1)
| ((header->rd & 0x01));
*p++ = ((header->ra & 0x01) << 7)
| ((header->z & 0x07) << 4)
| ((header->rcode & 0x0F));
*p++ = ((header->qr & 0x01) << 7) | ((header->opcode & 0x0F) << 3) |
((header->aa & 0x01) << 2) | ((header->tc & 0x01) << 1) |
((header->rd & 0x01));
*p++ = ((header->ra & 0x01) << 7) | ((header->z & 0x07) << 4) |
((header->rcode & 0x0F));
*offset += 2;
netbuf_add_16bitnum(buf, buflen, offset, header->qdcount);
@@ -640,31 +667,38 @@ static void netbuf_add_dnsquery_header(unsigned char *buf, int buflen, int *offs
netbuf_add_16bitnum(buf, buflen, offset, header->arcount);
}
static void netbuf_add_dnsquery_question(unsigned char *buf, int buflen, int *offset, struct dnsquery_question *question)
static void netbuf_add_dnsquery_question(unsigned char *buf,
int buflen,
int *offset,
struct dnsquery_question *question)
{
netbuf_add_domain_name(buf, buflen, offset, question->qname);
netbuf_add_16bitnum(buf, buflen, offset, question->qtype);
netbuf_add_16bitnum(buf, buflen, offset, question->qclass);
}
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx,
const char *fulldomain,
resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t *rr;
HINSTANCE hdnsapi = NULL;
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA**, PVOID*);
DNS_STATUS(WINAPI * pDnsQuery_A)
(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA **, PVOID *);
void(WINAPI * pDnsRecordListFree)(DNS_RECORDA *, DNS_FREE_TYPE);
if (hdnsapi = LoadLibrary("dnsapi.dll")) {
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
pDnsRecordListFree =
(void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
if (pDnsQuery_A && pDnsRecordListFree) {
DNS_RECORDA *dnsrecords = NULL;
DNS_STATUS error;
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD,
NULL, &dnsrecords, NULL);
if (error == 0) {
DNS_RECORDA *current = dnsrecords;
@@ -696,15 +730,15 @@ static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
}
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len)
static int
resolver_win32_srv_query(const char *fulldomain, unsigned char *buf, size_t len)
{
int set = 0;
int insize = 0;
/* if dnsapi didn't work/isn't there, try querying the dns server manually */
if (!set)
{
/* if dnsapi didn't work/isn't there, try querying the dns server manually
*/
if (!set) {
struct dnsquery_header header;
struct dnsquery_question question;
int offset = 0;
@@ -715,18 +749,17 @@ static int resolver_win32_srv_query(const char *fulldomain,
int numdnsservers = 0;
int j;
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi first */
if (!numdnsservers)
{
/* Try getting the DNS server ips from GetNetworkParams() in iphlpapi
* first */
if (!numdnsservers) {
HINSTANCE hiphlpapi = NULL;
DWORD(WINAPI * pGetNetworkParams)(PFIXED_INFO, PULONG);
if (hiphlpapi = LoadLibrary("Iphlpapi.dll"))
{
pGetNetworkParams = (void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
if (hiphlpapi = LoadLibrary("Iphlpapi.dll")) {
pGetNetworkParams =
(void *)GetProcAddress(hiphlpapi, "GetNetworkParams");
if (pGetNetworkParams)
{
if (pGetNetworkParams) {
FIXED_INFO *fi;
ULONG len;
DWORD error;
@@ -735,13 +768,13 @@ static int resolver_win32_srv_query(const char *fulldomain,
len = 65535;
fi = (FIXED_INFO *)buffer;
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
{
if ((error = pGetNetworkParams(fi, &len)) ==
ERROR_SUCCESS) {
IP_ADDR_STRING *pias = &(fi->DnsServerList);
while (pias && numdnsservers < 16)
{
strcpy(dnsserverips[numdnsservers++], pias->IpAddress.String);
while (pias && numdnsservers < 16) {
strcpy(dnsserverips[numdnsservers++],
pias->IpAddress.String);
pias = pias->Next;
}
}
@@ -751,48 +784,49 @@ static int resolver_win32_srv_query(const char *fulldomain,
}
/* Next, try getting the DNS server ips from the registry */
if (!numdnsservers)
{
if (!numdnsservers) {
HKEY search;
LONG error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &search);
error = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0,
KEY_READ, &search);
if (error != ERROR_SUCCESS)
{
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &search);
if (error != ERROR_SUCCESS) {
error = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0,
KEY_READ, &search);
}
if (error == ERROR_SUCCESS)
{
if (error == ERROR_SUCCESS) {
char name[512];
DWORD len = 512;
error = RegQueryValueEx(search, "NameServer", NULL, NULL, (LPBYTE)name, &len);
error = RegQueryValueEx(search, "NameServer", NULL, NULL,
(LPBYTE)name, &len);
if (error != ERROR_SUCCESS)
{
error = RegQueryValueEx(search, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len);
if (error != ERROR_SUCCESS) {
error = RegQueryValueEx(search, "DhcpNameServer", NULL,
NULL, (LPBYTE)name, &len);
}
if (error == ERROR_SUCCESS)
{
if (error == ERROR_SUCCESS) {
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
while (*start && numdnsservers < 16) {
while (strchr(parse, *end)) {
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
strncpy(dnsserverips[numdnsservers++], start,
end - start);
while (*end && !strchr(parse, *end))
{
while (*end && !strchr(parse, *end)) {
end++;
}
@@ -804,72 +838,71 @@ static int resolver_win32_srv_query(const char *fulldomain,
RegCloseKey(search);
}
if (!numdnsservers)
{
if (!numdnsservers) {
HKEY searchlist;
LONG error;
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &searchlist);
error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\P"
"arameters\\Interfaces",
0, KEY_READ, &searchlist);
if (error == ERROR_SUCCESS)
{
if (error == ERROR_SUCCESS) {
unsigned int i;
DWORD numinterfaces = 0;
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
RegQueryInfoKey(searchlist, NULL, NULL, NULL, &numinterfaces,
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
for (i = 0; i < numinterfaces; i++)
{
for (i = 0; i < numinterfaces; i++) {
char name[512];
DWORD len = 512;
HKEY searchentry;
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL, NULL, NULL);
RegEnumKeyEx(searchlist, i, (LPTSTR)name, &len, NULL, NULL,
NULL, NULL);
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ, &searchentry) == ERROR_SUCCESS)
{
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
{
if (RegOpenKeyEx(searchlist, name, 0, KEY_READ,
&searchentry) == ERROR_SUCCESS) {
if (RegQueryValueEx(searchentry, "DhcpNameServer", NULL,
NULL, (LPBYTE)name,
&len) == ERROR_SUCCESS) {
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
while (*start && numdnsservers < 16) {
while (strchr(parse, *end)) {
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
strncpy(dnsserverips[numdnsservers++], start,
end - start);
while (*end && !strchr(parse, *end))
{
while (*end && !strchr(parse, *end)) {
end++;
}
start = end;
}
}
else if (RegQueryValueEx(searchentry, "NameServer", NULL, NULL, (LPBYTE)name, &len) == ERROR_SUCCESS)
{
} else if (RegQueryValueEx(searchentry, "NameServer",
NULL, NULL, (LPBYTE)name,
&len) == ERROR_SUCCESS) {
char *parse = "0123456789.", *start, *end;
start = name;
end = name;
name[len] = '\0';
while (*start && numdnsservers < 16)
{
while (strchr(parse, *end))
{
while (*start && numdnsservers < 16) {
while (strchr(parse, *end)) {
end++;
}
strncpy(dnsserverips[numdnsservers++], start, end - start);
strncpy(dnsserverips[numdnsservers++], start,
end - start);
while (*end && !strchr(parse, *end))
{
while (*end && !strchr(parse, *end)) {
end++;
}
@@ -884,8 +917,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
}
/* If we have a DNS server, use it */
if (numdnsservers)
{
if (numdnsservers) {
ULONG nonblocking = 1;
int i;
@@ -898,14 +930,13 @@ static int resolver_win32_srv_query(const char *fulldomain,
memset(&question, 0, sizeof(question));
strncpy(question.qname, fulldomain, 1024);
question.qtype = 33; /* SRV */
question.qclass = 1; /* INTERNET! */
question.qtype = MESSAGE_T_SRV; /* SRV */
question.qclass = MESSAGE_C_IN; /* INTERNET! */
netbuf_add_dnsquery_question(buf, (int)len, &offset, &question);
insize = 0;
for (i = 0; i < numdnsservers && insize <= 0; i++)
{
for (i = 0; i < numdnsservers && insize <= 0; i++) {
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ioctlsocket(sock, FIONBIO, &nonblocking);
@@ -916,23 +947,18 @@ static int resolver_win32_srv_query(const char *fulldomain,
dnsaddr.sin_addr.s_addr = inet_addr(dnsserverips[i]);
addrlen = sizeof(dnsaddr);
sendto(sock, (char *)buf, offset, 0, (struct sockaddr *)&dnsaddr, addrlen);
for (j = 0; j < 50; j++)
{
insize = recvfrom(sock, (char *)buf, (int)len, 0, (struct sockaddr *)&dnsaddr, &addrlen);
if (insize == SOCKET_ERROR)
{
if (sock_error() == WSAEWOULDBLOCK)
{
sendto(sock, (char *)buf, offset, 0,
(struct sockaddr *)&dnsaddr, addrlen);
for (j = 0; j < 50; j++) {
insize = recvfrom(sock, (char *)buf, (int)len, 0,
(struct sockaddr *)&dnsaddr, &addrlen);
if (insize == SOCKET_ERROR) {
if (sock_error() == WSAEWOULDBLOCK) {
Sleep(100);
}
else
{
} else {
break;
}
}
else
{
} else {
break;
}
}
@@ -941,10 +967,9 @@ static int resolver_win32_srv_query(const char *fulldomain,
}
set = insize > 0;
}
}
return set ? insize : -1;
}
#endif /* _WIN32 */
#endif /* _WIN32 && !HAVE_CARES */

View File

@@ -46,8 +46,10 @@ void resolver_shutdown(void);
*
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
*/
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list);
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx,
const unsigned char *buf,
size_t len,
resolver_srv_rr_t **srv_rr_list);
/** Resolve SRV record.
*
* @param ctx a Strophe context object
@@ -58,8 +60,11 @@ int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
*
* @return XMPP_DOMAIN_FOUND on success or XMPP_DOMAIN_NOT_FOUND on fail
*/
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list);
int resolver_srv_lookup(xmpp_ctx_t *ctx,
const char *service,
const char *proto,
const char *domain,
resolver_srv_rr_t **srv_rr_list);
/** Release a list returned by resolver_srv_lookup() or
* resolver_srv_lookup_buf().

View File

@@ -21,7 +21,6 @@
#include "ostypes.h"
#include "sasl.h"
#include "md5.h"
#include "sha1.h"
#include "scram.h"
#include "rand.h"
#include "util.h"
@@ -36,9 +35,9 @@
#endif
#endif /* _MSC_VER */
/** generate authentication string for the SASL PLAIN mechanism */
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password)
{
size_t idlen, passlen;
size_t msglen;
char *result = NULL;
@@ -66,7 +65,7 @@ char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password) {
/** helpers for digest auth */
/* create a new, null-terminated string from a substring */
static char *_make_string(xmpp_ctx_t *ctx, const char *s, const unsigned len)
static char *_make_string(xmpp_ctx_t *ctx, const char *s, unsigned len)
{
char *result;
@@ -113,13 +112,17 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
s = text;
while (*s != '\0') {
/* skip any leading commas and spaces */
while ((*s == ',') || (*s == ' ')) s++;
while ((*s == ',') || (*s == ' '))
s++;
/* accumulate a key ending at '=' */
t = s;
while ((*t != '=') && (*t != '\0')) t++;
if (*t == '\0') break; /* bad string */
while ((*t != '=') && (*t != '\0'))
t++;
if (*t == '\0')
break; /* bad string */
key = _make_string(ctx, (char *)s, (t - s));
if (key == NULL) break;
if (key == NULL)
break;
/* advance our start pointer past the key */
s = t + 1;
t = s;
@@ -136,7 +139,8 @@ static hash_t *_parse_digest_challenge(xmpp_ctx_t *ctx, const char *msg)
}
/* otherwise, accumulate a value ending in ',' or '\0' */
} else {
while ((*t != ',') && (*t != '\0')) t++;
while ((*t != ',') && (*t != '\0'))
t++;
value = _make_string(ctx, (char *)s, (t - s));
s = t;
}
@@ -168,8 +172,8 @@ static void _digest_to_hex(const char *digest, char *hex)
}
/** append 'key="value"' to a buffer, growing as necessary */
static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
char *buf, int *len, int quote)
static char *
_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key, char *buf, int quote)
{
int olen, nlen;
int keylen, valuelen;
@@ -181,7 +185,8 @@ static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
buf = xmpp_alloc(ctx, 1);
buf[0] = '\0';
}
if (buf == NULL) return NULL;
if (buf == NULL)
return NULL;
/* get current string length */
olen = strlen(buf);
@@ -204,27 +209,33 @@ static char *_add_key(xmpp_ctx_t *ctx, hash_t *table, const char *key,
if (buf != NULL) {
c = buf + olen;
if (olen) *c++ = ',';
memcpy(c, key, keylen); c += keylen;
if (olen)
*c++ = ',';
memcpy(c, key, keylen);
c += keylen;
*c++ = '=';
memcpy(c, qvalue, valuelen); c += valuelen;
memcpy(c, qvalue, valuelen);
c += valuelen;
*c++ = '\0';
}
if (quote) xmpp_free(ctx, (char *)qvalue);
if (quote)
xmpp_free(ctx, (char *)qvalue);
return buf;
}
/** generate auth response string for the SASL DIGEST-MD5 mechanism */
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
const char *jid, const char *password) {
char *sasl_digest_md5(xmpp_ctx_t *ctx,
const char *challenge,
const char *jid,
const char *password)
{
hash_t *table;
char *result = NULL;
char *node, *domain, *realm;
char *value;
char *response;
int rlen;
struct MD5Context MD5;
unsigned char digest[16], HA1[16], HA2[16];
char hex[32];
@@ -340,16 +351,15 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
/* construct reply */
result = NULL;
rlen = 0;
result = _add_key(ctx, table, "username", result, &rlen, 1);
result = _add_key(ctx, table, "realm", result, &rlen, 1);
result = _add_key(ctx, table, "nonce", result, &rlen, 1);
result = _add_key(ctx, table, "cnonce", result, &rlen, 1);
result = _add_key(ctx, table, "nc", result, &rlen, 0);
result = _add_key(ctx, table, "qop", result, &rlen, 0);
result = _add_key(ctx, table, "digest-uri", result, &rlen, 1);
result = _add_key(ctx, table, "response", result, &rlen, 0);
result = _add_key(ctx, table, "charset", result, &rlen, 0);
result = _add_key(ctx, table, "username", result, 1);
result = _add_key(ctx, table, "realm", result, 1);
result = _add_key(ctx, table, "nonce", result, 1);
result = _add_key(ctx, table, "cnonce", result, 1);
result = _add_key(ctx, table, "nc", result, 0);
result = _add_key(ctx, table, "qop", result, 0);
result = _add_key(ctx, table, "digest-uri", result, 1);
result = _add_key(ctx, table, "response", result, 0);
result = _add_key(ctx, table, "charset", result, 0);
xmpp_free(ctx, node);
xmpp_free(ctx, domain);
@@ -362,13 +372,16 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
return response;
}
/** generate auth response string for the SASL SCRAM-SHA-1 mechanism */
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
const char *first_bare, const char *jid,
/** generate auth response string for the SASL SCRAM mechanism */
char *sasl_scram(xmpp_ctx_t *ctx,
const struct hash_alg *alg,
const char *challenge,
const char *first_bare,
const char *jid,
const char *password)
{
uint8_t key[SHA1_DIGEST_SIZE];
uint8_t sign[SHA1_DIGEST_SIZE];
uint8_t key[SCRAM_DIGEST_SIZE];
uint8_t sign[SCRAM_DIGEST_SIZE];
char *r = NULL;
char *s = NULL;
char *i = NULL;
@@ -385,7 +398,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
char *result = NULL;
size_t response_len;
size_t auth_len;
int j;
UNUSED(jid);
tmp = xmpp_strdup(ctx, challenge);
if (!tmp) {
@@ -420,7 +434,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
goto out_sval;
}
response_len = 39 + strlen(r);
/* "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);
if (!response) {
goto out_auth;
@@ -430,18 +445,17 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
xmpp_snprintf(auth, auth_len, "%s,%s,%s", first_bare + 3, challenge,
response);
SCRAM_SHA1_ClientKey((uint8_t *)password, strlen(password),
(uint8_t *)sval, sval_len, (uint32_t)ival, key);
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
sign[j] ^= key[j];
}
SCRAM_ClientKey(alg, (uint8_t *)password, strlen(password), (uint8_t *)sval,
sval_len, (uint32_t)ival, key);
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
SCRAM_ClientProof(alg, sign, key, sign);
sign_b64 = xmpp_base64_encode(ctx, sign, sizeof(sign));
sign_b64 = xmpp_base64_encode(ctx, sign, alg->digest_size);
if (!sign_b64) {
goto out_response;
}
/* Check for buffer overflow */
if (strlen(response) + strlen(sign_b64) + 3 + 1 > response_len) {
xmpp_free(ctx, sign_b64);
goto out_response;
@@ -450,8 +464,8 @@ char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
strcat(response, sign_b64);
xmpp_free(ctx, sign_b64);
response_b64 = xmpp_base64_encode(ctx, (unsigned char *)response,
strlen(response));
response_b64 =
xmpp_base64_encode(ctx, (unsigned char *)response, strlen(response));
if (!response_b64) {
goto out_response;
}

View File

@@ -17,14 +17,20 @@
#define __LIBSTROPHE_SASL_H__
#include "strophe.h"
#include "scram.h"
/** low-level sasl routines */
char *sasl_plain(xmpp_ctx_t *ctx, const char *authid, const char *password);
char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
const char *jid, const char *password);
char *sasl_scram_sha1(xmpp_ctx_t *ctx, const char *challenge,
const char *first_bare, const char *jid,
char *sasl_digest_md5(xmpp_ctx_t *ctx,
const char *challenge,
const char *jid,
const char *password);
char *sasl_scram(xmpp_ctx_t *ctx,
const struct hash_alg *alg,
const char *challenge,
const char *first_bare,
const char *jid,
const char *password);
#endif /* _LIBXMPP_SASL_H__ */

View File

@@ -19,56 +19,103 @@
#include <assert.h>
#include <string.h>
#include "common.h"
#include "sha1.h"
#include "sha256.h"
#include "sha512.h"
#include "ostypes.h"
#include "scram.h"
#define HMAC_BLOCK_SIZE 64
#define HMAC_BLOCK_SIZE_MAX 128
static const uint8_t ipad = 0x36;
static const uint8_t opad = 0x5C;
static void crypto_HMAC_SHA1(const uint8_t *key, size_t key_len,
const uint8_t *text, size_t len,
const struct hash_alg scram_sha1 = {
"SCRAM-SHA-1",
SASL_MASK_SCRAMSHA1,
SHA1_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))crypto_SHA1,
(void (*)(void *))crypto_SHA1_Init,
(void (*)(void *, const uint8_t *, size_t))crypto_SHA1_Update,
(void (*)(void *, uint8_t *))crypto_SHA1_Final};
const struct hash_alg scram_sha256 = {
"SCRAM-SHA-256",
SASL_MASK_SCRAMSHA256,
SHA256_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha256_hash,
(void (*)(void *))sha256_init,
(void (*)(void *, const uint8_t *, size_t))sha256_process,
(void (*)(void *, uint8_t *))sha256_done};
const struct hash_alg scram_sha512 = {
"SCRAM-SHA-512",
SASL_MASK_SCRAMSHA512,
SHA512_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
(void (*)(void *))sha512_init,
(void (*)(void *, const uint8_t *, size_t))sha512_process,
(void (*)(void *, uint8_t *))sha512_done};
union common_hash_ctx {
SHA1_CTX sha1;
sha256_context sha256;
sha512_context sha512;
};
static void crypto_HMAC(const struct hash_alg *alg,
const uint8_t *key,
size_t key_len,
const uint8_t *text,
size_t len,
uint8_t *digest)
{
uint8_t key_pad[HMAC_BLOCK_SIZE];
uint8_t key_ipad[HMAC_BLOCK_SIZE];
uint8_t key_opad[HMAC_BLOCK_SIZE];
uint8_t sha_digest[SHA1_DIGEST_SIZE];
int i;
SHA1_CTX ctx;
uint8_t key_pad[HMAC_BLOCK_SIZE_MAX];
uint8_t key_ipad[HMAC_BLOCK_SIZE_MAX];
uint8_t key_opad[HMAC_BLOCK_SIZE_MAX];
uint8_t sha_digest[SCRAM_DIGEST_SIZE];
size_t blocksize;
size_t i;
union common_hash_ctx ctx;
memset(key_pad, 0, sizeof(key_pad));
if (key_len <= HMAC_BLOCK_SIZE) {
assert(alg->digest_size <= HMAC_BLOCK_SIZE_MAX);
blocksize = alg->digest_size < 48 ? 64 : 128;
memset(key_pad, 0, blocksize);
if (key_len <= blocksize) {
memcpy(key_pad, key, key_len);
} else {
/* according to RFC2104 */
crypto_SHA1(key, key_len, key_pad);
alg->hash(key, key_len, key_pad);
}
for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
for (i = 0; i < blocksize; i++) {
key_ipad[i] = key_pad[i] ^ ipad;
key_opad[i] = key_pad[i] ^ opad;
}
crypto_SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, key_ipad, HMAC_BLOCK_SIZE);
crypto_SHA1_Update(&ctx, text, len);
crypto_SHA1_Final(&ctx, sha_digest);
alg->init((void *)&ctx);
alg->update((void *)&ctx, key_ipad, blocksize);
alg->update((void *)&ctx, text, len);
alg->final((void *)&ctx, sha_digest);
crypto_SHA1_Init(&ctx);
crypto_SHA1_Update(&ctx, key_opad, HMAC_BLOCK_SIZE);
crypto_SHA1_Update(&ctx, sha_digest, SHA1_DIGEST_SIZE);
crypto_SHA1_Final(&ctx, digest);
alg->init((void *)&ctx);
alg->update((void *)&ctx, key_opad, blocksize);
alg->update((void *)&ctx, sha_digest, alg->digest_size);
alg->final((void *)&ctx, digest);
}
static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i,
static void SCRAM_Hi(const struct hash_alg *alg,
const uint8_t *text,
size_t len,
const uint8_t *salt,
size_t salt_len,
uint32_t i,
uint8_t *digest)
{
int k;
size_t k;
uint32_t j;
uint8_t tmp[128];
@@ -77,7 +124,7 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
/* assume salt + INT(1) isn't longer than sizeof(tmp) */
assert(salt_len <= sizeof(tmp) - sizeof(int1));
memset(digest, 0, SHA1_DIGEST_SIZE);
memset(digest, 0, alg->digest_size);
if (i == 0) {
return;
}
@@ -86,46 +133,53 @@ static void SCRAM_SHA1_Hi(const uint8_t *text, size_t len,
memcpy(&tmp[salt_len], int1, sizeof(int1));
/* 'text' for Hi is a 'key' for HMAC */
crypto_HMAC_SHA1(text, len, tmp, salt_len + sizeof(int1), digest);
memcpy(tmp, digest, SHA1_DIGEST_SIZE);
crypto_HMAC(alg, text, len, tmp, salt_len + sizeof(int1), digest);
memcpy(tmp, digest, alg->digest_size);
for (j = 1; j < i; j++) {
crypto_HMAC_SHA1(text, len, tmp, SHA1_DIGEST_SIZE, tmp);
for (k = 0; k < SHA1_DIGEST_SIZE; k++) {
crypto_HMAC(alg, text, len, tmp, alg->digest_size, tmp);
for (k = 0; k < alg->digest_size; k++) {
digest[k] ^= tmp[k];
}
}
}
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i,
void SCRAM_ClientKey(const struct hash_alg *alg,
const uint8_t *password,
size_t len,
const uint8_t *salt,
size_t salt_len,
uint32_t i,
uint8_t *key)
{
uint8_t salted[SHA1_DIGEST_SIZE];
uint8_t salted[SCRAM_DIGEST_SIZE];
/* XXX: Normalize(password) is omitted */
SCRAM_SHA1_Hi(password, len, salt, salt_len, i, salted);
crypto_HMAC_SHA1(salted, SHA1_DIGEST_SIZE, (uint8_t *)"Client Key",
SCRAM_Hi(alg, password, len, salt, salt_len, i, salted);
crypto_HMAC(alg, salted, alg->digest_size, (uint8_t *)"Client Key",
strlen("Client Key"), key);
}
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
const uint8_t *AuthMessage, size_t len,
void SCRAM_ClientSignature(const struct hash_alg *alg,
const uint8_t *ClientKey,
const uint8_t *AuthMessage,
size_t len,
uint8_t *sign)
{
uint8_t stored[SHA1_DIGEST_SIZE];
uint8_t stored[SCRAM_DIGEST_SIZE];
crypto_SHA1(ClientKey, SHA1_DIGEST_SIZE, stored);
crypto_HMAC_SHA1(stored, SHA1_DIGEST_SIZE, AuthMessage, len, sign);
alg->hash(ClientKey, alg->digest_size, stored);
crypto_HMAC(alg, stored, alg->digest_size, AuthMessage, len, sign);
}
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
void SCRAM_ClientProof(const struct hash_alg *alg,
const uint8_t *ClientKey,
const uint8_t *ClientSignature,
uint8_t *proof)
{
int i;
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
size_t i;
for (i = 0; i < alg->digest_size; i++) {
proof[i] = ClientKey[i] ^ ClientSignature[i];
}
}

View File

@@ -1,5 +1,5 @@
/* scram.h
* strophe XMPP client library -- SCRAM-SHA1 helper functions
* strophe XMPP client library -- SCRAM helper functions
*
* Copyright (C) 2013 Dmitry Podgorny <pasis.ua@gmail.com>
*
@@ -10,7 +10,7 @@
*/
/** @file
* SCRAM-SHA1 helper functions.
* SCRAM helper functions.
*/
#ifndef __LIBSTROPHE_SCRAM_H__
@@ -19,17 +19,40 @@
/* make sure the stdint.h types are available */
#include "ostypes.h"
#include "sha1.h"
/* Maximum possible digest size. Used for buffers allocation. */
#include "sha512.h"
#define SCRAM_DIGEST_SIZE SHA512_DIGEST_SIZE
void SCRAM_SHA1_ClientKey(const uint8_t *password, size_t len,
const uint8_t *salt, size_t salt_len, uint32_t i,
struct hash_alg {
const char *scram_name;
int mask;
size_t digest_size;
void (*hash)(const uint8_t *, size_t, uint8_t *);
void (*init)(void *);
void (*update)(void *, const uint8_t *, size_t);
void (*final)(void *, uint8_t *);
};
extern const struct hash_alg scram_sha1;
extern const struct hash_alg scram_sha256;
extern const struct hash_alg scram_sha512;
void SCRAM_ClientKey(const struct hash_alg *alg,
const uint8_t *password,
size_t len,
const uint8_t *salt,
size_t salt_len,
uint32_t i,
uint8_t *key);
void SCRAM_SHA1_ClientSignature(const uint8_t *ClientKey,
const uint8_t *AuthMessage, size_t len,
void SCRAM_ClientSignature(const struct hash_alg *alg,
const uint8_t *ClientKey,
const uint8_t *AuthMessage,
size_t len,
uint8_t *sign);
void SCRAM_SHA1_ClientProof(const uint8_t *ClientKey,
void SCRAM_ClientProof(const struct hash_alg *alg,
const uint8_t *ClientKey,
const uint8_t *ClientSignature,
uint8_t *proof);

112
src/sha.h Normal file
View File

@@ -0,0 +1,112 @@
/* public api for steve reid's public domain SHA-1 implementation */
/* this file is in the public domain */
/** @file
* SHA-1 hash API.
*/
#ifndef __LIBSTROPHE_SHA_H__
#define __LIBSTROPHE_SHA_H__
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/* make sure the stdint.h types are available */
#include "ostypes.h"
#if defined(__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define STORE32H(x, y) \
do { \
uint32_t __t = (x); \
memcpy(y, &__t, 4); \
} while (0)
#define LOAD32H(x, y) \
do { \
memcpy(&(x), y, 4); \
x &= 0xFFFFFFFF; \
} while (0)
#define STORE64H(x, y) \
do { \
uint64_t __t = (x); \
memcpy(y, &__t, 8); \
} while (0)
#define LOAD64H(x, y) \
do { \
memcpy(&(x), y, 8); \
} while (0)
#elif defined(__LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define STORE32H(x, y) \
do { \
(y)[0] = (uint8_t)(((x) >> 24) & 255); \
(y)[1] = (uint8_t)(((x) >> 16) & 255); \
(y)[2] = (uint8_t)(((x) >> 8) & 255); \
(y)[3] = (uint8_t)((x)&255); \
} while (0)
#define LOAD32H(x, y) \
do { \
x = ((uint32_t)((y)[0] & 255) << 24) | \
((uint32_t)((y)[1] & 255) << 16) | \
((uint32_t)((y)[2] & 255) << 8) | ((uint32_t)((y)[3] & 255)); \
} while (0)
#define STORE64H(x, y) \
do { \
(y)[0] = (uint8_t)(((x) >> 56) & 255); \
(y)[1] = (uint8_t)(((x) >> 48) & 255); \
(y)[2] = (uint8_t)(((x) >> 40) & 255); \
(y)[3] = (uint8_t)(((x) >> 32) & 255); \
(y)[4] = (uint8_t)(((x) >> 24) & 255); \
(y)[5] = (uint8_t)(((x) >> 16) & 255); \
(y)[6] = (uint8_t)(((x) >> 8) & 255); \
(y)[7] = (uint8_t)((x)&255); \
} while (0)
#define LOAD64H(x, y) \
do { \
x = (((uint64_t)((y)[0] & 255)) << 56) | \
(((uint64_t)((y)[1] & 255)) << 48) | \
(((uint64_t)((y)[2] & 255)) << 40) | \
(((uint64_t)((y)[3] & 255)) << 32) | \
(((uint64_t)((y)[4] & 255)) << 24) | \
(((uint64_t)((y)[5] & 255)) << 16) | \
(((uint64_t)((y)[6] & 255)) << 8) | (((uint64_t)((y)[7] & 255))); \
} while (0)
#else
#error Unknown endianness not supported
#endif
#ifdef _MSC_VER
#define CONST64(n) n##ui64
#else
#define CONST64(n) n##ULL
#endif
#define RORc(x, y) \
(((((uint32_t)(x)&0xFFFFFFFFUL) >> (uint32_t)((y)&31)) | \
((uint32_t)(x) << (uint32_t)((32 - ((y)&31)) & 31))) & \
0xFFFFFFFFUL)
#define ROR64c(x, y) \
(((((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)(y)&CONST64(63))) | \
((x) << (((uint64_t)64 - ((y)&63)) & 63))) & \
CONST64(0xFFFFFFFFFFFFFFFF))
#ifdef __cplusplus
}
#endif
#endif /* __LIBSTROPHE_SHA_H__ */

View File

@@ -75,9 +75,6 @@ move public api to sha1.h
#include "ostypes.h"
#include "sha1.h"
/* Don't change user's data */
#define SHA1HANDSOFF
static uint32_t host_to_be(uint32_t i);
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
@@ -86,16 +83,27 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#define blk0(i) (block->l[i] = host_to_be(block->l[i]))
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
#define blk(i) \
(block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
block->l[(i + 2) & 15] ^ block->l[i & 15], \
1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
#define R0(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R1(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R2(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
w = rol(w, 30);
#define R3(v, w, x, y, z, i) \
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);
#define R4(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
w = rol(w, 30);
static uint32_t host_to_be(uint32_t i)
{
@@ -118,6 +126,13 @@ static uint32_t host_to_be(uint32_t i)
#undef le_to_be
}
static void *(*volatile SHA1_explicit_memset)(void *, int, size_t) = &memset;
static void SHA1_cleanse(void *p, size_t len)
{
SHA1_explicit_memset(p, 0, len);
}
/* Hash a single 512-bit block. This is the core of the algorithm. */
static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
{
@@ -128,13 +143,9 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
} CHAR64LONG16;
CHAR64LONG16 *block;
#ifdef SHA1HANDSOFF
static uint8_t workspace[64];
block = (CHAR64LONG16 *)workspace;
memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
@@ -144,6 +155,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
/* clang-format off */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
@@ -164,6 +176,7 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* clang-format on */
/* Add the working vars back into context.state[] */
state[0] += a;
@@ -173,10 +186,13 @@ static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
SHA1_cleanse(&a, sizeof(a));
SHA1_cleanse(&b, sizeof(b));
SHA1_cleanse(&c, sizeof(c));
SHA1_cleanse(&d, sizeof(d));
SHA1_cleanse(&e, sizeof(e));
}
/* SHA1Init - Initialize new context */
void crypto_SHA1_Init(SHA1_CTX *context)
{
@@ -189,10 +205,8 @@ void crypto_SHA1_Init(SHA1_CTX* context)
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
const size_t len)
void crypto_SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len)
{
size_t i, j;
@@ -207,12 +221,11 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
SHA1_Transform(context->state, data + i);
}
j = 0;
}
else i = 0;
} else
i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest)
{
@@ -220,32 +233,30 @@ void crypto_SHA1_Final(SHA1_CTX* context, uint8_t* digest)
uint8_t finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >>
((3 - (i & 3)) * 8)) &
255); /* Endian independent */
}
crypto_SHA1_Update(context, (uint8_t *)"\200", 1);
while ((context->count[0] & 504) != 448) {
crypto_SHA1_Update(context, (uint8_t *)"\0", 1);
}
crypto_SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
/* Should cause a SHA1_Transform() */
crypto_SHA1_Update(context, finalcount, 8);
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
digest[i] = (uint8_t)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
digest[i] =
(uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
}
/* Wipe variables */
i = 0;
memset(context->buffer, 0, 64);
memset(context->state, 0, 20);
memset(context->count, 0, 8);
memset(finalcount, 0, 8); /* SWR */
SHA1_cleanse(context->buffer, 64);
SHA1_cleanse(context->state, 20);
SHA1_cleanse(context->count, 8);
SHA1_cleanse(finalcount, 8); /* SWR */
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
SHA1_Transform(context->state, context->buffer);
#endif
}
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest)
{
SHA1_CTX ctx;

View File

@@ -24,8 +24,7 @@ typedef struct {
#define SHA1_DIGEST_SIZE 20
void crypto_SHA1_Init(SHA1_CTX *context);
void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
const size_t len);
void crypto_SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len);
void crypto_SHA1_Final(SHA1_CTX *context, uint8_t *digest);
void crypto_SHA1(const uint8_t *data, size_t len, uint8_t *digest);

210
src/sha256.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* Code originally from LibTomCrypt -- Licensed under the Public Domain/WTFPL2.0
*/
#include "sha256.h"
#include "sha.h"
/* Various logical functions */
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
static void sha256_compress(sha256_context *md, const uint8_t *buf)
{
uint32_t S[8], W[64], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD32H(W[i], buf + (4 * i));
}
/* fill W[16..63] */
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a, b, c, d, e, f, g, h, i, ki) \
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 0, 0x428a2f98);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 1, 0x71374491);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 2, 0xb5c0fbcf);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 3, 0xe9b5dba5);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 4, 0x3956c25b);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 5, 0x59f111f1);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 6, 0x923f82a4);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 7, 0xab1c5ed5);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 8, 0xd807aa98);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 9, 0x12835b01);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 10, 0x243185be);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 11, 0x550c7dc3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 12, 0x72be5d74);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 13, 0x80deb1fe);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 14, 0x9bdc06a7);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 15, 0xc19bf174);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 16, 0xe49b69c1);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 17, 0xefbe4786);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 18, 0x0fc19dc6);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 19, 0x240ca1cc);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 20, 0x2de92c6f);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 21, 0x4a7484aa);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 22, 0x5cb0a9dc);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 23, 0x76f988da);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 24, 0x983e5152);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 25, 0xa831c66d);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 26, 0xb00327c8);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 27, 0xbf597fc7);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 28, 0xc6e00bf3);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 29, 0xd5a79147);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 30, 0x06ca6351);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 31, 0x14292967);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 32, 0x27b70a85);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 33, 0x2e1b2138);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 34, 0x4d2c6dfc);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 35, 0x53380d13);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 36, 0x650a7354);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 37, 0x766a0abb);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 38, 0x81c2c92e);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 39, 0x92722c85);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 40, 0xa2bfe8a1);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 41, 0xa81a664b);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 42, 0xc24b8b70);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 43, 0xc76c51a3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 44, 0xd192e819);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 45, 0xd6990624);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 46, 0xf40e3585);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 47, 0x106aa070);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 48, 0x19a4c116);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 49, 0x1e376c08);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 50, 0x2748774c);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 51, 0x34b0bcb5);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 52, 0x391c0cb3);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 53, 0x4ed8aa4a);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 54, 0x5b9cca4f);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 55, 0x682e6ff3);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], 56, 0x748f82ee);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], 57, 0x78a5636f);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], 58, 0x84c87814);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], 59, 0x8cc70208);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], 60, 0x90befffa);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], 61, 0xa4506ceb);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], 62, 0xbef9a3f7);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], 63, 0xc67178f2);
#undef RND
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
}
void sha256_init(sha256_context *md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = 0x6A09E667UL;
md->state[1] = 0xBB67AE85UL;
md->state[2] = 0x3C6EF372UL;
md->state[3] = 0xA54FF53AUL;
md->state[4] = 0x510E527FUL;
md->state[5] = 0x9B05688CUL;
md->state[6] = 0x1F83D9ABUL;
md->state[7] = 0x5BE0CD19UL;
}
void sha256_process(sha256_context *md, const uint8_t *in, size_t inlen)
{
size_t n;
if (md->curlen > sizeof(md->buf)) {
return;
}
if ((md->length + inlen) < md->length) {
return;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 64) {
sha256_compress(md, in);
md->length += 64 * 8;
in += 64;
inlen -= 64;
} else {
n = (((inlen) < ((64 - md->curlen))) ? (inlen)
: ((64 - md->curlen)));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 64) {
sha256_compress(md, md->buf);
md->length += 8 * 64;
md->curlen = 0;
}
}
}
}
void sha256_done(sha256_context *md, uint8_t *out)
{
int i;
if (md->curlen >= sizeof(md->buf)) {
return;
}
/* increase the length of the message */
md->length += md->curlen * 8;
/* append the '1' bit */
md->buf[md->curlen++] = (uint8_t)0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 56) {
while (md->curlen < 64) {
md->buf[md->curlen++] = (uint8_t)0;
}
sha256_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->curlen < 56) {
md->buf[md->curlen++] = (uint8_t)0;
}
/* store length */
STORE64H(md->length, md->buf + 56);
sha256_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE32H(md->state[i], out + (4 * i));
}
}
void sha256_hash(const uint8_t *data, size_t len, uint8_t *digest)
{
sha256_context md;
sha256_init(&md);
sha256_process(&md, data, len);
sha256_done(&md, digest);
}

34
src/sha256.h Normal file
View File

@@ -0,0 +1,34 @@
/* public api for LibTomCrypt SHA-256 implementation */
/** @file
* SHA-256 hash API.
*/
#ifndef __LIBSTROPHE_SHA256_H__
#define __LIBSTROPHE_SHA256_H__
#ifdef __cplusplus
extern "C" {
#endif
/* make sure the stdint.h types are available */
#include "ostypes.h"
typedef struct {
uint64_t length;
uint32_t state[8], curlen;
uint8_t buf[64];
} sha256_context;
#define SHA256_DIGEST_SIZE 32
void sha256_init(sha256_context *md);
void sha256_process(sha256_context *md, const uint8_t *in, size_t inlen);
void sha256_done(sha256_context *md, uint8_t *out);
void sha256_hash(const uint8_t *data, size_t len, uint8_t *digest);
#ifdef __cplusplus
}
#endif
#endif /* __LIBSTROPHE_SHA256_H__ */

201
src/sha512.c Normal file
View File

@@ -0,0 +1,201 @@
/*
* Code originally from LibTomCrypt -- Licensed under the Public Domain/WTFPL2.0
*/
#include "sha512.h"
#include "sha.h"
/* the K array */
static const uint64_t K[80] = {
CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)};
/* Various logical functions */
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF)) >> ((uint64_t)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
/* compress 1024-bits */
static void sha512_compress(sha512_context *md, const uint8_t *buf)
{
uint64_t S[8], W[80], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 1024-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8 * i));
}
/* fill W[16..79] */
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 80; i += 8) {
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
}
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
}
void sha512_init(sha512_context *md)
{
md->curlen = 0;
md->length = 0;
md->state[0] = CONST64(0x6a09e667f3bcc908);
md->state[1] = CONST64(0xbb67ae8584caa73b);
md->state[2] = CONST64(0x3c6ef372fe94f82b);
md->state[3] = CONST64(0xa54ff53a5f1d36f1);
md->state[4] = CONST64(0x510e527fade682d1);
md->state[5] = CONST64(0x9b05688c2b3e6c1f);
md->state[6] = CONST64(0x1f83d9abfb41bd6b);
md->state[7] = CONST64(0x5be0cd19137e2179);
}
void sha512_process(sha512_context *md, const uint8_t *in, size_t inlen)
{
size_t n;
if (md->curlen > sizeof(md->buf)) {
return;
}
if ((md->length + inlen) < md->length) {
return;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md, in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
n = (((inlen) < ((128u - md->curlen))) ? (inlen)
: ((128u - md->curlen)));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
sha512_compress(md, md->buf);
md->length += 8 * 128;
md->curlen = 0;
}
}
}
}
void sha512_done(sha512_context *md, uint8_t *out)
{
int i;
if (md->curlen >= sizeof(md->buf)) {
return;
}
/* increase the length of the message */
md->length += md->curlen * CONST64(8);
/* append the '1' bit */
md->buf[md->curlen++] = (uint8_t)0x80;
/* if the length is currently above 112 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 112) {
while (md->curlen < 128) {
md->buf[md->curlen++] = (uint8_t)0;
}
sha512_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 120 bytes of zeroes
* note: that from 112 to 120 is the 64 MSB of the length. We assume that
* you won't hash > 2^64 bits of data... :-)
*/
while (md->curlen < 120) {
md->buf[md->curlen++] = (uint8_t)0;
}
/* store length */
STORE64H(md->length, md->buf + 120);
sha512_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out + (8 * i));
}
}
void sha512_hash(const uint8_t *data, size_t len, uint8_t *digest)
{
sha512_context md;
sha512_init(&md);
sha512_process(&md, data, len);
sha512_done(&md, digest);
}

34
src/sha512.h Normal file
View File

@@ -0,0 +1,34 @@
/* public api for LibTomCrypt SHA-512 implementation */
/** @file
* SHA-512 hash API.
*/
#ifndef __LIBSTROPHE_SHA512_H__
#define __LIBSTROPHE_SHA512_H__
#ifdef __cplusplus
extern "C" {
#endif
/* make sure the stdint.h types are available */
#include "ostypes.h"
typedef struct {
uint64_t length, state[8];
uint8_t curlen;
uint8_t buf[128];
} sha512_context;
#define SHA512_DIGEST_SIZE 64
void sha512_init(sha512_context *cc);
void sha512_process(sha512_context *cc, const uint8_t *data, size_t len);
void sha512_done(sha512_context *cc, uint8_t *dst);
void sha512_hash(const uint8_t *data, size_t len, uint8_t *digest);
#ifdef __cplusplus
}
#endif
#endif /* __LIBSTROPHE_SHA512_H__ */

View File

@@ -85,14 +85,29 @@
#define LDOUBLE double
#endif
static int dopr (char *buffer, size_t maxlen, const char *format,
va_list args);
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max);
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags);
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static int dopr(char *buffer, size_t maxlen, const char *format, va_list args);
static int fmtstr(char *buffer,
size_t *currlen,
size_t maxlen,
char *value,
int flags,
int min,
int max);
static int fmtint(char *buffer,
size_t *currlen,
size_t maxlen,
long value,
int base,
int min,
int max,
int flags);
static int fmtfp(char *buffer,
size_t *currlen,
size_t maxlen,
LDOUBLE fvalue,
int min,
int max,
int flags);
static int dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
/*
@@ -147,13 +162,11 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
ch = *format++;
total = 0;
while (state != DP_S_DONE)
{
while (state != DP_S_DONE) {
if (ch == '\0')
state = DP_S_DONE;
switch(state)
{
switch (state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
@@ -162,8 +175,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch)
{
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
@@ -190,50 +202,39 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
}
break;
case DP_S_MIN:
if (isdigit(ch))
{
if (isdigit(ch)) {
min = 10 * min + char_to_int(ch);
ch = *format++;
}
else if (ch == '*')
{
} else if (ch == '*') {
min = va_arg(args, int);
ch = *format++;
state = DP_S_DOT;
}
else
} else
state = DP_S_DOT;
break;
case DP_S_DOT:
if (ch == '.')
{
if (ch == '.') {
state = DP_S_MAX;
ch = *format++;
}
else
} else
state = DP_S_MOD;
break;
case DP_S_MAX:
if (isdigit(ch))
{
if (isdigit(ch)) {
if (max < 0)
max = 0;
max = 10 * max + char_to_int(ch);
ch = *format++;
}
else if (ch == '*')
{
} else if (ch == '*') {
max = va_arg(args, int);
ch = *format++;
state = DP_S_MOD;
}
else
} else
state = DP_S_MOD;
break;
case DP_S_MOD:
/* Currently, we don't support Long Long, bummer */
switch (ch)
{
switch (ch) {
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
@@ -252,8 +253,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch)
{
switch (ch) {
case 'd':
case 'i':
if (cflags == DP_C_SHORT)
@@ -262,7 +262,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
value = va_arg(args, long int);
else
value = va_arg(args, int);
total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
total += fmtint(buffer, &currlen, maxlen, value, 10, min, max,
flags);
break;
case 'o':
flags |= DP_F_UNSIGNED;
@@ -272,7 +273,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
value = va_arg(args, unsigned long int);
else
value = va_arg(args, unsigned int);
total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
total +=
fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
break;
case 'u':
flags |= DP_F_UNSIGNED;
@@ -282,7 +284,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
value = va_arg(args, unsigned long int);
else
value = va_arg(args, unsigned int);
total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
total += fmtint(buffer, &currlen, maxlen, value, 10, min, max,
flags);
break;
case 'X':
flags |= DP_F_UP;
@@ -295,7 +298,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
value = va_arg(args, unsigned long int);
else
value = va_arg(args, unsigned int);
total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
total += fmtint(buffer, &currlen, maxlen, value, 16, min, max,
flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
@@ -303,7 +307,8 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
else
fvalue = va_arg(args, double);
/* um, floating point? */
total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
total +=
fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
break;
case 'E':
flags |= DP_F_UP;
@@ -324,32 +329,29 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
fvalue = va_arg(args, double);
break;
case 'c':
total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
total +=
dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
break;
case 's':
strvalue = va_arg(args, char *);
total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
total +=
fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
break;
case 'p':
strvalue = va_arg(args, void *);
total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
max, flags);
total += fmtint(buffer, &currlen, maxlen, (long)strvalue, 16,
min, max, flags);
break;
case 'n':
if (cflags == DP_C_SHORT)
{
if (cflags == DP_C_SHORT) {
short int *num;
num = va_arg(args, short int *);
*num = currlen;
}
else if (cflags == DP_C_LONG)
{
} else if (cflags == DP_C_LONG) {
long int *num;
num = va_arg(args, long int *);
*num = currlen;
}
else
{
} else {
int *num;
num = va_arg(args, int *);
*num = currlen;
@@ -378,8 +380,7 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
break; /* some picky compilers need this */
}
}
if (buffer != NULL && maxlen > 0)
{
if (buffer != NULL && maxlen > 0) {
if (currlen < maxlen - 1)
buffer[currlen] = '\0';
else
@@ -388,19 +389,24 @@ static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
return total;
}
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
char *value, int flags, int min, int max)
static int fmtstr(char *buffer,
size_t *currlen,
size_t maxlen,
char *value,
int flags,
int min,
int max)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
int total = 0;
if (value == 0)
{
if (value == 0) {
value = "<NULL>";
}
for (strln = 0; value[strln]; ++strln); /* strlen */
for (strln = 0; value[strln]; ++strln)
; /* strlen */
if (max >= 0 && max < strln)
strln = max;
padlen = min - strln;
@@ -409,18 +415,15 @@ static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while (padlen > 0)
{
while (padlen > 0) {
total += dopr_outch(buffer, currlen, maxlen, ' ');
--padlen;
}
while (*value && ((max < 0) || (cnt < max)))
{
while (*value && ((max < 0) || (cnt < max))) {
total += dopr_outch(buffer, currlen, maxlen, *value++);
++cnt;
}
while (padlen < 0)
{
while (padlen < 0) {
total += dopr_outch(buffer, currlen, maxlen, ' ');
++padlen;
}
@@ -429,8 +432,14 @@ static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
long value, int base, int min, int max, int flags)
static int fmtint(char *buffer,
size_t *currlen,
size_t maxlen,
long value,
int base,
int min,
int max,
int flags)
{
int signvalue = 0;
unsigned long uvalue;
@@ -446,37 +455,35 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
uvalue = value;
if(!(flags & DP_F_UNSIGNED))
{
if (!(flags & DP_F_UNSIGNED)) {
if (value < 0) {
signvalue = '-';
uvalue = -value;
}
else
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
} else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else
if (flags & DP_F_SPACE)
else if (flags & DP_F_SPACE)
signvalue = ' ';
}
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
if (flags & DP_F_UP)
caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
convert[place++] = (caps ? "0123456789ABCDEF"
: "0123456789abcdef")[uvalue % (unsigned)base];
uvalue = (uvalue / (unsigned)base);
} while (uvalue && (place < 20));
if (place == 20) place--;
if (place == 20)
place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0) zpadlen = 0;
if (spadlen < 0) spadlen = 0;
if (flags & DP_F_ZERO)
{
if (zpadlen < 0)
zpadlen = 0;
if (spadlen < 0)
spadlen = 0;
if (flags & DP_F_ZERO) {
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
@@ -489,8 +496,7 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
#endif
/* Spaces */
while (spadlen > 0)
{
while (spadlen > 0) {
total += dopr_outch(buffer, currlen, maxlen, ' ');
--spadlen;
}
@@ -500,10 +506,8 @@ static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
total += dopr_outch(buffer, currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0)
{
while (zpadlen > 0)
{
if (zpadlen > 0) {
while (zpadlen > 0) {
total += dopr_outch(buffer, currlen, maxlen, '0');
--zpadlen;
}
@@ -536,8 +540,7 @@ static LDOUBLE _snp_pow10 (int exp)
{
LDOUBLE result = 1;
while (exp)
{
while (exp) {
result *= 10;
exp--;
}
@@ -557,8 +560,13 @@ static long _snp_round (LDOUBLE value)
return intpart;
}
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags)
static int fmtfp(char *buffer,
size_t *currlen,
size_t maxlen,
LDOUBLE fvalue,
int min,
int max,
int flags)
{
int signvalue = 0;
LDOUBLE ufvalue;
@@ -584,11 +592,9 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
if (fvalue < 0)
signvalue = '-';
else
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else
if (flags & DP_F_SPACE)
else if (flags & DP_F_SPACE)
signvalue = ' ';
#if 0
@@ -609,8 +615,7 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
*/
fracpart = _snp_round((_snp_pow10(max)) * (ufvalue - intpart));
if (fracpart >= _snp_pow10 (max))
{
if (fracpart >= _snp_pow10(max)) {
intpart++;
fracpart -= _snp_pow10(max);
}
@@ -625,7 +630,8 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
(caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
intpart = (intpart / 10);
} while (intpart && (iplace < 20));
if (iplace == 20) iplace--;
if (iplace == 20)
iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
@@ -634,7 +640,8 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
(caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
fracpart = (fracpart / 10);
} while (fracpart && (fplace < 20));
if (fplace == 20) fplace--;
if (fplace == 20)
fplace--;
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
@@ -647,22 +654,18 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0))
{
if (signvalue)
{
if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) {
total += dopr_outch(buffer, currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0)
{
while (padlen > 0) {
total += dopr_outch(buffer, currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0)
{
while (padlen > 0) {
total += dopr_outch(buffer, currlen, maxlen, ' ');
--padlen;
}
@@ -676,22 +679,19 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0)
{
if (max > 0) {
total += dopr_outch(buffer, currlen, maxlen, '.');
while (fplace > 0)
total += dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
}
while (zpadlen > 0)
{
while (zpadlen > 0) {
total += dopr_outch(buffer, currlen, maxlen, '0');
--zpadlen;
}
while (padlen < 0)
{
while (padlen < 0) {
total += dopr_outch(buffer, currlen, maxlen, ' ');
++padlen;
}

View File

@@ -21,8 +21,8 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <Iphlpapi.h>
#include <Mstcpip.h> /* tcp_keepalive */
#include <iphlpapi.h>
#include <mstcpip.h> /* tcp_keepalive */
#else
#include <errno.h>
#include <unistd.h>
@@ -33,17 +33,9 @@
#include <fcntl.h>
#endif
#include "common.h"
#include "sock.h"
#include "snprintf.h"
struct _xmpp_sock_t {
xmpp_ctx_t *ctx;
struct addrinfo *ainfo_list;
struct addrinfo *current;
sock_t sock;
};
void sock_initialize(void)
{
#ifdef _WIN32
@@ -77,23 +69,13 @@ static int _in_progress(int error)
#endif
}
xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port)
sock_t sock_connect(const char *host, unsigned short port)
{
xmpp_sock_t *xsock;
sock_t sock;
char service[6];
struct addrinfo hints;
struct addrinfo *res, *ainfo, hints;
int err;
xsock = xmpp_alloc(ctx, sizeof *xsock);
if (xsock == NULL) {
xmpp_error(ctx, "sock", "Memory allocation error.");
return NULL;
}
xsock->ctx = ctx;
xsock->ainfo_list = NULL;
xsock->current = NULL;
xsock->sock = -1;
xmpp_snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo));
@@ -104,33 +86,11 @@ xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port)
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(host, service, &hints, &xsock->ainfo_list);
if (err != 0) {
xmpp_free(ctx, xsock);
xsock = NULL;
}
return xsock;
}
err = getaddrinfo(host, service, &hints, &res);
if (err != 0)
return -1;
void sock_free(xmpp_sock_t *xsock)
{
if (xsock->ainfo_list != NULL)
freeaddrinfo(xsock->ainfo_list);
xmpp_free(xsock->ctx, xsock);
}
sock_t sock_connect(xmpp_sock_t *xsock)
{
struct addrinfo *ainfo;
sock_t sock = -1;
int err;
if (xsock->current == NULL)
ainfo = xsock->ainfo_list;
else
ainfo = xsock->current->ai_next;
for (; ainfo != NULL; ainfo = ainfo->ai_next) {
for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock < 0)
continue;
@@ -143,17 +103,13 @@ sock_t sock_connect(xmpp_sock_t *xsock)
}
sock_close(sock);
}
freeaddrinfo(res);
sock = ainfo == NULL ? -1 : sock;
xsock->sock = sock;
xsock->current = ainfo;
if (ainfo == NULL) {
freeaddrinfo(xsock->ainfo_list);
xsock->ainfo_list = NULL;
}
return sock;
}
int sock_set_keepalive(const sock_t sock, int timeout, int interval)
int sock_set_keepalive(sock_t sock, int timeout, int interval)
{
int ret;
int optval = (timeout && interval) ? 1 : 0;
@@ -167,7 +123,8 @@ int sock_set_keepalive(const sock_t sock, int timeout, int interval)
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);
ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), NULL, 0, &dw,
NULL, NULL);
#else
ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
if (ret < 0)
@@ -175,15 +132,19 @@ int sock_set_keepalive(const sock_t sock, int timeout, int interval)
if (optval) {
#ifdef TCP_KEEPIDLE
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout));
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));
/* 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));
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &interval,
sizeof(interval));
if (ret < 0)
return ret;
#endif /* TCP_KEEPINTVL */
@@ -193,7 +154,7 @@ int sock_set_keepalive(const sock_t sock, int timeout, int interval)
return ret;
}
int sock_close(const sock_t sock)
int sock_close(sock_t sock)
{
#ifdef _WIN32
return closesocket(sock);
@@ -219,27 +180,27 @@ static int _sock_set_blocking_mode(sock_t sock, int blocking)
#endif
}
int sock_set_blocking(const sock_t sock)
int sock_set_blocking(sock_t sock)
{
return _sock_set_blocking_mode(sock, 1);
}
int sock_set_nonblocking(const sock_t sock)
int sock_set_nonblocking(sock_t sock)
{
return _sock_set_blocking_mode(sock, 0);
}
int sock_read(const sock_t sock, void * const buff, const size_t len)
int sock_read(sock_t sock, void *buff, size_t len)
{
return recv(sock, buff, len, 0);
}
int sock_write(const sock_t sock, const void * const buff, const size_t len)
int sock_write(sock_t sock, const void *buff, size_t len)
{
return send(sock, buff, len, 0);
}
int sock_is_recoverable(const int error)
int sock_is_recoverable(int error)
{
#ifdef _WIN32
return (error == WSAEINTR || error == WSAEWOULDBLOCK ||
@@ -249,29 +210,31 @@ int sock_is_recoverable(const int error)
#endif
}
int sock_connect_error(const sock_t sock)
int sock_connect_error(sock_t sock)
{
struct sockaddr sa;
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
socklen_t len;
char temp;
memset(&sa, 0, sizeof(sa));
sa.sa_family = AF_UNSPEC;
len = sizeof(sa);
memset(&ss, 0, sizeof(ss));
len = sizeof(ss);
sa->sa_family = AF_UNSPEC;
/* we don't actually care about the peer name, we're just checking if
* we're connected or not */
if (getpeername(sock, &sa, &len) == 0)
{
if (getpeername(sock, sa, &len) == 0) {
return 0;
}
/* it's possible that the error wasn't ENOTCONN, so if it wasn't,
* return that */
#ifdef _WIN32
if (sock_error() != WSAENOTCONN) return sock_error();
if (sock_error() != WSAENOTCONN)
return sock_error();
#else
if (sock_error() != ENOTCONN) return sock_error();
if (sock_error() != ENOTCONN)
return sock_error();
#endif
/* load the correct error into errno through error slippage */

View File

@@ -25,25 +25,21 @@ typedef int sock_t;
typedef SOCKET sock_t;
#endif
typedef struct _xmpp_sock_t xmpp_sock_t;
void sock_initialize(void);
void sock_shutdown(void);
int sock_error(void);
xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port);
void sock_free(xmpp_sock_t *xsock);
sock_t sock_connect(xmpp_sock_t *xsock);
int sock_close(const sock_t sock);
sock_t sock_connect(const char *host, unsigned short port);
int sock_close(sock_t sock);
int sock_set_blocking(const sock_t sock);
int sock_set_nonblocking(const sock_t sock);
int sock_read(const sock_t sock, void * const buff, const size_t len);
int sock_write(const sock_t sock, const void * const buff, const size_t len);
int sock_is_recoverable(const int error);
int sock_set_blocking(sock_t sock);
int sock_set_nonblocking(sock_t sock);
int sock_read(sock_t sock, void *buff, size_t len);
int sock_write(sock_t sock, const void *buff, size_t len);
int sock_is_recoverable(int error);
/* checks for an error after connect, return 0 if connect successful */
int sock_connect_error(const sock_t sock);
int sock_set_keepalive(const sock_t sock, int timeout, int interval);
int sock_connect_error(sock_t sock);
int sock_set_keepalive(sock_t sock, int timeout, int interval);
#endif /* __LIBSTROPHE_SOCK_H__ */

View File

@@ -22,6 +22,7 @@
#include "strophe.h"
#include "common.h"
#include "hash.h"
#include "parser.h"
/** Create a stanza object.
* This function allocates and initializes a blank stanza object.
@@ -63,7 +64,7 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t *stanza)
{
stanza->ref++;
@@ -73,8 +74,7 @@ xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza)
/*
* Copy the attributes of stanza src into stanza dst. Return -1 on error.
*/
static int _stanza_copy_attributes(xmpp_stanza_t * dst,
const xmpp_stanza_t * const src)
static int _stanza_copy_attributes(xmpp_stanza_t *dst, const xmpp_stanza_t *src)
{
hash_iterator_t *iter;
const char *key;
@@ -82,11 +82,13 @@ static int _stanza_copy_attributes(xmpp_stanza_t * dst,
int rc = XMPP_EOK;
iter = hash_iter_new(src->attributes);
if (!iter) rc = XMPP_EMEM;
if (!iter)
rc = XMPP_EMEM;
while (rc == XMPP_EOK && (key = hash_iter_next(iter))) {
val = hash_get(src->attributes, key);
if (!val) rc = XMPP_EINT;
if (!val)
rc = XMPP_EINT;
if (rc == XMPP_EOK)
rc = xmpp_stanza_set_attribute(dst, key, val);
}
@@ -111,18 +113,20 @@ static int _stanza_copy_attributes(xmpp_stanza_t * dst,
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t *stanza)
{
xmpp_stanza_t *copy, *child, *copychild, *tail;
copy = xmpp_stanza_new(stanza->ctx);
if (!copy) goto copy_error;
if (!copy)
goto copy_error;
copy->type = stanza->type;
if (stanza->data) {
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
if (!copy->data) goto copy_error;
if (!copy->data)
goto copy_error;
}
if (stanza->attributes) {
@@ -133,7 +137,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
tail = copy->children;
for (child = stanza->children; child; child = child->next) {
copychild = xmpp_stanza_copy(child);
if (!copychild) goto copy_error;
if (!copychild)
goto copy_error;
copychild->parent = copy;
if (tail) {
@@ -148,7 +153,8 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
copy_error:
/* release all the hitherto allocated memory */
if (copy) xmpp_stanza_release(copy);
if (copy)
xmpp_stanza_release(copy);
return NULL;
}
@@ -162,7 +168,7 @@ copy_error:
*
* @ingroup Stanza
*/
int xmpp_stanza_release(xmpp_stanza_t * const stanza)
int xmpp_stanza_release(xmpp_stanza_t *stanza)
{
int released = 0;
xmpp_stanza_t *child, *tchild;
@@ -179,8 +185,10 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
xmpp_stanza_release(tchild);
}
if (stanza->attributes) hash_release(stanza->attributes);
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
if (stanza->attributes)
hash_release(stanza->attributes);
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
xmpp_free(stanza->ctx, stanza);
released = 1;
}
@@ -188,6 +196,19 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
return released;
}
/** Get the strophe context that the stanza is associated with.
*
* @param stanza a Strophe stanza object
*
* @return a Strophe context
*
* @ingroup Stanza
*/
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t *stanza)
{
return stanza->ctx;
}
/** Determine if a stanza is a text node.
*
* @param stanza a Strophe stanza object
@@ -196,7 +217,7 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
int xmpp_stanza_is_text(xmpp_stanza_t * const stanza)
int xmpp_stanza_is_text(xmpp_stanza_t *stanza)
{
return (stanza && stanza->type == XMPP_STANZA_TEXT);
}
@@ -209,7 +230,7 @@ int xmpp_stanza_is_text(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza)
int xmpp_stanza_is_tag(xmpp_stanza_t *stanza)
{
return (stanza && stanza->type == XMPP_STANZA_TAG);
}
@@ -220,7 +241,7 @@ int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza)
* On failure, returns NULL.
*/
static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
static char *_escape_xml(xmpp_ctx_t *ctx, char *text)
{
size_t len = 0;
char *src;
@@ -273,9 +294,8 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
}
/* small helper function */
static void _render_update(int *written, const int length,
const int lastwrite,
size_t *left, char **ptr)
static void _render_update(
int *written, int length, int lastwrite, size_t *left, char **ptr)
{
*written += lastwrite;
@@ -293,8 +313,8 @@ static void _render_update(int *written, const int length,
* return values < 0 indicate some error occurred,
* and return values > buflen indicate buffer was not large enough
*/
static int _render_stanza_recursive(xmpp_stanza_t *stanza,
char * const buf, size_t const buflen)
static int
_render_stanza_recursive(xmpp_stanza_t *stanza, char *buf, size_t buflen)
{
char *ptr = buf;
size_t left = buflen;
@@ -306,23 +326,29 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
written = 0;
if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_UNKNOWN)
return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_TEXT) {
if (!stanza->data) return XMPP_EINVOP;
if (!stanza->data)
return XMPP_EINVOP;
tmp = _escape_xml(stanza->ctx, stanza->data);
if (tmp == NULL) return XMPP_EMEM;
if (tmp == NULL)
return XMPP_EMEM;
ret = xmpp_snprintf(ptr, left, "%s", tmp);
xmpp_free(stanza->ctx, tmp);
if (ret < 0) return XMPP_EMEM;
if (ret < 0)
return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr);
} else { /* stanza->type == XMPP_STANZA_TAG */
if (!stanza->data) return XMPP_EINVOP;
if (!stanza->data)
return XMPP_EINVOP;
/* write beginning of tag and attributes */
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
if (ret < 0) return XMPP_EMEM;
if (ret < 0)
return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr);
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
@@ -330,10 +356,10 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
while ((key = hash_iter_next(iter))) {
if (!strcmp(key, "xmlns")) {
/* don't output namespace if parent stanza is the same */
if (stanza->parent &&
stanza->parent->attributes &&
if (stanza->parent && stanza->parent->attributes &&
hash_get(stanza->parent->attributes, key) &&
!strcmp((char*)hash_get(stanza->attributes, key),
!strcmp(
(char *)hash_get(stanza->attributes, key),
(char *)hash_get(stanza->parent->attributes, key)))
continue;
/* or if this is the stream namespace */
@@ -362,21 +388,24 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
if (!stanza->children) {
/* write end if singleton tag */
ret = xmpp_snprintf(ptr, left, "/>");
if (ret < 0) return XMPP_EMEM;
if (ret < 0)
return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr);
} else {
/* this stanza has child stanzas */
/* write end of start tag */
ret = xmpp_snprintf(ptr, left, ">");
if (ret < 0) return XMPP_EMEM;
if (ret < 0)
return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr);
/* iterate and recurse over child stanzas */
child = stanza->children;
while (child) {
ret = _render_stanza_recursive(child, ptr, left);
if (ret < 0) return ret;
if (ret < 0)
return ret;
_render_update(&written, buflen, ret, &left, &ptr);
@@ -385,7 +414,8 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
/* write end tag */
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
if (ret < 0) return XMPP_EMEM;
if (ret < 0)
return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr);
}
@@ -409,9 +439,7 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
char ** const buf,
size_t * const buflen)
int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char **buf, size_t *buflen)
{
char *buffer, *tmp;
size_t length;
@@ -472,12 +500,13 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
const char * const name)
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *name)
{
if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_TEXT)
return XMPP_EINVOP;
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
stanza->type = XMPP_STANZA_TAG;
stanza->data = xmpp_strdup(stanza->ctx, name);
@@ -495,9 +524,10 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_name(xmpp_stanza_t *stanza)
{
if (stanza->type == XMPP_STANZA_TEXT) return NULL;
if (stanza->type == XMPP_STANZA_TEXT)
return NULL;
return stanza->data;
}
@@ -509,7 +539,7 @@ const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
int xmpp_stanza_get_attribute_count(xmpp_stanza_t *stanza)
{
if (stanza->attributes == NULL) {
return 0;
@@ -532,8 +562,9 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
const char **attr, int attrlen)
int xmpp_stanza_get_attributes(xmpp_stanza_t *stanza,
const char **attr,
int attrlen)
{
hash_iterator_t *iter;
const char *key;
@@ -573,18 +604,20 @@ int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const key,
const char * const value)
int xmpp_stanza_set_attribute(xmpp_stanza_t *stanza,
const char *key,
const char *value)
{
char *val;
int rc;
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
if (stanza->type != XMPP_STANZA_TAG)
return XMPP_EINVOP;
if (!stanza->attributes) {
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
if (!stanza->attributes) return XMPP_EMEM;
if (!stanza->attributes)
return XMPP_EMEM;
}
val = xmpp_strdup(stanza->ctx, value);
@@ -612,12 +645,52 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
const char * const ns)
int xmpp_stanza_set_ns(xmpp_stanza_t *stanza, const char *ns)
{
return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
}
/** Add a child stanza to a stanza object.
* If do_clone is TRUE, user keeps reference to the child stanza and must call
* xmpp_stanza_release() to release the reference. If do_clone is FALSE, user
* transfers ownership and must not neither call xmpp_stanza_release() for
* the child stanza nor use it.
*
* @param stanza a Strophe stanza object
* @param child the child stanza object
* @param do_clone TRUE to increase ref count of child (default for
* xmpp_stanza_add_child())
*
* @return XMPP_EOK (0) on success or a number less than 0 on failure
*
* @ingroup Stanza
*/
int xmpp_stanza_add_child_ex(xmpp_stanza_t *stanza,
xmpp_stanza_t *child,
int do_clone)
{
xmpp_stanza_t *s;
if (do_clone) {
/* get a reference to the child */
xmpp_stanza_clone(child);
}
child->parent = stanza;
if (!stanza->children)
stanza->children = child;
else {
s = stanza->children;
while (s->next)
s = s->next;
s->next = child;
child->prev = s;
}
return XMPP_EOK;
}
/** Add a child stanza to a stanza object.
* This function clones the child and appends it to the stanza object's
* children.
@@ -631,23 +704,7 @@ int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
*/
int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
{
xmpp_stanza_t *s;
/* get a reference to the child */
xmpp_stanza_clone(child);
child->parent = stanza;
if (!stanza->children)
stanza->children = child;
else {
s = stanza->children;
while (s->next) s = s->next;
s->next = child;
child->prev = s;
}
return XMPP_EOK;
return xmpp_stanza_add_child_ex(stanza, child, 1);
}
/** Set the text data for a text stanza.
@@ -663,14 +720,15 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
*
* @ingroup Stanza
*/
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
const char * const text)
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *text)
{
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_TAG)
return XMPP_EINVOP;
stanza->type = XMPP_STANZA_TEXT;
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
stanza->data = xmpp_strdup(stanza->ctx, text);
return stanza->data == NULL ? XMPP_EMEM : XMPP_EOK;
@@ -691,16 +749,19 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
* @ingroup Stanza
*/
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char * const text,
const size_t size)
const char *text,
size_t size)
{
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_TAG)
return XMPP_EINVOP;
stanza->type = XMPP_STANZA_TEXT;
if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
if (stanza->data)
xmpp_free(stanza->ctx, stanza->data);
stanza->data = xmpp_alloc(stanza->ctx, size + 1);
if (!stanza->data) return XMPP_EMEM;
if (!stanza->data)
return XMPP_EMEM;
memcpy(stanza->data, text, size);
stanza->data[size] = 0;
@@ -718,7 +779,7 @@ int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_id(xmpp_stanza_t *stanza)
{
return xmpp_stanza_get_attribute(stanza, "id");
}
@@ -733,7 +794,7 @@ const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_ns(xmpp_stanza_t *stanza)
{
return xmpp_stanza_get_attribute(stanza, "xmlns");
}
@@ -748,7 +809,7 @@ const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_type(xmpp_stanza_t *stanza)
{
return xmpp_stanza_get_attribute(stanza, "type");
}
@@ -763,7 +824,7 @@ const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_to(xmpp_stanza_t *stanza)
{
return xmpp_stanza_get_attribute(stanza, "to");
}
@@ -778,7 +839,7 @@ const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_from(xmpp_stanza_t *stanza)
{
return xmpp_stanza_get_attribute(stanza, "from");
}
@@ -794,8 +855,8 @@ const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
const char * const name)
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t *stanza,
const char *name)
{
xmpp_stanza_t *child;
@@ -820,8 +881,8 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char * const ns)
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t *stanza,
const char *ns)
{
xmpp_stanza_t *child;
const char *child_ns;
@@ -835,6 +896,39 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
return child;
}
/** Get the first child of stanza with name and a given namespace.
* This function searches all the immediate children of stanza for a child
* stanza that matches the name and namespace provided.
* The first matching child is returned.
*
* @param stanza a Strophe stanza object
* @param name a string with the name to match
* @param ns a string with the namespace to match
*
* @return the matching child stanza object or NULL if no match was found
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t *stanza,
const char *name,
const char *ns)
{
xmpp_stanza_t *child;
const char *child_ns;
for (child = stanza->children; child; child = child->next) {
if (child->type == XMPP_STANZA_TAG &&
(strcmp(name, xmpp_stanza_get_name(child)) == 0)) {
child_ns = xmpp_stanza_get_ns(child);
if (child_ns && strcmp(ns, child_ns) == 0) {
break;
}
}
}
return child;
}
/** Get the list of children.
* This function returns the first child of the stanza object. The rest
* of the children can be obtained by calling xmpp_stanza_get_next() to
@@ -846,7 +940,7 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza)
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t *stanza)
{
return stanza->children;
}
@@ -859,7 +953,7 @@ xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza)
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t *stanza)
{
return stanza->next;
}
@@ -875,7 +969,7 @@ xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
char *xmpp_stanza_get_text(xmpp_stanza_t *stanza)
{
size_t len, clen;
xmpp_stanza_t *child;
@@ -893,10 +987,12 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
if (child->type == XMPP_STANZA_TEXT)
len += strlen(child->data);
if (len == 0) return NULL;
if (len == 0)
return NULL;
text = (char *)xmpp_alloc(stanza->ctx, len + 1);
if (!text) return NULL;
if (!text)
return NULL;
len = 0;
for (child = stanza->children; child; child = child->next)
@@ -924,7 +1020,7 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t *stanza)
{
if (stanza->type == XMPP_STANZA_TEXT)
return stanza->data;
@@ -943,8 +1039,7 @@ const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
*
* @ingroup Stanza
*/
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
const char * const id)
int xmpp_stanza_set_id(xmpp_stanza_t *stanza, const char *id)
{
return xmpp_stanza_set_attribute(stanza, "id", id);
}
@@ -960,8 +1055,7 @@ int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
const char * const type)
int xmpp_stanza_set_type(xmpp_stanza_t *stanza, const char *type)
{
return xmpp_stanza_set_attribute(stanza, "type", type);
}
@@ -978,8 +1072,7 @@ int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_set_to(xmpp_stanza_t * const stanza,
const char * const to)
int xmpp_stanza_set_to(xmpp_stanza_t *stanza, const char *to)
{
return xmpp_stanza_set_attribute(stanza, "to", to);
}
@@ -996,8 +1089,7 @@ int xmpp_stanza_set_to(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza,
const char * const from)
int xmpp_stanza_set_from(xmpp_stanza_t *stanza, const char *from)
{
return xmpp_stanza_set_attribute(stanza, "from", from);
}
@@ -1013,8 +1105,7 @@ int xmpp_stanza_set_from(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name)
const char *xmpp_stanza_get_attribute(xmpp_stanza_t *stanza, const char *name)
{
if (stanza->type != XMPP_STANZA_TAG)
return NULL;
@@ -1034,8 +1125,7 @@ const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
const char * const name)
int xmpp_stanza_del_attribute(xmpp_stanza_t *stanza, const char *name)
{
if (stanza->type != XMPP_STANZA_TAG)
return -1;
@@ -1058,23 +1148,26 @@ int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t *stanza)
{
xmpp_stanza_t *copy = NULL;
const char *from;
int rc;
from = xmpp_stanza_get_from(stanza);
if (!from) goto copy_error;
if (!from)
goto copy_error;
copy = xmpp_stanza_new(stanza->ctx);
if (!copy) goto copy_error;
if (!copy)
goto copy_error;
copy->type = stanza->type;
if (stanza->data) {
copy->data = xmpp_strdup(stanza->ctx, stanza->data);
if (!copy->data) goto copy_error;
if (!copy->data)
goto copy_error;
}
if (stanza->attributes) {
@@ -1084,20 +1177,101 @@ xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza)
xmpp_stanza_del_attribute(copy, "to");
xmpp_stanza_del_attribute(copy, "from");
xmpp_stanza_del_attribute(copy, "xmlns");
rc = xmpp_stanza_set_to(copy, from);
if (rc != XMPP_EOK) goto copy_error;
if (rc != XMPP_EOK)
goto copy_error;
return copy;
copy_error:
if (copy) xmpp_stanza_release(copy);
if (copy)
xmpp_stanza_release(copy);
return NULL;
}
static xmpp_stanza_t *
_stanza_new_with_attrs(xmpp_ctx_t *ctx, const char * const name,
const char * const type, const char * const id,
const char * const to)
/** Create an error stanza in reply to the provided stanza.
*
* 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 condition the defined-condition (e.g. "item-not-found")
* @param text optional description, may be NULL
*
* @return a new Strophe stanza object
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
const char *error_type,
const char *condition,
const char *text)
{
xmpp_ctx_t *ctx = stanza->ctx;
xmpp_stanza_t *reply = NULL;
xmpp_stanza_t *error;
xmpp_stanza_t *item;
xmpp_stanza_t *text_stanza;
const char *to;
if (!error_type || !condition)
goto quit_err;
reply = xmpp_stanza_reply(stanza);
if (!reply)
goto quit_err;
xmpp_stanza_set_type(reply, "error");
to = xmpp_stanza_get_to(stanza);
if (to)
xmpp_stanza_set_from(reply, to);
error = xmpp_stanza_new(ctx);
if (!error)
goto quit_err;
xmpp_stanza_set_name(error, "error");
xmpp_stanza_set_type(error, error_type);
xmpp_stanza_add_child(reply, error);
xmpp_stanza_release(error);
item = xmpp_stanza_new(ctx);
if (!item)
goto quit_err;
xmpp_stanza_set_name(item, condition);
xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
xmpp_stanza_add_child(error, item);
xmpp_stanza_release(item);
if (text) {
item = xmpp_stanza_new(ctx);
if (!item)
goto quit_err;
xmpp_stanza_set_name(item, "text");
xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF);
xmpp_stanza_add_child(error, item);
xmpp_stanza_release(item);
text_stanza = xmpp_stanza_new(ctx);
if (!text_stanza)
goto quit_err;
xmpp_stanza_set_text(text_stanza, text);
xmpp_stanza_add_child(item, text_stanza);
xmpp_stanza_release(text_stanza);
}
return reply;
quit_err:
if (reply)
xmpp_stanza_release(reply);
return NULL;
}
static xmpp_stanza_t *_stanza_new_with_attrs(xmpp_ctx_t *ctx,
const char *name,
const char *type,
const char *id,
const char *to)
{
xmpp_stanza_t *stanza = xmpp_stanza_new(ctx);
int ret;
@@ -1130,8 +1304,10 @@ _stanza_new_with_attrs(xmpp_ctx_t *ctx, const char * const name,
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
const char * const to, const char * const id)
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
const char *type,
const char *to,
const char *id)
{
return _stanza_new_with_attrs(ctx, "message", type, id, to);
}
@@ -1170,7 +1346,7 @@ char *xmpp_message_get_body(xmpp_stanza_t *msg)
*
* @ingroup Stanza
*/
int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text)
int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text)
{
xmpp_ctx_t *ctx = msg->ctx;
xmpp_stanza_t *body;
@@ -1216,8 +1392,7 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text)
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
const char * const id)
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);
}
@@ -1248,10 +1423,11 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
const char * const text)
xmpp_stanza_t *
xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *text)
{
xmpp_stanza_t *error = _stanza_new_with_attrs(ctx, "stream:error", NULL, NULL, NULL);
xmpp_stanza_t *error =
_stanza_new_with_attrs(ctx, "stream:error", NULL, NULL, NULL);
xmpp_stanza_t *error_type = xmpp_stanza_new(ctx);
switch (type) {
@@ -1353,3 +1529,59 @@ xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
return error;
}
static void _stub_stream_start(char *name, char **attrs, void *userdata)
{
UNUSED(name);
UNUSED(attrs);
UNUSED(userdata);
}
static void _stub_stream_end(char *name, void *userdata)
{
UNUSED(name);
UNUSED(userdata);
}
static void _stream_stanza(xmpp_stanza_t *stanza, void *userdata)
{
stanza = xmpp_stanza_clone(stanza);
*(xmpp_stanza_t **)userdata = stanza;
}
/** Create a stanza object from the string.
* This function allocates and initializes a stanza object which represents
* stanza located in the string.
* The stanza will have a reference count of one, so the caller does not
* need to clone it.
*
* @param ctx a Strophe context object
* @param str stanza in NULL terminated string representation
*
* @return a stanza object or NULL on an error
*
* @ingroup Stanza
*/
xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str)
{
xmpp_stanza_t *stanza = NULL;
parser_t *parser;
int ret;
static const char *start = "<stream>";
static const char *end = "</stream>";
parser = parser_new(ctx, _stub_stream_start, _stub_stream_end,
_stream_stanza, &stanza);
if (parser) {
ret = parser_feed(parser, (char *)start, strlen(start)) &&
parser_feed(parser, (char *)str, strlen(str)) &&
parser_feed(parser, (char *)end, strlen(end));
parser_free(parser);
if (!ret && stanza) {
xmpp_stanza_release(stanza);
stanza = NULL;
}
}
return stanza;
}

View File

@@ -27,6 +27,9 @@ void tls_shutdown(void);
tls_t *tls_new(xmpp_conn_t *conn);
void tls_free(tls_t *tls);
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n);
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn);
int tls_set_credentials(tls_t *tls, const char *cafilename);
int tls_start(tls_t *tls);
@@ -35,8 +38,8 @@ int tls_stop(tls_t *tls);
int tls_error(tls_t *tls);
int tls_pending(tls_t *tls);
int tls_read(tls_t *tls, void * const buff, const size_t len);
int tls_write(tls_t *tls, const void * const buff, const size_t len);
int tls_read(tls_t *tls, void *buff, size_t len);
int tls_write(tls_t *tls, const void *buff, size_t len);
int tls_clear_pending_write(tls_t *tls);
int tls_is_recoverable(int error);

View File

@@ -33,59 +33,90 @@ void tls_shutdown(void)
return;
}
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
UNUSED(conn);
UNUSED(n);
/* always fail */
return NULL;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
UNUSED(conn);
/* always fail */
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
UNUSED(conn);
/* always fail */
return NULL;
}
void tls_free(tls_t *tls)
{
UNUSED(tls);
return;
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(tls);
UNUSED(cafilename);
return -1;
}
int tls_start(tls_t *tls)
{
UNUSED(tls);
return -1;
}
int tls_stop(tls_t *tls)
{
UNUSED(tls);
return -1;
}
int tls_error(tls_t *tls)
{
UNUSED(tls);
/* todo: some kind of error polling/dump */
return 0;
}
int tls_pending(tls_t *tls)
{
UNUSED(tls);
return 0;
}
int tls_read(tls_t *tls, void * const buff, const size_t len)
int tls_read(tls_t *tls, void *buff, size_t len)
{
UNUSED(tls);
UNUSED(buff);
UNUSED(len);
return -1;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
int tls_write(tls_t *tls, const void *buff, size_t len)
{
UNUSED(tls);
UNUSED(buff);
UNUSED(len);
return -1;
}
int tls_clear_pending_write(tls_t *tls)
{
UNUSED(tls);
return -1;
}
int tls_is_recoverable(int error)
{
UNUSED(error);
return 0;
}

View File

@@ -13,7 +13,10 @@
* TLS implementation with GNUTLS
*/
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <gnutls/x509-ext.h>
#include "common.h"
#include "tls.h"
@@ -27,6 +30,7 @@ struct _tls {
sock_t sock;
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
gnutls_x509_crt_t client_cert;
int lasterror;
};
@@ -46,11 +50,135 @@ void tls_shutdown(void)
gnutls_global_deinit();
}
static gnutls_x509_crt_t _tls_load_cert(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;
res = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
gnutls_free(data.data);
if (res < 0)
goto LBL_ERR;
return cert;
LBL_ERR:
gnutls_x509_crt_deinit(cert);
return NULL;
}
static void _tls_free_cert(xmpp_conn_t *conn, gnutls_x509_crt_t cert)
{
if (conn->tls && conn->tls->client_cert == cert)
return;
gnutls_x509_crt_deinit(cert);
}
static int _tls_get_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert,
unsigned int n,
char **ret)
{
gnutls_datum_t san;
size_t name_len, oid_len;
char oid[128], name[128];
name_len = oid_len = 128;
int res =
gnutls_x509_crt_get_subject_alt_name(cert, n, name, &name_len, NULL);
if (res == GNUTLS_SAN_OTHERNAME_XMPP) {
/* This is the happy flow path with fixed GnuTLS.
* While implementing this I stumbled over an issue in GnuTLS
* which lead to
* https://gitlab.com/gnutls/gnutls/-/merge_requests/1397
*/
if (ret) {
*ret = xmpp_strdup(conn->ctx, name);
}
return GNUTLS_SAN_OTHERNAME_XMPP;
}
if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
if (res != GNUTLS_SAN_OTHERNAME)
return GNUTLS_E_X509_UNKNOWN_SAN;
res = gnutls_x509_crt_get_subject_alt_othername_oid(cert, n, oid, &oid_len);
if (res == GNUTLS_SAN_OTHERNAME_XMPP) {
gnutls_datum_t xmpp_addr;
san.data = (unsigned char *)name;
san.size = name_len;
res = gnutls_x509_othername_to_virtual(oid, &san, NULL, &xmpp_addr);
if (res < 0) {
gnutls_free(xmpp_addr.data);
return GNUTLS_E_MEMORY_ERROR;
}
if (ret) {
*ret = xmpp_strdup(conn->ctx, (char *)xmpp_addr.data);
}
gnutls_free(xmpp_addr.data);
return GNUTLS_SAN_OTHERNAME_XMPP;
}
return GNUTLS_E_X509_UNKNOWN_SAN;
}
int _tls_id_on_xmppaddr(xmpp_conn_t *conn,
gnutls_x509_crt_t cert,
unsigned int n,
char **ret)
{
int res = GNUTLS_E_SUCCESS;
unsigned int i, j;
for (i = j = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; ++i) {
res = _tls_get_id_on_xmppaddr(conn, cert, i, NULL);
if (res == GNUTLS_SAN_OTHERNAME_XMPP) {
if (j == n) {
res = _tls_get_id_on_xmppaddr(conn, cert, i, ret);
break;
}
j++;
}
}
return res;
}
/** Search through the SubjectAlternativeNames and return the next
* id-on-xmppAddr element starting from `n`.
*/
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
char *ret = NULL;
gnutls_x509_crt_t cert = _tls_load_cert(conn);
if (cert == NULL)
return NULL;
_tls_id_on_xmppaddr(conn, cert, n, &ret);
_tls_free_cert(conn, cert);
return ret;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
unsigned int ret = 0, n;
int res = GNUTLS_E_SUCCESS;
gnutls_x509_crt_t cert = _tls_load_cert(conn);
if (cert == NULL)
return 0;
for (n = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; ++n) {
res = _tls_id_on_xmppaddr(conn, cert, n, NULL);
if (res == GNUTLS_SAN_OTHERNAME_XMPP)
ret++;
}
_tls_free_cert(conn, cert);
return ret;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
if (tls) {
memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx;
tls->sock = conn->sock;
gnutls_init(&tls->session, GNUTLS_CLIENT);
@@ -58,6 +186,21 @@ tls_t *tls_new(xmpp_conn_t *conn)
gnutls_certificate_allocate_credentials(&tls->cred);
tls_set_credentials(tls, CAFILE);
if (conn->tls_client_cert && conn->tls_client_key) {
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;
}
gnutls_certificate_set_x509_key_file(
tls->cred, conn->tls_client_cert, conn->tls_client_key,
GNUTLS_X509_FMT_PEM);
}
gnutls_set_default_priority(tls->session);
/* fixme: this may require setting a callback on win32? */
@@ -69,6 +212,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
void tls_free(tls_t *tls)
{
if (tls->client_cert)
gnutls_x509_crt_deinit(tls->client_cert);
gnutls_deinit(tls->session);
gnutls_certificate_free_credentials(tls->cred);
xmpp_free(tls->ctx, tls);
@@ -79,8 +224,8 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
int err;
/* set trusted credentials -- takes a .pem filename */
err = gnutls_certificate_set_x509_trust_file(tls->cred,
cafilename, GNUTLS_X509_FMT_PEM);
err = gnutls_certificate_set_x509_trust_file(tls->cred, cafilename,
GNUTLS_X509_FMT_PEM);
if (err >= 0) {
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
tls->cred);
@@ -120,7 +265,7 @@ int tls_pending(tls_t *tls)
return gnutls_record_check_pending(tls->session);
}
int tls_read(tls_t *tls, void * const buff, const size_t len)
int tls_read(tls_t *tls, void *buff, size_t len)
{
int ret;
@@ -130,7 +275,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
return ret;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
int tls_write(tls_t *tls, const void *buff, size_t len)
{
int ret;
@@ -142,5 +287,6 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
int tls_clear_pending_write(tls_t *tls)
{
UNUSED(tls);
return 0;
}

View File

@@ -47,11 +47,34 @@
#endif
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static const unsigned char *ASN1_STRING_get0_data(ASN1_STRING *asn1)
{
return ASN1_STRING_data(asn1);
}
#endif
#if OPENSSL_VERSION_NUMBER < 0x10000000L
static int GENERAL_NAME_get0_otherName(const GENERAL_NAME *gen,
ASN1_OBJECT **poid,
ASN1_TYPE **pvalue)
{
if (gen->type != GEN_OTHERNAME)
return 0;
if (poid)
*poid = gen->d.otherName->type_id;
if (pvalue)
*pvalue = gen->d.otherName->value;
return 1;
}
#endif
struct _tls {
xmpp_ctx_t *ctx;
sock_t sock;
SSL_CTX *ssl_ctx;
SSL *ssl;
X509 *client_cert;
int lasterror;
};
@@ -62,9 +85,128 @@ enum {
};
static void _tls_sock_wait(tls_t *tls, int error);
static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size);
static void _tls_set_error(tls_t *tls, int error);
static void _tls_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 int _tls_xaddr_nid(void);
static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res);
static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn);
#define TLS_ERROR_STR(error, table) \
_tls_error_str(error, table, ARRAY_SIZE(table))
#define TLS_ERROR_FIELD(x) [x] = #x
const char *tls_errors[] = {
TLS_ERROR_FIELD(SSL_ERROR_NONE),
TLS_ERROR_FIELD(SSL_ERROR_SSL),
TLS_ERROR_FIELD(SSL_ERROR_WANT_READ),
TLS_ERROR_FIELD(SSL_ERROR_WANT_WRITE),
TLS_ERROR_FIELD(SSL_ERROR_WANT_X509_LOOKUP),
TLS_ERROR_FIELD(SSL_ERROR_SYSCALL),
TLS_ERROR_FIELD(SSL_ERROR_ZERO_RETURN),
TLS_ERROR_FIELD(SSL_ERROR_WANT_CONNECT),
TLS_ERROR_FIELD(SSL_ERROR_WANT_ACCEPT),
#ifndef LIBRESSL_VERSION_NUMBER
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC),
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC_JOB),
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
TLS_ERROR_FIELD(SSL_ERROR_WANT_CLIENT_HELLO_CB),
#endif
#endif /* !LIBRESSL_VERSION_NUMBER */
};
const char *cert_errors[] = {
TLS_ERROR_FIELD(X509_V_OK),
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
TLS_ERROR_FIELD(X509_V_ERR_UNSPECIFIED),
#endif
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_CRL),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY),
TLS_ERROR_FIELD(X509_V_ERR_CERT_SIGNATURE_FAILURE),
TLS_ERROR_FIELD(X509_V_ERR_CRL_SIGNATURE_FAILURE),
TLS_ERROR_FIELD(X509_V_ERR_CERT_NOT_YET_VALID),
TLS_ERROR_FIELD(X509_V_ERR_CERT_HAS_EXPIRED),
TLS_ERROR_FIELD(X509_V_ERR_CRL_NOT_YET_VALID),
TLS_ERROR_FIELD(X509_V_ERR_CRL_HAS_EXPIRED),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD),
TLS_ERROR_FIELD(X509_V_ERR_OUT_OF_MEM),
TLS_ERROR_FIELD(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT),
TLS_ERROR_FIELD(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_CERT_CHAIN_TOO_LONG),
TLS_ERROR_FIELD(X509_V_ERR_CERT_REVOKED),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CA),
TLS_ERROR_FIELD(X509_V_ERR_PATH_LENGTH_EXCEEDED),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_PURPOSE),
TLS_ERROR_FIELD(X509_V_ERR_CERT_UNTRUSTED),
TLS_ERROR_FIELD(X509_V_ERR_CERT_REJECTED),
TLS_ERROR_FIELD(X509_V_ERR_SUBJECT_ISSUER_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_AKID_SKID_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_CERTSIGN),
TLS_ERROR_FIELD(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER),
TLS_ERROR_FIELD(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN),
TLS_ERROR_FIELD(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_NON_CA),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED),
TLS_ERROR_FIELD(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_POLICY_EXTENSION),
TLS_ERROR_FIELD(X509_V_ERR_NO_EXPLICIT_POLICY),
TLS_ERROR_FIELD(X509_V_ERR_APPLICATION_VERIFICATION),
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
TLS_ERROR_FIELD(X509_V_ERR_DIFFERENT_CRL_SCOPE),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE),
TLS_ERROR_FIELD(X509_V_ERR_UNNESTED_RESOURCE),
TLS_ERROR_FIELD(X509_V_ERR_PERMITTED_VIOLATION),
TLS_ERROR_FIELD(X509_V_ERR_EXCLUDED_VIOLATION),
TLS_ERROR_FIELD(X509_V_ERR_SUBTREE_MINMAX),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX),
TLS_ERROR_FIELD(X509_V_ERR_CRL_PATH_VALIDATION_ERROR),
#ifndef LIBRESSL_VERSION_NUMBER
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_VERSION),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_ALGORITHM),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_CURVE),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256),
#endif /* !LIBRESSL_VERSION_NUMBER */
TLS_ERROR_FIELD(X509_V_ERR_HOSTNAME_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_EMAIL_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_IP_ADDRESS_MISMATCH),
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CALL),
TLS_ERROR_FIELD(X509_V_ERR_STORE_LOOKUP),
#ifndef LIBRESSL_VERSION_NUMBER
TLS_ERROR_FIELD(X509_V_ERR_PATH_LOOP),
TLS_ERROR_FIELD(X509_V_ERR_DANE_NO_MATCH),
TLS_ERROR_FIELD(X509_V_ERR_EE_KEY_TOO_SMALL),
TLS_ERROR_FIELD(X509_V_ERR_CA_KEY_TOO_SMALL),
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),
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 /* !LIBRESSL_VERSION_NUMBER */
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
};
#undef TLS_ERROR_FIELD
void tls_initialize(void)
{
@@ -74,6 +216,8 @@ void tls_initialize(void)
#else
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif
/* init xmppAddr OID */
_tls_xaddr_nid();
}
void tls_shutdown(void)
@@ -84,6 +228,7 @@ void tls_shutdown(void)
* memory rather than cause random crashes of the main program.
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
OBJ_cleanup();
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
@@ -103,6 +248,55 @@ int tls_error(tls_t *tls)
return tls->lasterror;
}
/** Search through the SubjectAlternativeNames and return the next
* id-on-xmppAddr element starting from `n`.
*/
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
char *ret = NULL;
int i, j;
GENERAL_NAMES *names = _tls_cert_get_names(conn);
if (!names)
return NULL;
int num_names = sk_GENERAL_NAME_num(names);
for (i = j = 0; i < num_names; ++i) {
char *res;
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
if (name == NULL)
break;
if (_tls_name_to_xmppaddr(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);
OPENSSL_free(res);
break;
}
j++;
OPENSSL_free(res);
}
GENERAL_NAMES_free(names);
return ret;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
unsigned int ret = 0;
GENERAL_NAMES *names = _tls_cert_get_names(conn);
if (!names)
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);
if (_tls_name_to_xmppaddr(name, NULL))
continue;
ret++;
}
GENERAL_NAMES_free(names);
return ret;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
@@ -110,11 +304,19 @@ tls_t *tls_new(xmpp_conn_t *conn)
if (tls) {
int ret;
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
X509_VERIFY_PARAM *param;
#endif
memset(tls, 0, sizeof(*tls));
tls->ctx = conn->ctx;
tls->sock = conn->sock;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
tls->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#else
tls->ssl_ctx = SSL_CTX_new(TLS_client_method());
#endif
if (tls->ssl_ctx == NULL)
goto err;
@@ -126,28 +328,62 @@ 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->tls_client_cert && conn->tls_client_key) {
tls->client_cert = _tls_cert_read(conn);
if (!tls->client_cert) {
xmpp_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);
} else {
/* If the server asks for a client certificate, don't send one. */
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
}
SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
if (ret == 0 && !conn->tls_trust) {
/*
* Returns 1 on success and 0 on failure. A missing default
* 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");
goto err_free_cert;
}
tls->ssl = SSL_new(tls->ssl_ctx);
if (tls->ssl == NULL)
goto err_free_ctx;
goto err_free_cert;
#if OPENSSL_VERSION_NUMBER >= 0x0908060L && !defined(OPENSSL_NO_TLSEXT)
/* Enable SNI. */
SSL_set_tlsext_host_name(tls->ssl, conn->domain);
#endif
/* Trust server's certificate when user sets the flag explicitly. */
mode = conn->tls_trust ? SSL_VERIFY_NONE : SSL_VERIFY_PEER;
SSL_set_verify(tls->ssl, mode, 0);
SSL_set_verify(tls->ssl, mode, NULL);
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
X509_VERIFY_PARAM *param = SSL_get0_param(tls->ssl);
param = SSL_get0_param(tls->ssl);
/*
* Allow only complete wildcards. RFC 6125 discourages wildcard usage
* completely, and lists internationalized domain names as a reason
* against partial wildcards.
* See https://tools.ietf.org/html/rfc6125#section-7.2 for more information.
* See https://tools.ietf.org/html/rfc6125#section-7.2 for more
* information.
*/
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set_hostflags(param,
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, conn->domain, 0);
#endif
@@ -160,6 +396,8 @@ tls_t *tls_new(xmpp_conn_t *conn)
err_free_ssl:
SSL_free(tls->ssl);
err_free_cert:
X509_free(tls->client_cert);
err_free_ctx:
SSL_CTX_free(tls->ssl_ctx);
err:
@@ -171,12 +409,15 @@ err:
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);
}
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(tls);
UNUSED(cafilename);
return -1;
}
@@ -203,8 +444,13 @@ int tls_start(tls_t *tls)
}
x509_res = SSL_get_verify_result(tls->ssl);
xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
x509_res == X509_V_OK ? "passed" : "FAILED");
if (x509_res == X509_V_OK) {
xmpp_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);
}
_tls_dump_cert_info(tls);
_tls_set_error(tls, error);
@@ -247,10 +493,9 @@ int tls_stop(tls_t *tls)
int tls_is_recoverable(int error)
{
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ
|| error == SSL_ERROR_WANT_WRITE
|| error == SSL_ERROR_WANT_CONNECT
|| error == SSL_ERROR_WANT_ACCEPT);
return (error == SSL_ERROR_NONE || error == SSL_ERROR_WANT_READ ||
error == SSL_ERROR_WANT_WRITE || error == SSL_ERROR_WANT_CONNECT ||
error == SSL_ERROR_WANT_ACCEPT);
}
int tls_pending(tls_t *tls)
@@ -258,7 +503,7 @@ int tls_pending(tls_t *tls)
return SSL_pending(tls->ssl);
}
int tls_read(tls_t *tls, void * const buff, const size_t len)
int tls_read(tls_t *tls, void *buff, size_t len)
{
int ret;
@@ -268,7 +513,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
return ret;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
int tls_write(tls_t *tls, const void *buff, size_t len)
{
int ret;
@@ -280,6 +525,7 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
int tls_clear_pending_write(tls_t *tls)
{
UNUSED(tls);
return 0;
}
@@ -291,7 +537,8 @@ static void _tls_sock_wait(tls_t *tls, int error)
int nfds;
int ret;
if (error == SSL_ERROR_NONE) return;
if (error == SSL_ERROR_NONE)
return;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
@@ -299,8 +546,9 @@ static void _tls_sock_wait(tls_t *tls, int error)
FD_SET(tls->sock, &rfds);
if (error == SSL_ERROR_WANT_WRITE)
FD_SET(tls->sock, &wfds);
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) ?
tls->sock + 1 : 0;
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)
? tls->sock + 1
: 0;
do {
tv.tv_sec = TLS_TIMEOUT_SEC;
tv.tv_usec = TLS_TIMEOUT_USEC;
@@ -308,10 +556,16 @@ static void _tls_sock_wait(tls_t *tls, int error)
} while (ret == -1 && errno == EINTR);
}
static const char *_tls_error_str(int error, const char **tbl, size_t tbl_size)
{
return (error >= 0 && (size_t)error < tbl_size) ? tbl[error] : "UNKNOWN";
}
static void _tls_set_error(tls_t *tls, int error)
{
if (error != 0 && !tls_is_recoverable(error)) {
xmpp_debug(tls->ctx, "tls", "error=%d errno=%d", error, errno);
xmpp_debug(tls->ctx, "tls", "error=%s(%d) errno=%d",
TLS_ERROR_STR(error, tls_errors), error, errno);
_tls_log_error(tls->ctx);
}
tls->lasterror = error;
@@ -353,3 +607,92 @@ static void _tls_dump_cert_info(tls_t *tls)
X509_free(cert);
}
}
static X509 *_tls_cert_read(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");
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));
}
}
return c;
}
static int _tls_xaddr_nid(void)
{
static int xaddr_nid = NID_undef;
if (xaddr_nid == NID_undef) {
xaddr_nid = OBJ_sn2nid("id-on-xmppAddr");
}
if (xaddr_nid == NID_undef) {
xaddr_nid = OBJ_create("1.3.6.1.5.5.7.8.5", "id-on-xmppAddr",
"XmppAddr Identifier");
}
return xaddr_nid;
}
static GENERAL_NAMES *_tls_cert_get_names(xmpp_conn_t *conn)
{
X509 *client_cert;
GENERAL_NAMES *names = NULL;
client_cert = _tls_cert_read(conn);
if (!client_cert)
return NULL;
int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
X509_EXTENSION *san_ext = X509_get_ext(client_cert, san);
if (!san_ext)
goto OUT;
ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext);
if (!data)
goto OUT;
const unsigned char *d = ASN1_STRING_get0_data(data);
if (!d)
goto OUT;
names = d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
OUT:
if (!conn->tls || !conn->tls->client_cert)
X509_free(client_cert);
return names;
}
/** Convert GENERAL_NAME* to a string
*
* This checks whether the GENERAL_NAME* that is given has the
* correct id-on-xmppAddr set and then optionally converts this
* form ASN.1 to a string/char*.
*
* When `res` pointer is set to NULL this method doesn't allocate
* the result but only checks whether it is in the correct format.
*
* @param name Pointer to the GENERAL_NAME that shall be converted
* @param res Result-pointer (optional, can be NULL)
*
* @return classic Unix style - 0=success, 1=error
*/
static int _tls_name_to_xmppaddr(GENERAL_NAME *name, char **res)
{
ASN1_OBJECT *oid;
ASN1_TYPE *val;
if (!name || name->type != GEN_OTHERNAME)
return 1;
if (GENERAL_NAME_get0_otherName(name, &oid, &val) == 0)
return 1;
if (OBJ_obj2nid(oid) != _tls_xaddr_nid() || !val)
return 1;
if (!res)
return 0;
if (ASN1_STRING_to_UTF8((unsigned char **)res, val->value.asn1_string) < 0)
return 1;
return 0;
}

View File

@@ -61,6 +61,21 @@ void tls_shutdown(void)
return;
}
char *tls_id_on_xmppaddr(xmpp_conn_t *conn, unsigned int n)
{
UNUSED(n);
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return NULL;
}
unsigned int tls_id_on_xmppaddr_num(xmpp_conn_t *conn)
{
/* always fail */
xmpp_error(conn->ctx, "tls", "Client-Authentication not implemented");
return 0;
}
tls_t *tls_new(xmpp_conn_t *conn)
{
xmpp_ctx_t *ctx = conn->ctx;
@@ -118,8 +133,7 @@ tls_t *tls_new(xmpp_conn_t *conn)
ret = tls->sft->QuerySecurityPackageInfo(UNISP_NAME, &(tls->spi));
if (ret != SEC_E_OK)
{
if (ret != SEC_E_OK) {
tls_free(tls);
return NULL;
}
@@ -140,11 +154,11 @@ tls_t *tls_new(xmpp_conn_t *conn)
(void)algs;
#endif
ret = tls->sft->AcquireCredentialsHandleA(NULL, UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL, &(tls->hcred), NULL);
ret = tls->sft->AcquireCredentialsHandleA(
NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &scred, NULL, NULL,
&(tls->hcred), NULL);
if (ret != SEC_E_OK)
{
if (ret != SEC_E_OK) {
tls_free(tls);
return NULL;
}
@@ -155,23 +169,23 @@ tls_t *tls_new(xmpp_conn_t *conn)
/* This bunch of queries should trip up wine until someone fixes
* schannel support there */
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
if (ret != SEC_E_OK)
{
ret = tls->sft->QueryCredentialsAttributes(
&(tls->hcred), SECPKG_ATTR_SUPPORTED_ALGS, &spc_sa);
if (ret != SEC_E_OK) {
tls_free(tls);
return NULL;
}
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
if (ret != SEC_E_OK)
{
ret = tls->sft->QueryCredentialsAttributes(
&(tls->hcred), SECPKG_ATTR_CIPHER_STRENGTHS, &spc_cs);
if (ret != SEC_E_OK) {
tls_free(tls);
return NULL;
}
ret = tls->sft->QueryCredentialsAttributes(&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
if (ret != SEC_E_OK)
{
ret = tls->sft->QueryCredentialsAttributes(
&(tls->hcred), SECPKG_ATTR_SUPPORTED_PROTOCOLS, &spc_sp);
if (ret != SEC_E_OK) {
tls_free(tls);
return NULL;
}
@@ -210,6 +224,8 @@ void tls_free(tls_t *tls)
int tls_set_credentials(tls_t *tls, const char *cafilename)
{
UNUSED(tls);
UNUSED(cafilename);
return -1;
}
@@ -225,10 +241,10 @@ int tls_start(tls_t *tls)
/* use the domain there as our name */
name = tls->conn->domain;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT
| ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR
| ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM
| ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;
ctxtreq = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM |
ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY;
memset(&(sbout[0]), 0, sizeof(sbout[0]));
sbout[0].BufferType = SECBUFFER_TOKEN;
@@ -251,16 +267,16 @@ int tls_start(tls_t *tls)
sbdin.cBuffers = 2;
sbdin.pBuffers = sbin;
ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), NULL, name, ctxtreq, 0, 0,
NULL, 0, &(tls->hctxt), &sbdout,
&ctxtattr, NULL);
ret = tls->sft->InitializeSecurityContextA(
&(tls->hcred), NULL, name, ctxtreq, 0, 0, NULL, 0, &(tls->hctxt),
&sbdout, &ctxtattr, NULL);
unsigned char *p = sbin[0].pvBuffer;
int len = 0;
while (ret == SEC_I_CONTINUE_NEEDED
|| ret == SEC_I_INCOMPLETE_CREDENTIALS
|| ret == SEC_E_INCOMPLETE_MESSAGE) {
while (ret == SEC_I_CONTINUE_NEEDED ||
ret == SEC_I_INCOMPLETE_CREDENTIALS ||
ret == SEC_E_INCOMPLETE_MESSAGE) {
int inbytes = 0;
if (ret != SEC_E_INCOMPLETE_MESSAGE) {
@@ -275,9 +291,7 @@ int tls_start(tls_t *tls)
sent = sock_write(tls->sock, writebuff, writelen);
if (sent == -1) {
tls->lasterror = sock_error();
}
else
{
} else {
writebuff += sent;
writelen -= sent;
}
@@ -319,20 +333,16 @@ int tls_start(tls_t *tls)
if (inbytes > 0) {
len += inbytes;
p += inbytes;
}
else
{
} else {
tls->lasterror = sock_error();
}
}
sbin[0].cbBuffer = len;
ret = tls->sft->InitializeSecurityContextA(&(tls->hcred), &(tls->hctxt), name,
ctxtreq, 0, 0, &sbdin, 0,
&(tls->hctxt), &sbdout,
&ctxtattr, NULL);
ret = tls->sft->InitializeSecurityContextA(
&(tls->hcred), &(tls->hctxt), name, ctxtreq, 0, 0, &sbdin, 0,
&(tls->hctxt), &sbdout, &ctxtattr, NULL);
}
if (ret == SEC_E_OK) {
@@ -342,9 +352,7 @@ int tls_start(tls_t *tls)
sent = sock_write(tls->sock, writebuff, writelen);
if (sent == -1) {
tls->lasterror = sock_error();
}
else
{
} else {
writebuff += sent;
writelen -= sent;
}
@@ -358,20 +366,21 @@ int tls_start(tls_t *tls)
if (ret != SEC_E_OK) {
tls->lasterror = ret;
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx", (unsigned long)ret);
xmpp_error(tls->ctx, "TLSS", "Schannel error 0x%lx",
(unsigned long)ret);
return 0;
}
tls->sft->QueryContextAttributes(&(tls->hctxt), SECPKG_ATTR_STREAM_SIZES,
&(tls->spcss));
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
+ tls->spcss.cbTrailer;
tls->recvbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage +
tls->spcss.cbTrailer;
tls->recvbuffer = xmpp_alloc(tls->ctx, tls->recvbuffermaxlen);
tls->recvbufferpos = 0;
tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage
+ tls->spcss.cbTrailer;
tls->sendbuffermaxlen = tls->spcss.cbHeader + tls->spcss.cbMaximumMessage +
tls->spcss.cbTrailer;
tls->sendbuffer = xmpp_alloc(tls->ctx, tls->sendbuffermaxlen);
tls->sendbufferpos = 0;
tls->sendbufferlen = 0;
@@ -385,6 +394,7 @@ int tls_start(tls_t *tls)
int tls_stop(tls_t *tls)
{
UNUSED(tls);
return -1;
}
@@ -395,12 +405,13 @@ int tls_error(tls_t *tls)
int tls_is_recoverable(int error)
{
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE
|| error == WSAEWOULDBLOCK || error == WSAEMSGSIZE
|| error == WSAEINPROGRESS);
return (error == SEC_E_OK || error == SEC_E_INCOMPLETE_MESSAGE ||
error == WSAEWOULDBLOCK || error == WSAEMSGSIZE ||
error == WSAEINPROGRESS);
}
int tls_pending(tls_t *tls) {
int tls_pending(tls_t *tls)
{
// There are 3 cases:
// - there is data in ready buffer, so it is by default pending
// - there is data in recv buffer. If it is not decrypted yet, means it
@@ -416,13 +427,12 @@ int tls_pending(tls_t *tls) {
return 0;
}
int tls_read(tls_t *tls, void * const buff, const size_t len)
int tls_read(tls_t *tls, void *buff, size_t len)
{
int bytes;
/* first, if we've got some ready data, put that in the buffer */
if (tls->readybufferpos < tls->readybufferlen)
{
if (tls->readybufferpos < tls->readybufferlen) {
if (len < tls->readybufferlen - tls->readybufferpos) {
bytes = len;
} else {
@@ -519,8 +529,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
return -1;
} else if (ret == SEC_I_RENEGOTIATE) {
ret = tls_start(tls);
if (!ret)
{
if (!ret) {
return -1;
}
@@ -542,8 +551,7 @@ int tls_read(tls_t *tls, void * const buff, const size_t len)
int tls_clear_pending_write(tls_t *tls)
{
if (tls->sendbufferpos < tls->sendbufferlen)
{
if (tls->sendbufferpos < tls->sendbufferlen) {
int bytes;
bytes = sock_write(tls->sock, tls->sendbuffer + tls->sendbufferpos,
@@ -564,7 +572,7 @@ int tls_clear_pending_write(tls_t *tls)
return 1;
}
int tls_write(tls_t *tls, const void * const buff, const size_t len)
int tls_write(tls_t *tls, const void *buff, size_t len)
{
SecBufferDesc sbdenc;
SecBuffer sbenc[4];
@@ -601,23 +609,22 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
sbenc[1].pvBuffer = tls->sendbuffer + tls->spcss.cbHeader;
while (remain > 0)
{
while (remain > 0) {
if (remain > tls->spcss.cbMaximumMessage) {
sbenc[1].cbBuffer = tls->spcss.cbMaximumMessage;
} else {
sbenc[1].cbBuffer = remain;
}
sbenc[2].pvBuffer = (unsigned char *)sbenc[1].pvBuffer
+ sbenc[1].cbBuffer;
sbenc[2].pvBuffer =
(unsigned char *)sbenc[1].pvBuffer + sbenc[1].cbBuffer;
sbenc[2].cbBuffer = tls->spcss.cbTrailer;
memcpy(sbenc[1].pvBuffer, p, sbenc[1].cbBuffer);
p += tls->spcss.cbMaximumMessage;
tls->sendbufferlen = sbenc[0].cbBuffer + sbenc[1].cbBuffer
+ sbenc[2].cbBuffer;
tls->sendbufferlen =
sbenc[0].cbBuffer + sbenc[1].cbBuffer + sbenc[2].cbBuffer;
ret = tls->sft->EncryptMessage(&(tls->hctxt), 0, &sbdenc, 0);
@@ -645,7 +652,6 @@ int tls_write(tls_t *tls, const void * const buff, const size_t len)
if (ret == 0 || (ret == -1 && tls_is_recoverable(tls_error(tls)))) {
return sent;
}
}
return sent;

252
src/tls_securetransport.c Normal file
View File

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

View File

@@ -38,7 +38,7 @@
*
* @return a new allocates string with the same data as s or NULL on error
*/
char *xmpp_strdup(const xmpp_ctx_t * const ctx, const char * const s)
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s)
{
size_t len;
char *copy;
@@ -86,8 +86,24 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
*/
uint64_t time_stamp(void)
{
#ifdef _WIN32
return timeGetTime();
#if defined(_WIN32) || defined(_XBOX_ONE)
#ifndef __GNUC__
#define EPOCHFILETIME (116444736000000000i64)
#else
#define EPOCHFILETIME (116444736000000000LL)
#endif
FILETIME ft;
LARGE_INTEGER li;
__int64 t;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
t = li.QuadPart; /* In 100-nanosecond intervals */
t -= EPOCHFILETIME; /* Offset to the Epoch time */
return (uint64_t)(t / 10000); /* Convert to milliseconds */
#else
struct timeval tv;
@@ -119,7 +135,7 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
*
* @param conn a Strophe connection object
*/
void disconnect_mem_error(xmpp_conn_t * const conn)
void disconnect_mem_error(xmpp_conn_t *conn)
{
xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
xmpp_disconnect(conn);

View File

@@ -18,6 +18,10 @@
#include "ostypes.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif /* ARRAY_SIZE */
/* TODO evaluate x and y only once */
#define xmpp_min(x, y) ((x) < (y) ? (x) : (y))

308
strophe.h
View File

@@ -39,6 +39,10 @@ extern "C" {
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-streams'.
*/
#define XMPP_NS_STREAMS_IETF "urn:ietf:params:xml:ns:xmpp-streams"
/** @def XMPP_NS_STANZAS_IETF
* Namespace definition for 'urn:ietf:params:xml:ns:xmpp-stanzas'.
*/
#define XMPP_NS_STANZAS_IETF "urn:ietf:params:xml:ns:xmpp-stanzas"
/** @def XMPP_NS_TLS
* Namespace definition for 'url:ietf:params:xml:ns:xmpp-tls'.
*/
@@ -71,6 +75,10 @@ extern "C" {
* Namespace definition for 'jabber:iq:roster'.
*/
#define XMPP_NS_ROSTER "jabber:iq:roster"
/** @def XMPP_NS_REGISTER
* Namespace definition for 'jabber:iq:register'.
*/
#define XMPP_NS_REGISTER "jabber:iq:register"
/* error defines */
/** @def XMPP_EOK
@@ -114,18 +122,17 @@ typedef struct _xmpp_log_t xmpp_log_t;
/* opaque run time context containing the above hooks */
typedef struct _xmpp_ctx_t xmpp_ctx_t;
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t * const mem,
const xmpp_log_t * const log);
void xmpp_ctx_free(xmpp_ctx_t * const ctx);
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log);
void xmpp_ctx_free(xmpp_ctx_t *ctx);
/* free some blocks returned by other APIs, for example the
buffer you get from xmpp_stanza_to_text */
void xmpp_free(const xmpp_ctx_t * const ctx, void *p);
void xmpp_free(const xmpp_ctx_t *ctx, void *p);
struct _xmpp_mem_t {
void *(*alloc)(const size_t size, void * const userdata);
void (*free)(void *p, void * const userdata);
void *(*realloc)(void *p, const size_t size, void * const userdata);
void *(*alloc)(size_t size, void *userdata);
void (*free)(void *p, void *userdata);
void *(*realloc)(void *p, size_t size, void *userdata);
void *userdata;
};
@@ -136,16 +143,12 @@ typedef enum {
XMPP_LEVEL_ERROR
} xmpp_log_level_t;
typedef enum {
XMPP_UNKNOWN,
XMPP_CLIENT,
XMPP_COMPONENT
} xmpp_conn_type_t;
typedef enum { XMPP_UNKNOWN, XMPP_CLIENT, XMPP_COMPONENT } xmpp_conn_type_t;
typedef void (*xmpp_log_handler)(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
typedef void (*xmpp_log_handler)(void *userdata,
xmpp_log_level_t level,
const char *area,
const char *msg);
struct _xmpp_log_t {
xmpp_log_handler handler;
@@ -215,95 +218,108 @@ typedef struct {
xmpp_stanza_t *stanza;
} xmpp_stream_error_t;
typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
const xmpp_conn_event_t event,
const int error,
xmpp_stream_error_t * const stream_error,
void * const userdata);
typedef void (*xmpp_conn_handler)(xmpp_conn_t *conn,
xmpp_conn_event_t event,
int error,
xmpp_stream_error_t *stream_error,
void *userdata);
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
int xmpp_conn_release(xmpp_conn_t * const conn);
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);
int xmpp_conn_release(xmpp_conn_t *conn);
long xmpp_conn_get_flags(const xmpp_conn_t * const conn);
int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t * const conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t * const conn);
void xmpp_conn_set_jid(xmpp_conn_t * const conn, const char * const jid);
const char *xmpp_conn_get_pass(const xmpp_conn_t * const conn);
void xmpp_conn_set_pass(xmpp_conn_t * const conn, const char * const pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t * const conn);
void xmpp_conn_disable_tls(xmpp_conn_t * const conn);
int xmpp_conn_is_secured(xmpp_conn_t * const conn);
void xmpp_conn_set_keepalive(xmpp_conn_t * const conn, int timeout, int interval);
long xmpp_conn_get_flags(const xmpp_conn_t *conn);
int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn);
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
void xmpp_conn_disable_tls(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
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_connect_client(xmpp_conn_t * const conn,
const char * const altdomain,
int xmpp_connect_client(xmpp_conn_t *conn,
const char *altdomain,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata);
void *userdata);
int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
unsigned short port, xmpp_conn_handler callback,
void * const userdata);
int xmpp_connect_component(xmpp_conn_t *conn,
const char *server,
unsigned short port,
xmpp_conn_handler callback,
void *userdata);
int xmpp_connect_raw(xmpp_conn_t * const conn,
const char * const altdomain,
int xmpp_connect_raw(xmpp_conn_t *conn,
const char *altdomain,
unsigned short altport,
xmpp_conn_handler callback,
void * const userdata);
int xmpp_conn_open_stream_default(xmpp_conn_t * const conn);
int xmpp_conn_open_stream(xmpp_conn_t * const conn, char **attributes,
void *userdata);
int xmpp_conn_open_stream_default(xmpp_conn_t *conn);
int xmpp_conn_open_stream(xmpp_conn_t *conn,
char **attributes,
size_t attributes_len);
int xmpp_conn_tls_start(xmpp_conn_t * const conn);
int xmpp_conn_tls_start(xmpp_conn_t *conn);
void xmpp_disconnect(xmpp_conn_t * const conn);
void xmpp_disconnect(xmpp_conn_t *conn);
void xmpp_send(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza);
void xmpp_send_raw_string(xmpp_conn_t * const conn,
const char * const fmt, ...);
void xmpp_send_raw(xmpp_conn_t * const conn,
const char * const data, const size_t len);
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza);
void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...);
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len);
/* handlers */
/* if the handle returns false it is removed */
typedef int (*xmpp_timed_handler)(xmpp_conn_t * const conn,
void * const userdata);
/* if the handler returns false it is removed */
typedef int (*xmpp_timed_handler)(xmpp_conn_t *conn, void *userdata);
void xmpp_timed_handler_add(xmpp_conn_t * const conn,
void xmpp_timed_handler_add(xmpp_conn_t *conn,
xmpp_timed_handler handler,
const unsigned long period,
void * const userdata);
void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
xmpp_timed_handler handler);
unsigned long period,
void *userdata);
void xmpp_timed_handler_delete(xmpp_conn_t *conn, xmpp_timed_handler handler);
/* if the handler returns false it is removed */
typedef int (*xmpp_handler)(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
typedef int (*xmpp_global_timed_handler)(xmpp_ctx_t *ctx, void *userdata);
void xmpp_handler_add(xmpp_conn_t * const conn,
xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void xmpp_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler);
void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx,
xmpp_global_timed_handler handler,
unsigned long period,
void *userdata);
void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx,
xmpp_global_timed_handler handler);
void xmpp_id_handler_add(xmpp_conn_t * const conn,
/* if the handler returns false it is removed */
typedef int (*xmpp_handler)(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata);
void xmpp_handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id,
void * const userdata);
void xmpp_id_handler_delete(xmpp_conn_t * const conn,
const char *ns,
const char *name,
const char *type,
void *userdata);
void xmpp_handler_delete(xmpp_conn_t *conn, xmpp_handler handler);
void xmpp_id_handler_add(xmpp_conn_t *conn,
xmpp_handler handler,
const char * const id);
const char *id,
void *userdata);
void xmpp_id_handler_delete(xmpp_conn_t *conn,
xmpp_handler handler,
const char *id);
/*
void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
@@ -313,86 +329,97 @@ void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
/* allocate and initialize a blank stanza */
xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx);
xmpp_stanza_t *xmpp_stanza_new_from_string(xmpp_ctx_t *ctx, const char *str);
/* clone a stanza */
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_clone(xmpp_stanza_t *stanza);
/* copies a stanza and all children */
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t *stanza);
/* free a stanza object and it's contents */
int xmpp_stanza_release(xmpp_stanza_t * const stanza);
int xmpp_stanza_release(xmpp_stanza_t *stanza);
int xmpp_stanza_is_text(xmpp_stanza_t * const stanza);
int xmpp_stanza_is_tag(xmpp_stanza_t * const stanza);
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t *stanza);
int xmpp_stanza_is_text(xmpp_stanza_t *stanza);
int xmpp_stanza_is_tag(xmpp_stanza_t *stanza);
/* marshall a stanza into text for transmission or display */
int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
char ** const buf, size_t * const buflen);
int xmpp_stanza_to_text(xmpp_stanza_t *stanza, char **buf, size_t *buflen);
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
const char * const name);
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char * const ns);
xmpp_stanza_t *xmpp_stanza_get_next(xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_get_children(xmpp_stanza_t *stanza);
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t *stanza,
const char *name);
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t *stanza,
const char *ns);
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t *stanza,
const char *name,
const char *ns);
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,
xmpp_stanza_t *child,
int do_clone);
const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name);
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza);
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
const char **attr, int attrlen);
const char *xmpp_stanza_get_attribute(xmpp_stanza_t *stanza, const char *name);
int xmpp_stanza_get_attribute_count(xmpp_stanza_t *stanza);
int xmpp_stanza_get_attributes(xmpp_stanza_t *stanza,
const char **attr,
int attrlen);
/* concatenate all child text nodes. this function
* returns a string that must be freed by the caller */
char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza);
char *xmpp_stanza_get_text(xmpp_stanza_t *stanza);
const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t *stanza);
const char *xmpp_stanza_get_name(xmpp_stanza_t *stanza);
/* set_attribute adds/replaces attributes */
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const key,
const char * const value);
int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
const char * const name);
int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
const char * const text);
int xmpp_stanza_set_attribute(xmpp_stanza_t *stanza,
const char *key,
const char *value);
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *name);
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *text);
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char * const text,
const size_t size);
int xmpp_stanza_del_attribute(xmpp_stanza_t * const stanza,
const char * const name);
const char *text,
size_t size);
int xmpp_stanza_del_attribute(xmpp_stanza_t *stanza, const char *name);
/* common stanza helpers */
const char *xmpp_stanza_get_ns(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_type(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_id(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_to(xmpp_stanza_t * const stanza);
const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza);
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, const char * const ns);
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, const char * const id);
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, const char * const type);
int xmpp_stanza_set_to(xmpp_stanza_t * const stanza, const char * const to);
int xmpp_stanza_set_from(xmpp_stanza_t * const stanza, const char * const from);
const char *xmpp_stanza_get_ns(xmpp_stanza_t *stanza);
const char *xmpp_stanza_get_type(xmpp_stanza_t *stanza);
const char *xmpp_stanza_get_id(xmpp_stanza_t *stanza);
const char *xmpp_stanza_get_to(xmpp_stanza_t *stanza);
const char *xmpp_stanza_get_from(xmpp_stanza_t *stanza);
int xmpp_stanza_set_ns(xmpp_stanza_t *stanza, const char *ns);
int xmpp_stanza_set_id(xmpp_stanza_t *stanza, const char *id);
int xmpp_stanza_set_type(xmpp_stanza_t *stanza, const char *type);
int xmpp_stanza_set_to(xmpp_stanza_t *stanza, const char *to);
int xmpp_stanza_set_from(xmpp_stanza_t *stanza, const char *from);
/* allocate and initialize a stanza in reply to another */
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t * const stanza);
xmpp_stanza_t *xmpp_stanza_reply(xmpp_stanza_t *stanza);
xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *stanza,
const char *error_type,
const char *condition,
const char *text);
/* stanza subclasses */
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx, const char * const type,
const char * const to, const char * const id);
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
const char *type,
const char *to,
const char *id);
char *xmpp_message_get_body(xmpp_stanza_t *msg);
int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
int xmpp_message_set_body(xmpp_stanza_t *msg, const char *text);
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
const char * const id);
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char *type, const char *id);
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx);
xmpp_stanza_t *xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t const type,
const char * const text);
xmpp_stanza_t *
xmpp_error_new(xmpp_ctx_t *ctx, xmpp_error_type_t type, const char *text);
/* jid */
/* these return new strings that must be xmpp_free()'d */
char *xmpp_jid_new(xmpp_ctx_t *ctx, const char *node,
char *xmpp_jid_new(xmpp_ctx_t *ctx,
const char *node,
const char *domain,
const char *resource);
char *xmpp_jid_bare(xmpp_ctx_t *ctx, const char *jid);
@@ -402,10 +429,10 @@ char *xmpp_jid_resource(xmpp_ctx_t *ctx, const char *jid);
/* event loop */
void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout);
void xmpp_run_once(xmpp_ctx_t *ctx, unsigned long timeout);
void xmpp_run(xmpp_ctx_t *ctx);
void xmpp_stop(xmpp_ctx_t *ctx);
void xmpp_ctx_set_timeout(xmpp_ctx_t * const ctx, const unsigned long timeout);
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout);
/* UUID */
@@ -421,7 +448,8 @@ char *xmpp_uuid_gen(xmpp_ctx_t *ctx);
typedef struct _xmpp_sha1_t xmpp_sha1_t;
char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
void xmpp_sha1_digest(const unsigned char *data, size_t len,
void xmpp_sha1_digest(const unsigned char *data,
size_t len,
unsigned char *digest);
xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx);
@@ -434,10 +462,14 @@ void xmpp_sha1_to_digest(xmpp_sha1_t *sha1, unsigned char *digest);
/* Base64 */
char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
char *
xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len);
char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len);
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx, const char *base64, size_t len,
unsigned char **out, size_t *outlen);
void xmpp_base64_decode_bin(xmpp_ctx_t *ctx,
const char *base64,
size_t len,
unsigned char **out,
size_t *outlen);
#ifdef __cplusplus
}

View File

@@ -1,133 +0,0 @@
/* strophepp.h
** strophe XMPP client library C++ API
**
** 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.
*/
/** @file
* Strophe public C++ API definitions.
*/
#ifndef __LIBSTROPHE_STROPHEPP_H__
#define __LIBSTROPHE_STROPHEPP_H__
#include "strophe.h"
namespace XMPP {
class Context {
private:
xmpp_mem_t m_mem;
xmpp_log_t m_log;
xmpp_ctx_t *m_ctx;
public:
Context();
virtual ~Context();
virtual void *alloc(const size_t size);
virtual void *realloc(void *p, const size_t size);
virtual void free(void *p);
virtual void log(const xmpp_log_level_t level,
const char * const area,
const char * const msg);
xmpp_ctx_t *getContext();
private:
static void *callAlloc(const size_t size, void * const userdata);
static void *callRealloc(void *p, const size_t size,
void * const userdata);
static void callFree(void *p, void * const userdata);
static void callLog(void * const userdata,
const xmpp_log_level_t level,
const char * const area,
const char * const msg);
};
class Stanza {
private:
Context *m_ctx;
xmpp_stanza_t *m_stanza;
void *operator new(size_t size, Context *ctx);
void operator delete(void *p);
Stanza(Context *ctx);
virtual ~Stanza();
public:
static Stanza *create(Context *ctx);
void release();
Stanza *clone();
Stanza *copy();
int toText(const char ** const buf, size_t * const buflen);
Stanza *getChildren();
Stanza *getChildByName(const char * const name);
Stanza *getNext();
char *getAttribute(const char * const name);
char *getNamespace();
char *getText();
char *getName();
void addChild(Stanza *child);
void setNamespace(const char * const ns);
void setAttribute(const char * const key, const char * const value);
void setName(const char * const name);
void setText(const char * const text);
void setText(const char * const text, const size_t size);
char *getType();
char *getId();
char *getTo();
char *getFrom();
void setType(const char * const type);
void setId(const char * const id);
void setTo(const char * const to);
void setFrom(const char * const from);
};
class Connection {
private:
Context *m_ctx;
xmpp_conn_t *conn;
void *operator new(size_t size, Context *ctx);
Connection(Context *ctx);
public:
static Connection *create(Context *ctx);
virtual ~Connection();
Connection *clone();
void operator delete(void *p);
const char *getJID();
void setJID(const char * const jid);
const char *getPass();
void setPass(const char * const pass);
bool connectClient(const char * const domain,
xmpp_conn_handler callback,
void * const userdata);
void disconnect();
void send(Stanza *stanza);
void addTimedHandler(xmpp_timed_handler handler,
const unsigned long perdio,
void * const userdata);
void deleteTimedHandler(xmpp_timed_handler handler);
void addHandler(xmpp_handler handler,
const char * const ns,
const char * const name,
const char * const type,
void * const userdata);
void deleteHandler(xmpp_handler handler);
void addIdHandler(xmpp_handler handler,
const char * const id,
void * const userdata);
void deleteIdHandler(xmpp_handler handler);
};
}
#endif /* __LIBSTROPHE_STROPHEPP_H__ */

16
tests/cert.pem Normal file
View File

@@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICfjCCAjSgAwIBAgIIW5u5Vwn2Mv0wCgYIKoZIzj0EAwIwSzFJMEcGA1UEAwxA
dmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxlbmd0aC5pcy5hLnZhbGlk
LmFzY2lpLmNoYXJhY3RlcjAgFw0yMTAzMDExOTExMDBaGA8yMTIxMDMwMTE5MTEw
MFowSzFJMEcGA1UEAwxAdmVyeS5sb25nLnVzZXJuYW1lQHNvLnRoZS5hc24xLmxl
bmd0aC5pcy5hLnZhbGlkLmFzY2lpLmNoYXJhY3RlcjBJMBMGByqGSM49AgEGCCqG
SM49AwEBAzIABI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE
85RReISg+9/JDaOCAQ4wggEKMAkGA1UdEwQCMAAwHQYDVR0OBBYEFPjLGyHxqlOV
nXJQ9YBrnureO8LiMB8GA1UdIwQYMBaAFPjLGyHxqlOVnXJQ9YBrnureO8LiMAsG
A1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjCBmgYDVR0RBIGSMIGPoE4G
CCsGAQUFBwgFoEIMQHZlcnkubG9uZy51c2VybmFtZUBzby50aGUuYXNuMS5sZW5n
dGguaXMuYS52YWxpZC5hc2NpaS5jaGFyYWN0ZXKBDnlldEBub3RoZXIuc2Fugg53
d3cuc3Ryb3BoZS5pbaAdBggrBgEFBQcIBaARDA9zZWNvbmRAeG1wcC5qaWQwCgYI
KoZIzj0EAwIDOAAwNQIZAJmfqBhBMdaKCiWEuXu84K4+lznfzlRfmwIYCGRD1xk0
9cRa3V6PVwYWz6HcdRdMUBUj
-----END CERTIFICATE-----

View File

@@ -18,11 +18,12 @@
#include "test.h"
#define fail_unless(expr) do { \
#define fail_unless(expr) \
do { \
int result = (expr); \
if (!result) { \
printf("%s:%d: Assertion failed: %s\n", \
__FILE__, __LINE__, #expr); \
printf("%s:%d: Assertion failed: %s\n", __FILE__, __LINE__, \
#expr); \
exit(1); \
} \
} while (0)
@@ -42,6 +43,9 @@ static void create_destroy(void)
int cbtest_got_start = 0;
void cbtest_handle_start(char *name, char **attrs, void *userdata)
{
(void)attrs;
(void)userdata;
if (strcmp(name, "stream") == 0)
cbtest_got_start = 1;
}
@@ -49,6 +53,8 @@ void cbtest_handle_start(char *name, char **attrs, void *userdata)
int cbtest_got_end = 0;
void cbtest_handle_end(char *name, void *userdata)
{
(void)userdata;
if (strcmp(name, "stream") == 0)
cbtest_got_end = 1;
}
@@ -56,6 +62,8 @@ void cbtest_handle_end(char *name, void *userdata)
int cbtest_got_stanza = 0;
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
{
(void)userdata;
if (strcmp(xmpp_stanza_get_name(stanza), "message") == 0)
cbtest_got_stanza = 1;
}
@@ -67,9 +75,7 @@ static void callbacks(void)
int ret;
ctx = xmpp_ctx_new(NULL, NULL);
parser = parser_new(ctx,
cbtest_handle_start,
cbtest_handle_end,
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end,
cbtest_handle_stanza, NULL);
ret = parser_feed(parser, "<stream>", 8);

5
tests/key.pem Normal file
View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MF8CAQEEGF7SsbTSOjzb97nFc7Qbt4sic+1nZk+ETqAKBggqhkjOPQMBAaE0AzIA
BI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE85RReISg+9/J
DQ==
-----END EC PRIVATE KEY-----

View File

@@ -55,8 +55,8 @@ int main(int argc, char **argv)
}
domain = argv[1];
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s",
service, proto, domain);
snprintf(fulldomain, sizeof(fulldomain), "_%s._%s.%s", service, proto,
domain);
errno = 0;
len = res_query(fulldomain, C_IN, T_SRV, buf, sizeof(buf));

View File

@@ -16,9 +16,9 @@
static uint8_t char_to_bin(char c)
{
return c <= '9' ? (uint8_t)(c - '0') :
c <= 'Z' ? (uint8_t)(c - 'A' + 10) :
(uint8_t)(c - 'a' + 10);
return c <= '9' ? (uint8_t)(c - '0')
: c <= 'Z' ? (uint8_t)(c - 'A' + 10)
: (uint8_t)(c - 'a' + 10);
}
void test_hex_to_bin(const char *hex, uint8_t *bin, size_t *bin_len)

View File

@@ -18,7 +18,8 @@
#include "ostypes.h"
#define TEST_MAIN \
int main(int argc, char **argv) { \
int main(int argc, char **argv) \
{ \
int num_failed; \
Suite *s = parser_suite(); \
SRunner *sr = srunner_create(s); \
@@ -37,10 +38,10 @@ do { \
const char *__v1 = v1; \
const char *__v2 = v2; \
if (strcmp(__v1, __v2) != 0) { \
printf("%s differs!\n" \
"expected: %s\n" \
"got: %s\n", \
#v1, __v1, __v2); \
printf("Error: %s\n" \
"Expected: %s\n" \
"Got: %s\n", \
#v1 " != " #v2, __v1, __v2); \
exit(1); \
} \
} while (0)
@@ -51,14 +52,10 @@ do { \
const uint8_t *__v2 = (uint8_t *)(v2); \
size_t __len1 = len1; \
size_t __len2 = len2; \
if (__len1 != __len2 || \
memcmp(__v1, __v2, __len1) != 0) \
{ \
printf("%s differs!\n", #v1); \
printf("expected: 0x%s\n", \
test_bin_to_hex(__v1, __len1)); \
printf("got: 0x%s\n", \
test_bin_to_hex(__v2, __len2)); \
if (__len1 != __len2 || memcmp(__v1, __v2, __len1) != 0) { \
printf("Error: %s\n", #v1 " != " #v2); \
printf("Expected: 0x%s\n", test_bin_to_hex(__v1, __len1)); \
printf("Got: 0x%s\n", test_bin_to_hex(__v2, __len2)); \
exit(1); \
} \
} while (0)

View File

@@ -17,11 +17,11 @@
#include "test.h"
static const unsigned char test_2_raw[] =
{0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e, 0x00};
static const unsigned char test_4_raw[] =
{0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd, 0xf3, 0xd5,
0x41, 0xbc, 0x1b, 0xe9, 0xdf, 0xe9, 0xb3, 0x08, 0x00};
static const unsigned char test_2_raw[] = {0x14, 0xfb, 0x9c, 0x03,
0xd9, 0x7e, 0x00};
static const unsigned char test_4_raw[] = {0xd6, 0x2f, 0x27, 0x49, 0x7e, 0xdd,
0xf3, 0xd5, 0x41, 0xbc, 0x1b, 0xe9,
0xdf, 0xe9, 0xb3, 0x08, 0x00};
static const struct {
char *raw;
@@ -36,13 +36,11 @@ static const struct {
.base64 = "FPucA9l+",
},
{
.raw =
"From rest and sleep, which but thy pictures be, "
.raw = "From rest and sleep, which but thy pictures be, "
"Much pleasure; then from thee much more must flow, "
"And soonest our best men with thee do go, "
"Rest of their bones, and soul's delivery.",
.base64 =
"RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
.base64 = "RnJvbSByZXN0IGFuZCBzbGVlcCwgd2hpY2ggYnV0IHRoeSBwaWN0dXJl"
"cyBiZSwgTXVjaCBwbGVhc3VyZTsgdGhlbiBmcm9tIHRoZWUgbXVjaCBt"
"b3JlIG11c3QgZmxvdywgQW5kIHNvb25lc3Qgb3VyIGJlc3QgbWVuIHdp"
"dGggdGhlZSBkbyBnbywgUmVzdCBvZiB0aGVpciBib25lcywgYW5kIHNv"
@@ -53,11 +51,9 @@ static const struct {
.base64 = "1i8nSX7d89VBvBvp3+mzCA==",
},
{
.raw =
"realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
.raw = "realm=\"chesspark.com\",nonce=\"b243c0d663257a9149999cef2f83"
"a22116559e93\",qop=\"auth\",charset=utf-8,algorithm=md5-sess",
.base64 =
"cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
.base64 = "cmVhbG09ImNoZXNzcGFyay5jb20iLG5vbmNlPSJiMjQzYzBkNjYzMjU3"
"YTkxNDk5OTljZWYyZjgzYTIyMTE2NTU5ZTkzIixxb3A9ImF1dGgiLGNo"
"YXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz",
},
@@ -94,41 +90,30 @@ static const struct {
};
static const unsigned char bin_data[] = {
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
0x6d, 0x00,
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67, 0x6d, 0x61, 0x69, 0x6c,
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c,
0x74, 0x34, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x19, 0x00, 0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61,
0x6c, 0x74, 0x33, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
};
int main(int argc, char *argv[])
int main()
{
xmpp_ctx_t *ctx;
unsigned char *udec;

View File

@@ -1,5 +1,6 @@
/* test_ctx.c
** libstrophe XMPP client library -- test routines for the library run-time context
** libstrophe XMPP client library -- test routines for the library run-time
*context
**
** Copyright (C) 2005-2009 Collecta, Inc.
**
@@ -21,33 +22,41 @@ static int mem_alloc_called = 0;
static int mem_free_called = 0;
static int mem_realloc_called = 0;
void *my_alloc(const size_t size, void * const userdata)
void *my_alloc(size_t size, void *userdata)
{
(void)userdata;
mem_alloc_called++;
return malloc(size);
}
void my_free(void *p, void * const userdata)
void my_free(void *p, void *userdata)
{
(void)userdata;
mem_free_called++;
return free(p);
}
void *my_realloc(void *p, const size_t size, void * const userdata)
void *my_realloc(void *p, size_t size, void *userdata)
{
(void)userdata;
mem_realloc_called++;
return realloc(p, size);
}
void my_logger(void * const userdata, const xmpp_log_level_t level,
const char * const area, const char * const msg)
void my_logger(void *userdata,
xmpp_log_level_t level,
const char *area,
const char *msg)
{
if (strcmp((char *)userdata, "asdf") == 0 && level == XMPP_LEVEL_DEBUG
&& strcmp(area, "test") == 0 && strcmp(msg, "hello") == 0)
if (strcmp((char *)userdata, "asdf") == 0 && level == XMPP_LEVEL_DEBUG &&
strcmp(area, "test") == 0 && strcmp(msg, "hello") == 0)
log_called++;
}
int main(int argc, char **argv)
int main()
{
xmpp_ctx_t *ctx;
xmpp_mem_t mymem;
@@ -56,7 +65,8 @@ int main(int argc, char **argv)
void *testptr1, *testptr2;
ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) return 1;
if (ctx == NULL)
return 1;
/* destroy context */
xmpp_ctx_free(ctx);

View File

@@ -22,12 +22,8 @@
#define TESTSIZE 500
/* static test data */
const char *keys[] = {
"foo", "bar", "baz", "quux", "xyzzy"
};
const char *values[] = {
"wuzzle", "mug", "canonical", "rosebud", "lottery"
};
const char *keys[] = {"foo", "bar", "baz", "quux", "xyzzy"};
const char *values[] = {"wuzzle", "mug", "canonical", "rosebud", "lottery"};
const int nkeys = ARRAY_SIZE(keys);
int main(int argc, char **argv)
@@ -68,7 +64,8 @@ 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]));
if (err) return err;
if (err)
return err;
}
/* test key count */
@@ -80,11 +77,15 @@ 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]));
if (err) return err;
if (hash_num_keys(table) != nkeys) return 1;
if (err)
return err;
if (hash_num_keys(table) != nkeys)
return 1;
result = hash_get(table, keys[0]);
if (result == NULL) return 1;
if (strcmp(result, values[i]) != 0) return 1;
if (result == NULL)
return 1;
if (strcmp(result, values[i]) != 0)
return 1;
}
/* restore value for the 1st key */
hash_add(table, keys[0], xmpp_strdup(ctx, values[0]));
@@ -132,14 +133,19 @@ int main(int argc, char **argv)
/* test drops */
hash_drop(clone, keys[2]);
if (hash_get(clone, keys[2]) != NULL) return 1;
if (hash_get(clone, keys[2]) != NULL)
return 1;
hash_drop(clone, keys[1]);
hash_drop(clone, keys[4]);
if (hash_get(clone, keys[4]) != NULL) return 1;
if (hash_get(clone, keys[1]) != NULL) return 1;
if (hash_get(clone, keys[4]) != NULL)
return 1;
if (hash_get(clone, keys[1]) != NULL)
return 1;
/* keys 0,3 should still be available */
if (hash_get(clone, keys[0]) == NULL) return 1;
if (hash_get(clone, keys[3]) == NULL) return 1;
if (hash_get(clone, keys[0]) == NULL)
return 1;
if (hash_get(clone, keys[3]) == NULL)
return 1;
/* release our clone */
hash_release(clone);

View File

@@ -36,61 +36,93 @@ int test_jid(xmpp_ctx_t *ctx)
node = xmpp_jid_node(ctx, jid1);
domain = xmpp_jid_domain(ctx, jid1);
resource = xmpp_jid_resource(ctx, jid1);
printf("jid '%s' parsed to %s, %s, %s\n",
jid1, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "foo@bar.com")) return 1;
if (node == NULL || strcmp(node, "foo")) return 1;
if (domain == NULL || strcmp(domain, "bar.com")) return 1;
if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
printf("jid '%s' parsed to %s, %s, %s\n", jid1, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "foo@bar.com"))
return 1;
if (node == NULL || strcmp(node, "foo"))
return 1;
if (domain == NULL || strcmp(domain, "bar.com"))
return 1;
if (resource != NULL)
return 1;
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid2);
node = xmpp_jid_node(ctx, jid2);
domain = xmpp_jid_domain(ctx, jid2);
resource = xmpp_jid_resource(ctx, jid2);
printf("jid '%s' parsed to %s, %s, %s\n",
jid2, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "anyone@example.com")) return 1;
if (node == NULL || strcmp(node, "anyone")) return 1;
if (domain == NULL || strcmp(domain, "example.com")) return 1;
if (resource == NULL || strcmp(resource, "hullo")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
printf("jid '%s' parsed to %s, %s, %s\n", jid2, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "anyone@example.com"))
return 1;
if (node == NULL || strcmp(node, "anyone"))
return 1;
if (domain == NULL || strcmp(domain, "example.com"))
return 1;
if (resource == NULL || strcmp(resource, "hullo"))
return 1;
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid3);
node = xmpp_jid_node(ctx, jid3);
domain = xmpp_jid_domain(ctx, jid3);
resource = xmpp_jid_resource(ctx, jid3);
printf("jid '%s' parsed to %s, %s, %s\n",
jid3, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net")) return 1;
if (node == NULL || strcmp(node, "manic.porter")) return 1;
if (domain == NULL || strcmp(domain, "xyz.net")) return 1;
if (resource == NULL || strcmp(resource, "frob")) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
printf("jid '%s' parsed to %s, %s, %s\n", jid3, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "manic.porter@xyz.net"))
return 1;
if (node == NULL || strcmp(node, "manic.porter"))
return 1;
if (domain == NULL || strcmp(domain, "xyz.net"))
return 1;
if (resource == NULL || strcmp(resource, "frob"))
return 1;
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
bare = xmpp_jid_bare(ctx, jid4);
node = xmpp_jid_node(ctx, jid4);
domain = xmpp_jid_domain(ctx, jid4);
resource = xmpp_jid_resource(ctx, jid4);
printf("jid '%s' parsed to %s, %s, %s\n",
jid4, _s(node), _s(domain), _s(resource));
if (bare == NULL || strcmp(bare, "domain.tld")) return 1;
if (node != NULL) return 1;
if (domain == NULL || strcmp(domain, "domain.tld")) return 1;
if (resource != NULL) return 1;
if (bare) xmpp_free(ctx, bare);
if (node) xmpp_free(ctx, node);
if (domain) xmpp_free(ctx, domain);
if (resource) xmpp_free(ctx, resource);
printf("jid '%s' parsed to %s, %s, %s\n", jid4, _s(node), _s(domain),
_s(resource));
if (bare == NULL || strcmp(bare, "domain.tld"))
return 1;
if (node != NULL)
return 1;
if (domain == NULL || strcmp(domain, "domain.tld"))
return 1;
if (resource != NULL)
return 1;
if (bare)
xmpp_free(ctx, bare);
if (node)
xmpp_free(ctx, node);
if (domain)
xmpp_free(ctx, domain);
if (resource)
xmpp_free(ctx, resource);
return 0;
}
@@ -101,38 +133,46 @@ int test_jid_new(xmpp_ctx_t *ctx)
jid = xmpp_jid_new(ctx, "node", "domain", "resource");
printf("new jid: '%s'\n", jid);
if (strcmp(jid, "node@domain/resource")) return 1;
if (strcmp(jid, "node@domain/resource"))
return 1;
xmpp_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;
if (strcmp(jid, "foo@bar.com"))
return 1;
xmpp_free(ctx, jid);
return 0;
}
int main(int argc, char *argv[])
int main()
{
xmpp_ctx_t *ctx;
int ret;
printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) printf("failed to create context\n");
if (ctx == NULL) return -1;
if (ctx == NULL)
printf("failed to create context\n");
if (ctx == NULL)
return -1;
printf("ok.\n");
printf("testing jid routines...\n");
ret = test_jid(ctx);
if (ret) printf("testing jid routines... failed!\n");
if (ret) return ret;
if (ret)
printf("testing jid routines... failed!\n");
if (ret)
return ret;
printf("testing jid routines... ok.\n");
printf("testing jid new routines...\n");
ret = test_jid_new(ctx);
if (ret) printf("testing jid new routines... failed!\n");
if (ret) return ret;
if (ret)
printf("testing jid new routines... failed!\n");
if (ret)
return ret;
printf("testing jid new routines... ok.\n");
printf("freeing context... ");

View File

@@ -57,7 +57,7 @@ static const struct {
},
};
int main(int argc, char **argv)
int main()
{
struct MD5Context ctx;
unsigned char digest[16];

View File

@@ -21,14 +21,31 @@
#include "rand.c"
/* stubs to build test without whole libstrophe */
void *xmpp_alloc(const xmpp_ctx_t * const ctx, const size_t size) {
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
{
(void)ctx;
(void)size;
return NULL;
}
void xmpp_free(const xmpp_ctx_t * const ctx, void *p) { }
int xmpp_snprintf (char *str, size_t count, const char *fmt, ...) {
void xmpp_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, ...)
{
(void)str;
(void)count;
(void)fmt;
return 0;
}
uint64_t time_stamp(void) {
#endif /* HAVE_SNPRINTF */
uint64_t time_stamp(void)
{
return 0;
}
@@ -121,8 +138,8 @@ int main()
&entropy_input_len);
test_hex_to_bin(test_vectors[i].nonce, nonce, &nonce_len);
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len,
nonce, nonce_len);
Hash_DRBG_Instantiate(&ctx, entropy_input, entropy_input_len, nonce,
nonce_len);
COMPARE(test_vectors[i].V1, test_bin_to_hex(ctx.V, sizeof(ctx.V)));
COMPARE(test_vectors[i].C1, test_bin_to_hex(ctx.C, sizeof(ctx.C)));
assert(ctx.reseed_counter == 1);

View File

@@ -19,71 +19,51 @@
/* res_query("_xmpp-client._tcp.jabber.kiev.ua", C_IN, T_SRV, ...) */
static const unsigned char data1[] = {
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01,
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, 0x04, 0x6b, 0x69,
0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01,
0x00, 0x00, 0x00, 0x3b, 0x00, 0x16, 0x00, 0x01,
0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62,
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76,
0x02, 0x75, 0x61, 0x00,
0x95, 0xf3, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 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, 0x04, 0x6b, 0x69, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00, 0x00, 0x21,
0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b,
0x00, 0x16, 0x00, 0x01, 0x00, 0x00, 0x14, 0x66, 0x06, 0x6a, 0x61, 0x62,
0x62, 0x65, 0x72, 0x04, 0x6b, 0x69, 0x65, 0x76, 0x02, 0x75, 0x61, 0x00,
};
/* 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,
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,
};
/* res_query("_xmpp-client._tcp.gmail.com", C_IN, T_SRV, ...) */
static const unsigned char data3[] = {
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x5f, 0x78, 0x6d,
0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67,
0x6d, 0x61, 0x69, 0x6c, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00,
0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04,
0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0,
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14,
0x66, 0x04, 0x61, 0x6c, 0x74, 0x34, 0x04, 0x78,
0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32,
0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00,
0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x19, 0x00,
0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00,
0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x33, 0x04,
0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
0x6d, 0x00,
0xda, 0xa8, 0x81, 0x80, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x5f, 0x78, 0x6d, 0x70, 0x70, 0x2d, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x04, 0x5f, 0x74, 0x63, 0x70, 0x05, 0x67, 0x6d, 0x61, 0x69, 0x6c,
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x31, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61, 0x6c,
0x74, 0x34, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00,
0x21, 0x00, 0x01, 0x00, 0x00, 0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00,
0x00, 0x14, 0x66, 0x04, 0x61, 0x6c, 0x74, 0x32, 0x04, 0x78, 0x6d, 0x70,
0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x02,
0x43, 0x00, 0x19, 0x00, 0x05, 0x00, 0x00, 0x14, 0x66, 0x04, 0x78, 0x6d,
0x70, 0x70, 0x01, 0x6c, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
0x63, 0x6f, 0x6d, 0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
0x02, 0x43, 0x00, 0x1e, 0x00, 0x14, 0x00, 0x00, 0x14, 0x66, 0x04, 0x61,
0x6c, 0x74, 0x33, 0x04, 0x78, 0x6d, 0x70, 0x70, 0x01, 0x6c, 0x06, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
};
/* res_query("_xmpp-client._tcp.jabber.calyxinstitute.org", C_IN, T_SRV, ...) */
static const unsigned char data4[] = {
@@ -119,17 +99,14 @@ static const unsigned char data5[] = {
};
/* hacked data2 with two empty-string targets. */
static const unsigned char data6[] = {
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, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66,
0x00, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00,
0x00, 0x03, 0x83, 0x00, 0x08, 0x00, 0x1f, 0x00,
0x1e, 0x14, 0x66, 0xc0, 0x40,
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, 0x07, 0x00, 0x1e, 0x00, 0x1e, 0x14, 0x66, 0x00, 0xc0,
0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x08,
0x00, 0x1f, 0x00, 0x1e, 0x14, 0x66, 0xc0, 0x40,
};
static const struct {
@@ -187,12 +164,13 @@ static int srv_rr_list_len(resolver_srv_rr_t *list)
{
int nr;
for (nr = 0; list != NULL; ++nr, list = list->next);
for (nr = 0; list != NULL; ++nr, list = list->next)
;
return nr;
}
int main(int argc, char **argv)
int main()
{
xmpp_ctx_t *ctx;
xmpp_rand_t *rand;
@@ -223,8 +201,8 @@ int main(int argc, char **argv)
port = srv_rr_list->port;
COMPARE(tests[i].target, domain);
if (tests[i].port != port) {
printf("fail! got port=%u, but should be %u\n",
(unsigned)port, (unsigned)tests[i].port);
printf("fail! got port=%u, but should be %u\n", (unsigned)port,
(unsigned)tests[i].port);
return 1;
}
printf("ok\n");

View File

@@ -69,8 +69,8 @@ int test_digest_md5(xmpp_ctx_t *ctx)
{
char *result;
result = sasl_digest_md5(ctx, challenge_md5,
"somenode@somerealm", "secret");
result =
sasl_digest_md5(ctx, challenge_md5, "somenode@somerealm", "secret");
printf("response:\n%s\n", result);
if (strcmp(response_md5, result)) {
/* generated incorrect response to challenge */
@@ -80,27 +80,33 @@ int test_digest_md5(xmpp_ctx_t *ctx)
return 0;
}
int main(int argc, char *argv[])
int main()
{
xmpp_ctx_t *ctx;
int ret;
printf("allocating context... ");
ctx = xmpp_ctx_new(NULL, NULL);
if (ctx == NULL) printf("failed to create context\n");
if (ctx == NULL) return -1;
if (ctx == NULL)
printf("failed to create context\n");
if (ctx == NULL)
return -1;
printf("ok.\n");
printf("testing SASL PLAIN... ");
ret = test_plain(ctx);
if (ret) printf("failed!\n");
if (ret) return ret;
if (ret)
printf("failed!\n");
if (ret)
return ret;
printf("ok.\n");
printf("testing SASL DIGEST-MD5... ");
ret = test_digest_md5(ctx);
if (ret) printf("failed!\n");
if (ret) return ret;
if (ret)
printf("failed!\n");
if (ret)
return ret;
printf("ok.\n");
printf("freeing context... ");

View File

@@ -58,19 +58,19 @@ static const struct {
},
};
static void test_df(void)
static void test_df(const struct hash_alg *alg)
{
size_t i;
const char *s;
uint8_t dk[SHA1_DIGEST_SIZE];
uint8_t dk[SCRAM_DIGEST_SIZE];
printf("Derivation function tests (SCRAM_SHA1_Hi).\n");
printf("Derivation function SCRAM_Hi tests for %s.\n", alg->scram_name);
for (i = 0; i < ARRAY_SIZE(df_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
SCRAM_SHA1_Hi((uint8_t *)df_vectors[i].P, df_vectors[i].P_len,
SCRAM_Hi(alg, (uint8_t *)df_vectors[i].P, df_vectors[i].P_len,
(uint8_t *)df_vectors[i].S, df_vectors[i].S_len,
df_vectors[i].c, dk);
s = test_bin_to_hex(dk, sizeof(dk));
s = test_bin_to_hex(dk, alg->digest_size);
COMPARE(df_vectors[i].DK, s);
printf("ok\n");
}
@@ -101,42 +101,115 @@ static const struct {
},
};
static void test_scram(void)
static void test_scram(const struct hash_alg *alg)
{
uint8_t key[SHA1_DIGEST_SIZE];
uint8_t sign[SHA1_DIGEST_SIZE];
uint8_t key[SCRAM_DIGEST_SIZE];
uint8_t sign[SCRAM_DIGEST_SIZE];
uint8_t salt[256];
size_t salt_len;
char auth[512];
const char *s;
size_t i;
int j;
size_t j;
printf("SCRAM_SHA1_ClientKey and SCRAM_SHA1_ClientSignature tests.\n");
printf("SCRAM_ClientKey and SCRAM_ClientSignature tests for %s.\n",
alg->scram_name);
for (i = 0; i < ARRAY_SIZE(scram_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
snprintf(auth, sizeof(auth), "%s,%s,%s",
scram_vectors[i].initial + 3, scram_vectors[i].challenge,
scram_vectors[i].response);
snprintf(auth, sizeof(auth), "%s,%s,%s", scram_vectors[i].initial + 3,
scram_vectors[i].challenge, scram_vectors[i].response);
test_hex_to_bin(scram_vectors[i].salt, salt, &salt_len);
SCRAM_SHA1_ClientKey((uint8_t *)scram_vectors[i].password,
strlen(scram_vectors[i].password),
salt, salt_len, scram_vectors[i].i, key);
SCRAM_SHA1_ClientSignature(key, (uint8_t *)auth, strlen(auth), sign);
for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
SCRAM_ClientKey(alg, (uint8_t *)scram_vectors[i].password,
strlen(scram_vectors[i].password), salt, salt_len,
scram_vectors[i].i, key);
SCRAM_ClientSignature(alg, key, (uint8_t *)auth, strlen(auth), sign);
for (j = 0; j < alg->digest_size; j++) {
sign[j] ^= key[j];
}
s = test_bin_to_hex(sign, SHA1_DIGEST_SIZE);
s = test_bin_to_hex(sign, alg->digest_size);
COMPARE(scram_vectors[i].sign, s);
printf("ok\n");
}
}
int main(int argc, char **argv)
/*
* Test vectors for HMAC (RFC2202, RFC4231).
*/
static const uint8_t hmac_key1[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
static const uint8_t hmac_data1[] = {0x48, 0x69, 0x20, 0x54,
0x68, 0x65, 0x72, 0x65};
static const struct {
const uint8_t *key;
size_t key_len;
const uint8_t *data;
size_t data_len;
const uint8_t sha1[SHA1_DIGEST_SIZE];
const uint8_t sha256[SHA256_DIGEST_SIZE];
const uint8_t sha512[SHA512_DIGEST_SIZE];
} hmac_vectors[] = {
{
test_df();
test_scram();
.key = hmac_key1,
.key_len = sizeof(hmac_key1),
.data = hmac_data1,
.data_len = sizeof(hmac_data1),
.sha1 = {0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xe2, 0x8b,
0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, 0xf1, 0x46, 0xbe, 0x00},
.sha256 = {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7},
.sha512 = {0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0,
0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2,
0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1,
0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d,
0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20,
0x3a, 0x12, 0x68, 0x54},
},
};
static void test_hmac(const struct hash_alg *alg)
{
size_t i;
uint8_t digest[SCRAM_DIGEST_SIZE];
printf("HMAC tests for %s.\n", alg->scram_name);
for (i = 0; i < ARRAY_SIZE(hmac_vectors); ++i) {
printf("Test #%d: ", (int)i + 1);
memset(digest, 0, sizeof(digest));
crypto_HMAC(alg, hmac_vectors[i].key, hmac_vectors[i].key_len,
hmac_vectors[i].data, hmac_vectors[i].data_len, digest);
switch (alg->digest_size) {
case SHA1_DIGEST_SIZE:
COMPARE_BUF(hmac_vectors[i].sha1, alg->digest_size, digest,
alg->digest_size);
break;
case SHA256_DIGEST_SIZE:
COMPARE_BUF(hmac_vectors[i].sha256, alg->digest_size, digest,
alg->digest_size);
break;
case SHA512_DIGEST_SIZE:
COMPARE_BUF(hmac_vectors[i].sha512, alg->digest_size, digest,
alg->digest_size);
break;
default:
printf("Unknown digest size: %zu\n", alg->digest_size);
exit(1);
}
printf("ok\n");
}
}
int main()
{
test_df(&scram_sha1);
test_scram(&scram_sha1);
test_hmac(&scram_sha1);
test_hmac(&scram_sha256);
test_hmac(&scram_sha512);
return 0;
}

View File

@@ -12,13 +12,11 @@
/* Test Vectors (from FIPS PUB 180-1) */
static char *test_data[] = {
"abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"A million repetitions of 'a'",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
static char *test_results[] = {
"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
static char *test_results[] = {"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D",
"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1",
"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F",
"AD5B3FDB CB526778 C2839D2F 151EA753 995E26A0"};
@@ -39,9 +37,9 @@ static void digest_to_hex(const uint8_t *digest, char *output)
*(c - 1) = '\0';
}
int main(int argc, char** argv)
int main()
{
int k;
size_t k;
SHA1_CTX context;
uint8_t digest[20];
char output[80];

44
tests/test_sha256.c Normal file
View File

@@ -0,0 +1,44 @@
/* Tests for SHA-256 from LibTomCrypt */
/* This file is in the public domain */
/* gcc -o test_sha256 -I./src tests/test_sha256.c tests/test.c src/sha256.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sha256.h"
#include "test.h"
int main()
{
static const struct {
const char *msg;
unsigned char hash[SHA256_DIGEST_SIZE];
} tests[] = {
{"abc",
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}},
{"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}},
};
int i;
unsigned char tmp[SHA256_DIGEST_SIZE];
sha256_context md;
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
sha256_init(&md);
sha256_process(&md, (unsigned char *)tests[i].msg,
(unsigned long)strlen(tests[i].msg));
sha256_done(&md, tmp);
COMPARE_BUF(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash));
}
/* success */
fprintf(stdout, "ok\n");
return (0);
}

65
tests/test_sha512.c Normal file
View File

@@ -0,0 +1,65 @@
/* Tests for SHA-512 from LibTomCrypt */
/* This file is in the public domain */
/* gcc -o test_sha512 -I./src tests/test_sha512.c tests/test.c src/sha512.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sha512.h"
#include "test.h"
static const uint8_t hash_1m_a[SHA512_DIGEST_SIZE] = {
0xe7, 0x18, 0x48, 0x3d, 0x0c, 0xe7, 0x69, 0x64, 0x4e, 0x2e, 0x42,
0xc7, 0xbc, 0x15, 0xb4, 0x63, 0x8e, 0x1f, 0x98, 0xb1, 0x3b, 0x20,
0x44, 0x28, 0x56, 0x32, 0xa8, 0x03, 0xaf, 0xa9, 0x73, 0xeb, 0xde,
0x0f, 0xf2, 0x44, 0x87, 0x7e, 0xa6, 0x0a, 0x4c, 0xb0, 0x43, 0x2c,
0xe5, 0x77, 0xc3, 0x1b, 0xeb, 0x00, 0x9c, 0x5c, 0x2c, 0x49, 0xaa,
0x2e, 0x4e, 0xad, 0xb2, 0x17, 0xad, 0x8c, 0xc0, 0x9b};
int main()
{
static const struct {
const char *msg;
uint8_t hash[SHA512_DIGEST_SIZE];
} tests[] = {
{"abc",
{0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73,
0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9,
0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21,
0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23,
0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8,
0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}},
{"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklm"
"nopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
{0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, 0x8c, 0xf4, 0xf7,
0x28, 0x14, 0xfc, 0x14, 0x3f, 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f,
0x7f, 0xa1, 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, 0x50,
0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, 0x33, 0x1b, 0x99, 0xde,
0xc4, 0xb5, 0x43, 0x3a, 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26,
0x54, 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09}},
};
size_t i;
uint8_t tmp[SHA512_DIGEST_SIZE];
sha512_context md;
for (i = 0; i < ARRAY_SIZE(tests); i++) {
sha512_init(&md);
sha512_process(&md, (uint8_t *)tests[i].msg, strlen(tests[i].msg));
sha512_done(&md, tmp);
COMPARE_BUF(tests[i].hash, sizeof(tests[i].hash), tmp, sizeof(tmp));
}
/* special case: one million repetitions of the character 'a' */
sha512_init(&md);
for (i = 0; i < 1000000U; ++i)
sha512_process(&md, (uint8_t *)"a", 1);
sha512_done(&md, tmp);
COMPARE_BUF(hash_1m_a, sizeof(hash_1m_a), tmp, sizeof(tmp));
/* success */
fprintf(stdout, "ok\n");
return 0;
}

View File

@@ -20,38 +20,14 @@ int main (void)
{
char buf1[LONG_STRING];
char buf2[LONG_STRING];
char *fp_fmt[] = {
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%.1f",
NULL
};
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
"0x%x",
"0x%04x",
NULL
};
char *fp_fmt[] = {"%-1.5f", "%1.5f", "%123.9f", "%10.5f", "% 10.5f",
"%+22.9f", "%+4.9f", "%01.3f", "%4f", "%3.1f",
"%3.2f", "%.0f", "%.1f", NULL};
double fp_nums[] = {-1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96,
0.996, 0.9996, 1.996, 4.136, 0};
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
"%4d", "0x%x", "0x%04x", NULL};
long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0};
int x, y;
int fail = 0;
@@ -60,13 +36,12 @@ int main (void)
printf("Testing xmpp_snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] != NULL; x++)
for (y = 0; fp_nums[y] != 0 ; y++)
{
for (y = 0; fp_nums[y] != 0; y++) {
xmpp_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: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: "
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
fp_fmt[x], buf1, buf2);
fail++;
}
@@ -74,13 +49,12 @@ int main (void)
}
for (x = 0; int_fmt[x] != NULL; x++)
for (y = 0; int_nums[y] != 0 ; y++)
{
for (y = 0; int_nums[y] != 0; y++) {
xmpp_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: %s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: "
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
int_fmt[x], buf1, buf2);
fail++;
}

View File

@@ -23,19 +23,24 @@ int wait_for_connect(sock_t sock)
fd_set wfds, efds;
int ret;
FD_ZERO(&wfds); FD_SET(sock, &wfds);
FD_ZERO(&efds); FD_SET(sock, &efds);
FD_ZERO(&wfds);
FD_SET(sock, &wfds);
FD_ZERO(&efds);
FD_SET(sock, &efds);
ret = select(sock + 1, NULL, &wfds, &efds, NULL);
if (ret <= 0) return -1;
if (ret <= 0)
return -1;
if (FD_ISSET(sock, &efds)) return 0;
if (FD_ISSET(sock, &wfds)) return 1;
if (FD_ISSET(sock, &efds))
return 0;
if (FD_ISSET(sock, &wfds))
return 1;
return -1;
}
int main(int argc, char **argv)
int main()
{
sock_t sock;
int err;

131
tests/test_stanza.c Normal file
View File

@@ -0,0 +1,131 @@
/* test_stanza.c
* libstrophe XMPP client library -- test routines for stanza functions
*
* Copyright (C) 2020 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.
*/
/* gcc -o test_stanza -I./src tests/test_stanza.c -lstrophe */
#include <strophe.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define MAGICPTR ((void *)0xfeedbeef)
static unsigned long used_blocks = 0;
static void *stanza_alloc(size_t size, void *userdata)
{
assert(userdata == MAGICPTR);
++used_blocks;
return malloc(size);
}
static void stanza_free(void *ptr, void *userdata)
{
assert(userdata == MAGICPTR);
if (ptr != NULL) {
assert(used_blocks > 0);
--used_blocks;
}
free(ptr);
}
static void *stanza_realloc(void *ptr, size_t size, void *userdata)
{
assert(userdata == MAGICPTR);
if (ptr != NULL && size == 0) {
/* equivalent to free(ptr) */
assert(used_blocks > 0);
--used_blocks;
} else if (ptr == NULL) {
/* equivalent to malloc(size) */
++used_blocks;
}
return realloc(ptr, size);
}
static const xmpp_mem_t stanza_mem = {
.alloc = &stanza_alloc,
.free = &stanza_free,
.realloc = &stanza_realloc,
.userdata = MAGICPTR,
};
static void test_stanza_add_child(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
xmpp_stanza_t *child;
unsigned long baseline = used_blocks;
/* xmpp_stanza_add_child */
stanza = xmpp_stanza_new(ctx);
child = xmpp_stanza_new(ctx);
assert(stanza != NULL);
assert(child != NULL);
xmpp_stanza_add_child(stanza, child);
xmpp_stanza_release(stanza);
assert(used_blocks > baseline);
xmpp_stanza_release(child);
assert(used_blocks == baseline);
/* xmpp_stanza_add_child_ex */
stanza = xmpp_stanza_new(ctx);
child = xmpp_stanza_new(ctx);
assert(stanza != NULL);
assert(child != NULL);
xmpp_stanza_add_child_ex(stanza, child, 0);
xmpp_stanza_release(stanza);
assert(used_blocks == baseline);
}
static void test_stanza_from_string(xmpp_ctx_t *ctx)
{
xmpp_stanza_t *stanza;
char *buf;
size_t buflen;
int ret;
static 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 "
"xmlns=\"jabber:client\">Hello World!</body></payload></signcrypt>";
stanza = xmpp_stanza_new_from_string(ctx, str);
assert(stanza != NULL);
ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
assert(ret == XMPP_EOK);
assert(strcmp(buf, str) == 0);
xmpp_free(ctx, buf);
xmpp_stanza_release(stanza);
}
int main()
{
xmpp_ctx_t *ctx;
xmpp_initialize();
ctx = xmpp_ctx_new(&stanza_mem, NULL);
assert(ctx != NULL);
test_stanza_add_child(ctx);
test_stanza_from_string(ctx);
xmpp_ctx_free(ctx);
xmpp_shutdown();
/* All allocated blocks must be freed. */
assert(used_blocks == 0);
}

View File

@@ -75,8 +75,8 @@ static int test_strdup_one(xmpp_ctx_t *ctx, const char *s)
if (!s1 || !s2 || strcmp(s1, s2) != 0) {
rc = -1;
printf("strdup: '%s', xmpp_strdup: '%s'\n",
s1 ? s1 : "<NULL>", s2 ? s2 : "<NULL>");
printf("strdup: '%s', xmpp_strdup: '%s'\n", s1 ? s1 : "<NULL>",
s2 ? s2 : "<NULL>");
}
free(s1);

69
tests/test_xmppaddr.c Normal file
View File

@@ -0,0 +1,69 @@
/* test_xmppaddr.c
** libstrophe XMPP client library -- test routines for the xmppaddr
** certificate API's
**
** 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 "test.h"
int main()
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
char xmppaddr_num[] = "0";
unsigned int 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");
xmppaddr_num[0] = xmppaddr_num[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;
}
free(r);
}
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

14
travis/before_script.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
if [ "x$LIBRESSL" = "xyes" ]; then
cd "$HOME"
git clone https://github.com/libressl-portable/portable.git libressl-git
cd libressl-git
if [ -n "$LIBRESSL_COMMIT" ]; then
git checkout "$LIBRESSL_COMMIT"
fi
./autogen.sh
./configure --prefix="$HOME/libressl"
make -j"$(nproc)"
make install
fi