Compare commits
45 Commits
unify-erro
...
0.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c84ca3730 | ||
|
|
bf1348e89d | ||
|
|
795675d1aa | ||
|
|
12009a009d | ||
|
|
f23ac83c95 | ||
|
|
2dc20d13fb | ||
|
|
e26548375e | ||
|
|
e73cdb57f3 | ||
|
|
fcc4f8c680 | ||
|
|
a1de389e45 | ||
|
|
4ef5b2d449 | ||
|
|
ad9e9d5dbd | ||
|
|
4e53184eee | ||
|
|
f19ed572f0 | ||
|
|
f27d95fe43 | ||
|
|
2bf1988b3c | ||
|
|
05620ab506 | ||
|
|
0ea9c1d3a2 | ||
|
|
1f0a3f1ad1 | ||
|
|
2f491e0250 | ||
|
|
2509ed8424 | ||
|
|
f3e3e64a17 | ||
|
|
d7a28f97a6 | ||
|
|
2199d8d088 | ||
|
|
d1ce4b35ae | ||
|
|
e77cd53215 | ||
|
|
588aea4f54 | ||
|
|
ee5f9fb77b | ||
|
|
4790a61437 | ||
|
|
25d3a2d459 | ||
|
|
27be6acaeb | ||
|
|
9a0e070c24 | ||
|
|
e490011b68 | ||
|
|
3b4b664c28 | ||
|
|
18c95fa7bd | ||
|
|
cf2f7147d9 | ||
|
|
ecf6457cdb | ||
|
|
db8a511f68 | ||
|
|
2d5424bcff | ||
|
|
5792d52461 | ||
|
|
09229e2cd5 | ||
|
|
c07ac0a68d | ||
|
|
60ce94c267 | ||
|
|
99f2d4fe54 | ||
|
|
acced31192 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -61,6 +61,7 @@ tests/test_snprintf
|
||||
tests/test_sock
|
||||
tests/test_stanza
|
||||
tests/test_string
|
||||
tests/test_xmppaddr
|
||||
m4/
|
||||
libstrophe.project
|
||||
libs/
|
||||
|
||||
22
.travis.yml
22
.travis.yml
@@ -1,24 +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 dos2unix
|
||||
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libgnutls28-dev libc-ares-dev dos2unix
|
||||
stages:
|
||||
- style
|
||||
- test
|
||||
before_script:
|
||||
- ./bootstrap.sh
|
||||
env:
|
||||
- CONFIGURE_OPT="--without-libxml2"
|
||||
- CONFIGURE_OPT="--with-libxml2"
|
||||
- CONFIGURE_OPT="--with-gnutls"
|
||||
- CONFIGURE_OPT="--disable-tls"
|
||||
- CONFIGURE_OPT="--enable-cares"
|
||||
script: ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
|
||||
- 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 code style"
|
||||
script: ./configure && make format && git diff --exit-code
|
||||
env:
|
||||
- CONFIGURE_OPT=""
|
||||
matrix:
|
||||
fast_finish: true
|
||||
name: "Check coding style"
|
||||
env: CONFIGURE_OPT=""
|
||||
script: ./bootstrap.sh && ./configure && make format && git diff --exit-code
|
||||
allow_failures:
|
||||
- stage: style
|
||||
|
||||
28
ChangeLog
28
ChangeLog
@@ -1,3 +1,31 @@
|
||||
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
|
||||
- Support for manual certificate verification
|
||||
- New API:
|
||||
- xmpp_conn_set_client_cert()
|
||||
- xmpp_conn_cert_xmppaddr_num()
|
||||
- xmpp_conn_cert_xmppaddr()
|
||||
- xmpp_conn_set_cafile()
|
||||
- xmpp_conn_set_capath()
|
||||
- xmpp_conn_set_certfail_handler()
|
||||
- xmpp_conn_get_peer_cert()
|
||||
- xmpp_tlscert_get_ctx()
|
||||
- xmpp_tlscert_get_conn()
|
||||
- xmpp_tlscert_get_pem()
|
||||
- xmpp_tlscert_get_dnsname()
|
||||
- xmpp_tlscert_get_string()
|
||||
- xmpp_tlscert_get_description()
|
||||
- xmpp_tlscert_free()
|
||||
|
||||
0.10.1
|
||||
- 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
|
||||
|
||||
4
Doxyfile
4
Doxyfile
@@ -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.11
|
||||
|
||||
# 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
|
||||
|
||||
41
Makefile.am
41
Makefile.am
@@ -5,8 +5,13 @@ 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@
|
||||
@@ -43,6 +48,7 @@ libstrophe_la_SOURCES = \
|
||||
src/snprintf.c \
|
||||
src/sock.c \
|
||||
src/stanza.c \
|
||||
src/tls.c \
|
||||
src/util.c \
|
||||
src/uuid.c
|
||||
libstrophe_la_SOURCES += \
|
||||
@@ -67,8 +73,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
|
||||
@@ -88,14 +98,18 @@ EXTRA_DIST = \
|
||||
MIT-LICENSE.txt \
|
||||
bootstrap.sh \
|
||||
build-android.sh \
|
||||
docs/footer.html \
|
||||
examples/README.md \
|
||||
jni/Android.mk \
|
||||
jni/Application.mk \
|
||||
src/tls_gnutls.c \
|
||||
src/tls_schannel.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 \
|
||||
@@ -151,8 +165,22 @@ TESTS = \
|
||||
tests/test_stanza \
|
||||
tests/test_resolver
|
||||
|
||||
if !DISABLE_TLS
|
||||
TESTS += tests/test_xmppaddr
|
||||
endif
|
||||
|
||||
check_PROGRAMS = $(TESTS)
|
||||
|
||||
if FUZZ
|
||||
check_PROGRAMS += tests/test_fuzz
|
||||
|
||||
tests_test_fuzz_SOURCES = tests/test_fuzz.c
|
||||
tests_test_fuzz_CFLAGS = -fsanitize=fuzzer,address $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
|
||||
-I$(top_srcdir)/src
|
||||
tests_test_fuzz_LDADD = $(STROPHE_LIBS)
|
||||
tests_test_fuzz_LDFLAGS = -static
|
||||
endif
|
||||
|
||||
tests_check_parser_SOURCES = tests/check_parser.c tests/test.h
|
||||
tests_check_parser_CFLAGS = $(PARSER_CFLAGS) $(STROPHE_FLAGS) \
|
||||
-I$(top_srcdir)/src
|
||||
@@ -211,11 +239,16 @@ 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_SOURCES = tests/test_stanza.c tests/test.h
|
||||
tests_test_stanza_CFLAGS = $(STROPHE_FLAGS) -I$(top_srcdir)/src
|
||||
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
|
||||
|
||||
@@ -8,6 +8,7 @@ BinPackParameters: 'false'
|
||||
BreakBeforeBraces: Linux
|
||||
ColumnLimit: '80'
|
||||
DerivePointerAlignment: 'false'
|
||||
IndentGotoLabels: false
|
||||
IndentWidth: '4'
|
||||
PointerAlignment: Right
|
||||
SortIncludes: 'false'
|
||||
|
||||
28
configure.ac
28
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT([libstrophe], [0.10.0], [jack@metajack.im])
|
||||
AC_INIT([libstrophe], [0.11.0], [jack@metajack.im])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
LT_INIT([dlopen])
|
||||
@@ -26,16 +26,39 @@ AS_CASE([$PLATFORM],
|
||||
|
||||
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])])
|
||||
|
||||
AC_ARG_ENABLE([fuzzing],
|
||||
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
|
||||
[case "${enableval}" in yes) fuzzing=true ;; no) fuzzing=false ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-fuzzing]) ;; esac],[fuzzing=false])
|
||||
AM_CONDITIONAL([FUZZ], [test x$fuzzing = xtrue])
|
||||
|
||||
if test "x$enable_fuzzing" = "xyes" ; then
|
||||
if test "x$CC" != "xclang" ; then
|
||||
AC_MSG_ERROR(["You need to set CC=clang to use --enable-fuzzing, used $CC"])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SEARCH_LIBS([socket], [network socket])
|
||||
AC_CHECK_FUNCS([snprintf vsnprintf])
|
||||
AC_CHECK_DECLS([va_copy], [], [], [#include <stdarg.h>])
|
||||
|
||||
if test "x$enable_tls" != xno; then
|
||||
if test "x$enable_tls" != xno -a "x$with_gnutls" == xyes; then
|
||||
PKG_CHECK_MODULES([gnutls], [gnutls],
|
||||
[PC_REQUIRES="gnutls ${PC_REQUIRES}"],
|
||||
[AC_CHECK_HEADER([gnutls/gnutls.h],
|
||||
[
|
||||
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],
|
||||
@@ -145,6 +168,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}])
|
||||
|
||||
0
docs/.keep
Normal file
0
docs/.keep
Normal file
@@ -1,2 +0,0 @@
|
||||
</body>
|
||||
</html>
|
||||
@@ -19,9 +19,7 @@
|
||||
|
||||
#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;
|
||||
@@ -46,11 +44,11 @@ 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;
|
||||
|
||||
148
examples/basic.c
148
examples/basic.c
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <strophe.h>
|
||||
@@ -18,12 +19,26 @@
|
||||
#define KA_TIMEOUT 60
|
||||
#define KA_INTERVAL 1
|
||||
|
||||
static void print_tlscert(const xmpp_tlscert_t *cert)
|
||||
{
|
||||
const char *name;
|
||||
size_t n;
|
||||
for (n = 0; n < (unsigned)XMPP_CERT_ELEMENT_MAX; ++n) {
|
||||
printf("\t%32s: %s\n", xmpp_tlscert_get_description(n),
|
||||
xmpp_tlscert_get_string(cert, n));
|
||||
}
|
||||
n = 0;
|
||||
while ((name = xmpp_tlscert_get_dnsname(cert, n++)) != NULL)
|
||||
printf("\t%32s: %s\n", "dnsName", name);
|
||||
printf("PEM:\n%s\n", xmpp_tlscert_get_pem(cert));
|
||||
}
|
||||
|
||||
/* define a handler for connection events */
|
||||
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)
|
||||
{
|
||||
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
|
||||
int secured;
|
||||
@@ -36,6 +51,11 @@ void conn_handler(xmpp_conn_t *const conn,
|
||||
secured = xmpp_conn_is_secured(conn);
|
||||
fprintf(stderr, "DEBUG: connection is %s.\n",
|
||||
secured ? "secured" : "NOT secured");
|
||||
if (secured) {
|
||||
xmpp_tlscert_t *cert = xmpp_conn_get_peer_cert(conn);
|
||||
print_tlscert(cert);
|
||||
xmpp_tlscert_free(cert);
|
||||
}
|
||||
xmpp_disconnect(conn);
|
||||
} else {
|
||||
fprintf(stderr, "DEBUG: disconnected\n");
|
||||
@@ -43,19 +63,67 @@ void conn_handler(xmpp_conn_t *const conn,
|
||||
}
|
||||
}
|
||||
|
||||
static int certfail_handler(const xmpp_tlscert_t *cert,
|
||||
const char *const errormsg)
|
||||
{
|
||||
char read_char[16] = {0};
|
||||
printf("Received certificate can't be validated!\n");
|
||||
printf("Reason: %s\n", errormsg);
|
||||
print_tlscert(cert);
|
||||
printf("Do you agree to connect?\n[y(es)|n(o)]: ");
|
||||
fflush(stdout);
|
||||
if (fgets(read_char, sizeof(read_char), stdin) == NULL) {
|
||||
printf("fgets() failed\n");
|
||||
return 0;
|
||||
}
|
||||
printf("\n");
|
||||
return read_char[0] == 'y' || read_char[0] == 'Y';
|
||||
}
|
||||
|
||||
static void usage(int exit_code)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"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"
|
||||
" --capath <path> Path to an additional CA trust store "
|
||||
"(directory).\n"
|
||||
" --cafile <path> Path to an additional CA trust store "
|
||||
"(single file).\n"
|
||||
" --tls-key <key> Path to private key.\n\n"
|
||||
" --disable-tls Disable TLS.\n"
|
||||
" --mandatory-tls Deny plaintext connection.\n"
|
||||
" --trust-tls Trust TLS certificate.\n"
|
||||
" --enable-certfail Enable certfail handler.\n"
|
||||
" --legacy-ssl Use old style SSL.\n"
|
||||
" --legacy-auth Allow legacy authentication.\n"
|
||||
" --verbose Increase the verbosity level.\n"
|
||||
" --tcp-keepalive Configure TCP keepalive.\n\n"
|
||||
"Note: --disable-tls conflicts with --mandatory-tls or "
|
||||
"--legacy-ssl\n");
|
||||
|
||||
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,
|
||||
*capath = NULL, *cafile = NULL;
|
||||
long flags = 0;
|
||||
int tcp_keepalive = 0;
|
||||
int tcp_keepalive = 0, verbosity = 0, certfail = 0;
|
||||
int i;
|
||||
unsigned long port = 0;
|
||||
|
||||
/* take a jid and password on the command line */
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--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;
|
||||
@@ -65,29 +133,35 @@ int main(int argc, char **argv)
|
||||
flags |= XMPP_CONN_FLAG_LEGACY_SSL;
|
||||
else if (strcmp(argv[i], "--legacy-auth") == 0)
|
||||
flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
|
||||
else if (strcmp(argv[i], "--verbose") == 0)
|
||||
verbosity++;
|
||||
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
|
||||
tcp_keepalive = 1;
|
||||
else if (strcmp(argv[i], "--enable-certfail") == 0)
|
||||
certfail = 1;
|
||||
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
|
||||
jid = argv[i];
|
||||
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
|
||||
password = argv[i];
|
||||
else if ((strcmp(argv[i], "--tls-cert") == 0) && (++i < argc))
|
||||
cert = argv[i];
|
||||
else if ((strcmp(argv[i], "--tls-key") == 0) && (++i < argc))
|
||||
key = argv[i];
|
||||
else if ((strcmp(argv[i], "--capath") == 0) && (++i < argc))
|
||||
capath = argv[i];
|
||||
else if ((strcmp(argv[i], "--cafile") == 0) && (++i < argc))
|
||||
cafile = argv[i];
|
||||
else
|
||||
break;
|
||||
}
|
||||
if ((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"
|
||||
" --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");
|
||||
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
|
||||
@@ -101,6 +175,7 @@ int main(int argc, char **argv)
|
||||
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
|
||||
/* create a context */
|
||||
ctx = xmpp_ctx_new(NULL, log);
|
||||
xmpp_ctx_set_verbosity(ctx, verbosity);
|
||||
|
||||
/* create a connection */
|
||||
conn = xmpp_conn_new(ctx);
|
||||
@@ -112,15 +187,28 @@ int main(int argc, char **argv)
|
||||
xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
|
||||
|
||||
/* setup authentication information */
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
xmpp_conn_set_pass(conn, pass);
|
||||
if (cert && key) {
|
||||
xmpp_conn_set_client_cert(conn, cert, key);
|
||||
}
|
||||
if (jid)
|
||||
xmpp_conn_set_jid(conn, jid);
|
||||
if (password)
|
||||
xmpp_conn_set_pass(conn, password);
|
||||
|
||||
if (certfail)
|
||||
xmpp_conn_set_certfail_handler(conn, certfail_handler);
|
||||
if (capath)
|
||||
xmpp_conn_set_capath(conn, capath);
|
||||
if (cafile)
|
||||
xmpp_conn_set_cafile(conn, cafile);
|
||||
|
||||
/* initiate connection */
|
||||
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);
|
||||
/* enter the event loop -
|
||||
our connect handler will trigger an exit */
|
||||
xmpp_run(ctx);
|
||||
}
|
||||
|
||||
/* release our connection and context */
|
||||
xmpp_conn_release(conn);
|
||||
|
||||
@@ -22,9 +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;
|
||||
@@ -70,9 +68,7 @@ int version_handler(xmpp_conn_t *const conn,
|
||||
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;
|
||||
@@ -118,11 +114,11 @@ int message_handler(xmpp_conn_t *const conn,
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#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;
|
||||
|
||||
|
||||
@@ -102,9 +102,7 @@ iq_reg_send_form(xmpp_reg_t *reg, xmpp_conn_t *conn, xmpp_stanza_t *stanza)
|
||||
}
|
||||
}
|
||||
|
||||
static int iq_reg2_cb(xmpp_conn_t *const conn,
|
||||
xmpp_stanza_t *const stanza,
|
||||
void *const userdata)
|
||||
static int iq_reg2_cb(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
|
||||
{
|
||||
const char *type;
|
||||
|
||||
@@ -129,9 +127,7 @@ quit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iq_reg_cb(xmpp_conn_t *const conn,
|
||||
xmpp_stanza_t *const stanza,
|
||||
void *const userdata)
|
||||
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;
|
||||
@@ -166,9 +162,8 @@ quit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
(void)stanza;
|
||||
(void)userdata;
|
||||
@@ -179,9 +174,9 @@ static int _handle_error(xmpp_conn_t *const conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = xmpp_stanza_get_name(stanza);
|
||||
|
||||
@@ -201,8 +196,7 @@ static int _handle_proceedtls_default(xmpp_conn_t *const conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _handle_missing_features(xmpp_conn_t *const conn,
|
||||
void *const userdata)
|
||||
static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
|
||||
{
|
||||
(void)userdata;
|
||||
|
||||
@@ -212,9 +206,8 @@ 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_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||
xmpp_ctx_t *ctx = reg->ctx;
|
||||
@@ -265,11 +258,11 @@ static int _handle_features(xmpp_conn_t *const conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
xmpp_reg_t *reg = (xmpp_reg_t *)userdata;
|
||||
int secured;
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
|
||||
#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;
|
||||
@@ -51,11 +49,11 @@ 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;
|
||||
|
||||
@@ -160,7 +160,7 @@ 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;
|
||||
|
||||
@@ -170,9 +170,7 @@ static int timedout(xmpp_conn_t *const conn, void *const userdata)
|
||||
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;
|
||||
@@ -217,11 +215,11 @@ static void send_vcard_req(xmpp_conn_t *conn, const char *to, const char *id)
|
||||
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;
|
||||
|
||||
|
||||
223
src/auth.c
223
src/auth.c
@@ -60,51 +60,43 @@
|
||||
#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_challenge(xmpp_conn_t *const conn,
|
||||
xmpp_stanza_t *const stanza,
|
||||
void *const userdata);
|
||||
static char *_make_scram_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;
|
||||
@@ -199,8 +191,7 @@ 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);
|
||||
|
||||
@@ -212,9 +203,8 @@ 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;
|
||||
@@ -252,6 +242,9 @@ static int _handle_features(xmpp_conn_t *const conn,
|
||||
|
||||
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)
|
||||
@@ -279,7 +272,7 @@ 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;
|
||||
|
||||
@@ -293,9 +286,9 @@ static char *_get_authid(xmpp_conn_t *const conn)
|
||||
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;
|
||||
|
||||
@@ -319,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;
|
||||
|
||||
@@ -346,8 +338,7 @@ static int _handle_sasl_result(xmpp_conn_t *const conn,
|
||||
} else {
|
||||
/* got unexpected reply */
|
||||
xmpp_error(conn->ctx, "xmpp",
|
||||
"Got unexpected reply to SASL %s"
|
||||
"authentication.",
|
||||
"Got unexpected reply to SASL %s authentication.",
|
||||
(char *)userdata);
|
||||
xmpp_disconnect(conn);
|
||||
}
|
||||
@@ -356,9 +347,9 @@ 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;
|
||||
@@ -415,9 +406,9 @@ 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;
|
||||
@@ -452,9 +443,9 @@ struct scram_user_data {
|
||||
};
|
||||
|
||||
/* handle the challenge phase of SCRAM-SHA-1 auth */
|
||||
static int _handle_scram_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;
|
||||
@@ -533,7 +524,7 @@ err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_make_scram_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;
|
||||
@@ -556,7 +547,7 @@ static char *_make_scram_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;
|
||||
|
||||
@@ -570,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;
|
||||
|
||||
@@ -591,7 +581,7 @@ 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;
|
||||
@@ -664,10 +654,57 @@ static void _auth(xmpp_conn_t *const conn)
|
||||
|
||||
/* 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->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)
|
||||
@@ -793,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);
|
||||
@@ -809,7 +846,7 @@ void auth_handle_open(xmpp_conn_t *const conn)
|
||||
}
|
||||
|
||||
/* 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,
|
||||
@@ -818,7 +855,7 @@ static void _handle_open_tls(xmpp_conn_t *const conn)
|
||||
}
|
||||
|
||||
/* 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.");
|
||||
|
||||
@@ -829,9 +866,8 @@ static void _handle_open_sasl(xmpp_conn_t *const conn)
|
||||
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;
|
||||
@@ -936,8 +972,7 @@ 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)
|
||||
{
|
||||
UNUSED(userdata);
|
||||
|
||||
@@ -948,9 +983,8 @@ static int _handle_missing_features_sasl(xmpp_conn_t *const 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;
|
||||
@@ -1022,7 +1056,7 @@ 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);
|
||||
|
||||
@@ -1031,9 +1065,8 @@ static int _handle_missing_bind(xmpp_conn_t *const conn, void *const userdata)
|
||||
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;
|
||||
|
||||
@@ -1062,8 +1095,7 @@ 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);
|
||||
|
||||
@@ -1072,7 +1104,7 @@ static int _handle_missing_session(xmpp_conn_t *const 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)
|
||||
{
|
||||
UNUSED(userdata);
|
||||
|
||||
@@ -1083,9 +1115,8 @@ static int _handle_missing_legacy(xmpp_conn_t *const conn, void *const userdata)
|
||||
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;
|
||||
@@ -1216,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;
|
||||
|
||||
@@ -1236,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;
|
||||
@@ -1286,9 +1317,9 @@ 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;
|
||||
|
||||
@@ -1318,7 +1349,7 @@ 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);
|
||||
|
||||
@@ -1327,7 +1358,7 @@ int _handle_missing_handshake(xmpp_conn_t *const conn, void *const userdata)
|
||||
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. */
|
||||
@@ -1335,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.");
|
||||
}
|
||||
|
||||
94
src/common.h
94
src/common.h
@@ -77,6 +77,7 @@ typedef struct _xmpp_connlist_t {
|
||||
struct _xmpp_ctx_t {
|
||||
const xmpp_mem_t *mem;
|
||||
const xmpp_log_t *log;
|
||||
int verbosity;
|
||||
|
||||
xmpp_rand_t *rand;
|
||||
xmpp_loop_status_t loop_status;
|
||||
@@ -87,33 +88,24 @@ struct _xmpp_ctx_t {
|
||||
};
|
||||
|
||||
/* 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_alloc(const xmpp_ctx_t *ctx, size_t size);
|
||||
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size);
|
||||
char *xmpp_strdup(const xmpp_ctx_t *ctx, const char *s);
|
||||
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len);
|
||||
|
||||
void xmpp_log(const xmpp_ctx_t *const ctx,
|
||||
void xmpp_log(const xmpp_ctx_t *ctx,
|
||||
const xmpp_log_level_t level,
|
||||
const char *const area,
|
||||
const char *const fmt,
|
||||
const char *area,
|
||||
const char *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,
|
||||
...);
|
||||
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
|
||||
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
|
||||
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
|
||||
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
|
||||
void xmpp_debug_verbose(
|
||||
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...);
|
||||
|
||||
/** connection **/
|
||||
|
||||
@@ -143,6 +135,7 @@ struct _xmpp_send_queue_t {
|
||||
#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)
|
||||
@@ -153,7 +146,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;
|
||||
@@ -176,11 +169,16 @@ struct _xmpp_conn_t {
|
||||
int tls_mandatory;
|
||||
int tls_legacy_ssl;
|
||||
int tls_trust;
|
||||
char *tls_cafile;
|
||||
char *tls_capath;
|
||||
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 */
|
||||
int auth_legacy_enabled;
|
||||
int secured; /* set when stream is secured with TLS */
|
||||
xmpp_certfail_handler certfail_handler;
|
||||
|
||||
/* if server returns <bind/> or <session/> we must do them */
|
||||
int bind_required;
|
||||
@@ -225,13 +223,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,
|
||||
@@ -256,32 +254,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__ */
|
||||
|
||||
441
src/conn.c
441
src/conn.c
@@ -48,10 +48,13 @@
|
||||
#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,
|
||||
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 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,
|
||||
@@ -59,24 +62,22 @@ static void _conn_attributes_new(xmpp_conn_t *conn,
|
||||
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 *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 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);
|
||||
static int _send_raw(xmpp_conn_t *conn, char *data, size_t len);
|
||||
|
||||
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);
|
||||
|
||||
@@ -93,7 +94,7 @@ void xmpp_send_error(xmpp_conn_t *const conn,
|
||||
*
|
||||
* @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;
|
||||
@@ -143,9 +144,14 @@ 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_cafile = NULL;
|
||||
conn->tls_capath = NULL;
|
||||
conn->tls_client_cert = NULL;
|
||||
conn->tls_client_key = NULL;
|
||||
conn->sasl_support = 0;
|
||||
conn->auth_legacy_enabled = 0;
|
||||
conn->secured = 0;
|
||||
conn->certfail_handler = NULL;
|
||||
|
||||
conn->bind_required = 0;
|
||||
conn->session_required = 0;
|
||||
@@ -201,7 +207,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;
|
||||
@@ -219,7 +225,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;
|
||||
|
||||
@@ -245,7 +251,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;
|
||||
@@ -338,6 +344,14 @@ int xmpp_conn_release(xmpp_conn_t *const conn)
|
||||
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);
|
||||
if (conn->tls_cafile)
|
||||
xmpp_free(ctx, conn->tls_cafile);
|
||||
if (conn->tls_capath)
|
||||
xmpp_free(ctx, conn->tls_capath);
|
||||
xmpp_free(ctx, conn);
|
||||
released = 1;
|
||||
}
|
||||
@@ -353,7 +367,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;
|
||||
}
|
||||
@@ -371,7 +385,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;
|
||||
}
|
||||
@@ -387,13 +401,126 @@ 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);
|
||||
conn->jid = xmpp_strdup(conn->ctx, jid);
|
||||
}
|
||||
|
||||
/** Set the Handler function which will be called when the TLS stack can't
|
||||
* verify the CA of the server we're trying to connect to.
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @param hndl certfail Handler function
|
||||
*
|
||||
* @ingroup Connections
|
||||
* @ingroup TLS
|
||||
*/
|
||||
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
|
||||
xmpp_certfail_handler hndl)
|
||||
{
|
||||
conn->certfail_handler = hndl;
|
||||
}
|
||||
|
||||
/** Set the CAfile
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @param cert path to a certificate file
|
||||
*
|
||||
* @ingroup Connections
|
||||
* @ingroup TLS
|
||||
*/
|
||||
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
|
||||
{
|
||||
conn->tls_cafile = xmpp_strdup(conn->ctx, path);
|
||||
}
|
||||
|
||||
/** Set the CApath
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
* @param cert path to a folder containing certificates
|
||||
*
|
||||
* @ingroup Connections
|
||||
* @ingroup TLS
|
||||
*/
|
||||
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
|
||||
{
|
||||
conn->tls_capath = xmpp_strdup(conn->ctx, path);
|
||||
}
|
||||
|
||||
/** Retrieve the peer certificate
|
||||
*
|
||||
* The returned Certificate object must be free'd by calling
|
||||
* \ref xmpp_tlscert_free
|
||||
*
|
||||
* @param conn a Strophe connection object
|
||||
*
|
||||
* @return a Strophe Certificate object
|
||||
*
|
||||
* @ingroup Connections
|
||||
* @ingroup TLS
|
||||
*/
|
||||
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
|
||||
{
|
||||
return tls_peer_cert(conn);
|
||||
}
|
||||
|
||||
/** 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
|
||||
* @ingroup TLS
|
||||
*/
|
||||
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
|
||||
* @ingroup TLS
|
||||
*/
|
||||
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
|
||||
* @ingroup TLS
|
||||
*/
|
||||
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
|
||||
@@ -402,7 +529,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;
|
||||
}
|
||||
@@ -416,11 +543,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);
|
||||
conn->pass = pass ? xmpp_strdup(conn->ctx, pass) : NULL;
|
||||
}
|
||||
|
||||
/** Get the strophe context that the connection is associated with.
|
||||
@@ -430,7 +557,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;
|
||||
}
|
||||
@@ -456,11 +583,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;
|
||||
@@ -470,6 +597,25 @@ 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;
|
||||
@@ -536,11 +682,11 @@ int xmpp_connect_client(xmpp_conn_t *const conn,
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_connect_component(xmpp_conn_t *const conn,
|
||||
const char *const server,
|
||||
int xmpp_connect_component(xmpp_conn_t *conn,
|
||||
const char *server,
|
||||
unsigned short port,
|
||||
xmpp_conn_handler callback,
|
||||
void *const userdata)
|
||||
void *userdata)
|
||||
{
|
||||
/* The server domain, jid and password MUST be specified. */
|
||||
if (!(server && conn->jid && conn->pass))
|
||||
@@ -583,18 +729,18 @@ int xmpp_connect_component(xmpp_conn_t *const conn,
|
||||
*
|
||||
* @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");
|
||||
@@ -628,7 +774,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;
|
||||
@@ -655,24 +801,16 @@ int xmpp_conn_open_stream_default(xmpp_conn_t *const conn)
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_open_stream(xmpp_conn_t *const conn,
|
||||
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.
|
||||
@@ -681,7 +819,7 @@ int xmpp_conn_open_stream(xmpp_conn_t *const conn,
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
@@ -692,7 +830,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);
|
||||
@@ -706,7 +844,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;
|
||||
@@ -724,14 +862,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);
|
||||
@@ -746,7 +884,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)
|
||||
@@ -772,13 +910,16 @@ 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;
|
||||
char buf[1024]; /* small buffer for common case */
|
||||
char *bigbuf;
|
||||
|
||||
if (conn->state != XMPP_STATE_CONNECTED)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = xmpp_vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
@@ -797,14 +938,10 @@ void xmpp_send_raw_string(xmpp_conn_t *const conn, const char *const fmt, ...)
|
||||
xmpp_vsnprintf(bigbuf, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", bigbuf);
|
||||
|
||||
/* len - 1 so we don't send trailing \0 */
|
||||
xmpp_send_raw(conn, bigbuf, len - 1);
|
||||
|
||||
xmpp_free(conn->ctx, bigbuf);
|
||||
_send_raw(conn, bigbuf, len - 1);
|
||||
} else {
|
||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
||||
/* go through xmpp_send_raw() which does the strdup() for us */
|
||||
xmpp_send_raw(conn, buf, len);
|
||||
}
|
||||
}
|
||||
@@ -821,41 +958,20 @@ void xmpp_send_raw_string(xmpp_conn_t *const conn, const char *const fmt, ...)
|
||||
*
|
||||
* @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;
|
||||
char *d;
|
||||
|
||||
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;
|
||||
|
||||
item->data = xmpp_alloc(conn->ctx, len);
|
||||
if (!item->data) {
|
||||
xmpp_free(conn->ctx, item);
|
||||
d = xmpp_strndup(conn->ctx, data, len);
|
||||
if (!d) {
|
||||
xmpp_error(conn->ctx, "conn", "Failed to strndup");
|
||||
return;
|
||||
}
|
||||
memcpy(item->data, data, len);
|
||||
item->len = len;
|
||||
item->next = NULL;
|
||||
item->written = 0;
|
||||
|
||||
/* add item to the send queue */
|
||||
if (!conn->send_queue_tail) {
|
||||
/* first item, set head and tail */
|
||||
conn->send_queue_head = item;
|
||||
conn->send_queue_tail = item;
|
||||
} else {
|
||||
/* add to the tail */
|
||||
conn->send_queue_tail->next = item;
|
||||
conn->send_queue_tail = item;
|
||||
}
|
||||
conn->send_queue_len++;
|
||||
_send_raw(conn, d, len);
|
||||
}
|
||||
|
||||
/** Send an XML stanza to the XMPP server.
|
||||
@@ -867,18 +983,20 @@ 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;
|
||||
char *buf = NULL;
|
||||
size_t len;
|
||||
|
||||
if (conn->state == XMPP_STATE_CONNECTED) {
|
||||
if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) {
|
||||
xmpp_send_raw(conn, buf, len);
|
||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
|
||||
xmpp_free(conn->ctx, buf);
|
||||
}
|
||||
if (conn->state != XMPP_STATE_CONNECTED)
|
||||
return;
|
||||
|
||||
if (xmpp_stanza_to_text(stanza, &buf, &len) != 0) {
|
||||
xmpp_error(conn->ctx, "conn", "Failed to stanza_to_text");
|
||||
return;
|
||||
}
|
||||
|
||||
_send_raw(conn, buf, len);
|
||||
}
|
||||
|
||||
/** Send the opening <stream:stream> tag to the server.
|
||||
@@ -887,22 +1005,36 @@ void xmpp_send(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza)
|
||||
*
|
||||
* @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;
|
||||
|
||||
@@ -942,7 +1074,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;
|
||||
|
||||
@@ -951,7 +1083,6 @@ long xmpp_conn_get_flags(const xmpp_conn_t *const conn)
|
||||
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;
|
||||
;
|
||||
|
||||
return flags;
|
||||
}
|
||||
@@ -978,7 +1109,7 @@ 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",
|
||||
@@ -1013,7 +1144,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);
|
||||
|
||||
@@ -1027,7 +1158,7 @@ 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;
|
||||
}
|
||||
@@ -1037,7 +1168,7 @@ int xmpp_conn_is_secured(xmpp_conn_t *const conn)
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_is_connecting(xmpp_conn_t *const conn)
|
||||
int xmpp_conn_is_connecting(xmpp_conn_t *conn)
|
||||
{
|
||||
return conn->state == XMPP_STATE_CONNECTING;
|
||||
}
|
||||
@@ -1047,7 +1178,7 @@ int xmpp_conn_is_connecting(xmpp_conn_t *const conn)
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_is_connected(xmpp_conn_t *const conn)
|
||||
int xmpp_conn_is_connected(xmpp_conn_t *conn)
|
||||
{
|
||||
return conn->state == XMPP_STATE_CONNECTED;
|
||||
}
|
||||
@@ -1057,13 +1188,13 @@ int xmpp_conn_is_connected(xmpp_conn_t *const conn)
|
||||
*
|
||||
* @ingroup Connections
|
||||
*/
|
||||
int xmpp_conn_is_disconnected(xmpp_conn_t *const conn)
|
||||
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)
|
||||
{
|
||||
UNUSED(userdata);
|
||||
|
||||
@@ -1074,7 +1205,7 @@ static int _disconnect_cleanup(xmpp_conn_t *const conn, void *const userdata)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *_conn_build_stream_tag(xmpp_conn_t *const conn,
|
||||
static char *_conn_build_stream_tag(xmpp_conn_t *conn,
|
||||
char **attributes,
|
||||
size_t attributes_len)
|
||||
{
|
||||
@@ -1119,6 +1250,22 @@ static char *_conn_build_stream_tag(xmpp_conn_t *const conn,
|
||||
return tag;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -1191,7 +1338,7 @@ 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;
|
||||
@@ -1227,7 +1374,7 @@ 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_end(char *name, void *userdata)
|
||||
{
|
||||
xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
|
||||
|
||||
@@ -1238,7 +1385,7 @@ static void _handle_stream_end(char *name, void *const userdata)
|
||||
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;
|
||||
@@ -1252,7 +1399,7 @@ static void _handle_stream_stanza(xmpp_stanza_t *stanza, void *const userdata)
|
||||
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) {
|
||||
@@ -1266,7 +1413,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;
|
||||
@@ -1317,13 +1464,13 @@ 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;
|
||||
|
||||
@@ -1353,10 +1500,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
|
||||
@@ -1370,3 +1516,36 @@ static int _conn_connect(xmpp_conn_t *const conn,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _send_raw(xmpp_conn_t *conn, char *data, size_t len)
|
||||
{
|
||||
xmpp_send_queue_t *item;
|
||||
|
||||
/* create send queue item for queue */
|
||||
item = xmpp_alloc(conn->ctx, sizeof(xmpp_send_queue_t));
|
||||
if (!item) {
|
||||
xmpp_error(conn->ctx, "conn", "DROPPED: %s", data);
|
||||
xmpp_free(conn->ctx, data);
|
||||
return XMPP_EMEM;
|
||||
}
|
||||
|
||||
item->data = data;
|
||||
item->len = len;
|
||||
item->next = NULL;
|
||||
item->written = 0;
|
||||
|
||||
/* add item to the send queue */
|
||||
if (!conn->send_queue_tail) {
|
||||
/* first item, set head and tail */
|
||||
conn->send_queue_head = item;
|
||||
conn->send_queue_tail = item;
|
||||
} else {
|
||||
/* add to the tail */
|
||||
conn->send_queue_tail->next = item;
|
||||
conn->send_queue_tail = item;
|
||||
}
|
||||
conn->send_queue_len++;
|
||||
xmpp_debug_verbose(2, conn->ctx, "conn", "QUEUED: %s", data);
|
||||
xmpp_debug_verbose(1, conn->ctx, "conn", "Added queue element: %p", item);
|
||||
return XMPP_EOK;
|
||||
}
|
||||
|
||||
13
src/crypto.c
13
src/crypto.c
@@ -244,15 +244,14 @@ static const char _base64_charmap[65] = {
|
||||
'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;
|
||||
@@ -304,7 +303,7 @@ 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;
|
||||
@@ -331,8 +330,8 @@ static size_t base64_decoded_len(const char *const buffer, const size_t len)
|
||||
}
|
||||
|
||||
static void base64_decode(xmpp_ctx_t *ctx,
|
||||
const char *const buffer,
|
||||
const size_t len,
|
||||
const char *buffer,
|
||||
size_t len,
|
||||
unsigned char **out,
|
||||
size_t *outlen)
|
||||
{
|
||||
|
||||
104
src/ctx.c
104
src/ctx.c
@@ -122,19 +122,19 @@ 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);
|
||||
@@ -146,8 +146,7 @@ static xmpp_mem_t xmpp_default_mem = {
|
||||
_free, _realloc, NULL};
|
||||
|
||||
/* log levels and names */
|
||||
static const char *const _xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN",
|
||||
"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};
|
||||
|
||||
@@ -160,10 +159,10 @@ static const xmpp_log_level_t _xmpp_default_logger_levels[] = {
|
||||
* @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)
|
||||
@@ -212,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);
|
||||
}
|
||||
@@ -223,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);
|
||||
}
|
||||
@@ -237,7 +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);
|
||||
}
|
||||
@@ -255,10 +254,10 @@ void *xmpp_realloc(const xmpp_ctx_t *const ctx, void *p, const size_t size)
|
||||
* @param fmt a printf-style format string for the message
|
||||
* @param ap variable argument list supplied for the format string
|
||||
*/
|
||||
void xmpp_log(const xmpp_ctx_t *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;
|
||||
@@ -266,6 +265,13 @@ void xmpp_log(const xmpp_ctx_t *const ctx,
|
||||
char *buf;
|
||||
va_list copy;
|
||||
|
||||
if (!ctx->log->handler)
|
||||
return;
|
||||
|
||||
if (ctx->log->handler == xmpp_default_logger &&
|
||||
level < *(xmpp_log_level_t *)ctx->log->userdata)
|
||||
return;
|
||||
|
||||
va_copy(copy, ap);
|
||||
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
|
||||
if (ret >= (int)sizeof(smbuf)) {
|
||||
@@ -289,8 +295,7 @@ void xmpp_log(const xmpp_ctx_t *const ctx,
|
||||
}
|
||||
va_end(copy);
|
||||
|
||||
if (ctx->log->handler)
|
||||
ctx->log->handler(ctx->log->userdata, level, area, buf);
|
||||
ctx->log->handler(ctx->log->userdata, level, area, buf);
|
||||
|
||||
if (buf != smbuf)
|
||||
xmpp_free(ctx, buf);
|
||||
@@ -306,10 +311,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;
|
||||
|
||||
@@ -328,10 +330,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;
|
||||
|
||||
@@ -350,10 +349,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;
|
||||
|
||||
@@ -372,10 +368,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;
|
||||
|
||||
@@ -384,6 +377,30 @@ void xmpp_debug(const xmpp_ctx_t *const ctx,
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/** Write to the log at the DEBUG level if verbosity is enabled.
|
||||
* This is a convenience function for writing to the log at the DEBUG level.
|
||||
* It takes a printf-style format string followed by a variable list of
|
||||
* arguments for formatting.
|
||||
*
|
||||
* @param level the verbosity level
|
||||
* @param ctx a Strophe context object
|
||||
* @param area the area to log for
|
||||
* @param fmt a printf-style format string followed by a variable list of
|
||||
* arguments to format
|
||||
*/
|
||||
void xmpp_debug_verbose(
|
||||
int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (ctx->verbosity < level)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/** Create and initialize a Strophe context object.
|
||||
* If mem is NULL, a default allocation setup will be used which
|
||||
* wraps malloc(), free(), and realloc() from the standard library.
|
||||
@@ -398,8 +415,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;
|
||||
|
||||
@@ -439,7 +455,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);
|
||||
@@ -453,7 +469,19 @@ 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;
|
||||
}
|
||||
|
||||
/** Set the verbosity level of a Strophe context.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param level the verbosity level
|
||||
*
|
||||
* @ingroup Context
|
||||
*/
|
||||
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level)
|
||||
{
|
||||
ctx->verbosity = level;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
*
|
||||
* @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;
|
||||
@@ -110,6 +110,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
|
||||
conn->error = ECONNABORTED;
|
||||
conn_disconnect(conn);
|
||||
goto NEXT_ITEM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +134,9 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
break; /* partial write or an error */
|
||||
|
||||
/* all data for this queue item written, delete and move on */
|
||||
xmpp_debug(conn->ctx, "conn", "SENT: %s", sq->data);
|
||||
xmpp_debug_verbose(1, ctx, "xmpp",
|
||||
"Finished writing queue element: %p.", sq);
|
||||
xmpp_free(ctx, sq->data);
|
||||
tsq = sq;
|
||||
sq = sq->next;
|
||||
@@ -154,7 +158,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
|
||||
conn->error = ECONNABORTED;
|
||||
conn_disconnect(conn);
|
||||
}
|
||||
|
||||
NEXT_ITEM:
|
||||
connitem = connitem->next;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
|
||||
* @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;
|
||||
@@ -144,7 +144,7 @@ void handler_fire_stanza(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza)
|
||||
*
|
||||
* @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;
|
||||
@@ -253,9 +253,9 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
|
||||
static void _timed_handler_add(xmpp_ctx_t *ctx,
|
||||
xmpp_handlist_t **handlers_list,
|
||||
xmpp_void_handler handler,
|
||||
const unsigned long period,
|
||||
void *const userdata,
|
||||
const int user_handler)
|
||||
unsigned long period,
|
||||
void *userdata,
|
||||
int user_handler)
|
||||
{
|
||||
xmpp_handlist_t *item;
|
||||
|
||||
@@ -311,16 +311,15 @@ static void _timed_handler_delete(xmpp_ctx_t *ctx,
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
_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,
|
||||
const char *id,
|
||||
void *userdata,
|
||||
int user_handler)
|
||||
{
|
||||
xmpp_handlist_t *item, *tail;
|
||||
@@ -373,9 +372,9 @@ 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;
|
||||
|
||||
@@ -406,12 +405,12 @@ 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,
|
||||
const char *ns,
|
||||
const char *name,
|
||||
const char *type,
|
||||
void *userdata,
|
||||
int user_handler)
|
||||
{
|
||||
xmpp_handlist_t *item, *tail;
|
||||
@@ -489,7 +488,7 @@ 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;
|
||||
|
||||
@@ -536,10 +535,10 @@ void xmpp_handler_delete(xmpp_conn_t *const conn, xmpp_handler handler)
|
||||
*
|
||||
* @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->ctx, &conn->timed_handlers, handler, period,
|
||||
userdata, 1);
|
||||
@@ -554,10 +553,10 @@ 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->ctx, &conn->timed_handlers, handler, period,
|
||||
userdata, 0);
|
||||
@@ -579,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);
|
||||
}
|
||||
@@ -596,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);
|
||||
}
|
||||
@@ -626,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);
|
||||
}
|
||||
@@ -647,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);
|
||||
}
|
||||
@@ -762,10 +761,10 @@ void handler_system_delete_all(xmpp_conn_t *conn)
|
||||
*
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||
void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx,
|
||||
xmpp_global_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void *const userdata)
|
||||
unsigned long period,
|
||||
void *userdata)
|
||||
{
|
||||
_timed_handler_add(ctx, &ctx->timed_handlers, handler, period, userdata, 1);
|
||||
}
|
||||
@@ -777,7 +776,7 @@ void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||
*
|
||||
* @ingroup Handlers
|
||||
*/
|
||||
void xmpp_global_timed_handler_delete(xmpp_ctx_t *const ctx,
|
||||
void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx,
|
||||
xmpp_global_timed_handler handler)
|
||||
{
|
||||
_timed_handler_delete(ctx, &ctx->timed_handlers, handler);
|
||||
|
||||
@@ -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_new(xmpp_ctx_t *const ctx, const int size, hash_free_func free_func)
|
||||
}
|
||||
|
||||
/** 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;
|
||||
@@ -143,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;
|
||||
|
||||
11
src/hash.h
11
src/hash.h
@@ -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);
|
||||
|
||||
@@ -20,12 +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,
|
||||
|
||||
@@ -295,12 +295,26 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
|
||||
return _xml_name(ctx, nsname);
|
||||
}
|
||||
|
||||
static void _free_parent_stanza(xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *parent;
|
||||
|
||||
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
|
||||
;
|
||||
xmpp_stanza_release(parent);
|
||||
}
|
||||
|
||||
/* free a parser */
|
||||
void parser_free(parser_t *parser)
|
||||
{
|
||||
if (parser->expat)
|
||||
XML_ParserFree(parser->expat);
|
||||
|
||||
if (parser->stanza) {
|
||||
_free_parent_stanza(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
|
||||
if (parser->inner_text) {
|
||||
xmpp_free(parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
@@ -330,7 +344,7 @@ int parser_reset(parser_t *parser)
|
||||
}
|
||||
|
||||
if (parser->stanza) {
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
_free_parent_stanza(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,13 +262,22 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
|
||||
return xmpp_strdup(ctx, nsname);
|
||||
}
|
||||
|
||||
static void _free_parent_stanza(xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *parent;
|
||||
|
||||
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
|
||||
;
|
||||
xmpp_stanza_release(parent);
|
||||
}
|
||||
|
||||
/* free a parser */
|
||||
void parser_free(parser_t *parser)
|
||||
{
|
||||
if (parser->xmlctx)
|
||||
xmlFreeParserCtxt(parser->xmlctx);
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
_free_parent_stanza(parser->stanza);
|
||||
xmpp_free(parser->ctx, parser);
|
||||
}
|
||||
|
||||
@@ -278,7 +287,7 @@ int parser_reset(parser_t *parser)
|
||||
if (parser->xmlctx)
|
||||
xmlFreeParserCtxt(parser->xmlctx);
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
_free_parent_stanza(parser->stanza);
|
||||
|
||||
parser->stanza = NULL;
|
||||
parser->depth = 0;
|
||||
|
||||
@@ -65,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;
|
||||
|
||||
|
||||
@@ -206,9 +206,7 @@ void crypto_SHA1_Init(SHA1_CTX *context)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
|
||||
@@ -24,9 +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);
|
||||
|
||||
|
||||
18
src/sock.c
18
src/sock.c
@@ -69,7 +69,7 @@ static int _in_progress(int error)
|
||||
#endif
|
||||
}
|
||||
|
||||
sock_t sock_connect(const char *const host, const unsigned short port)
|
||||
sock_t sock_connect(const char *host, unsigned short port)
|
||||
{
|
||||
sock_t sock;
|
||||
char service[6];
|
||||
@@ -109,7 +109,7 @@ sock_t sock_connect(const char *const host, const unsigned short port)
|
||||
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;
|
||||
@@ -154,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);
|
||||
@@ -180,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 ||
|
||||
@@ -210,7 +210,7 @@ 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_storage ss;
|
||||
struct sockaddr *sa = (struct sockaddr *)&ss;
|
||||
|
||||
18
src/sock.h
18
src/sock.h
@@ -30,16 +30,16 @@ void sock_shutdown(void);
|
||||
|
||||
int sock_error(void);
|
||||
|
||||
sock_t sock_connect(const char *const host, const unsigned short port);
|
||||
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__ */
|
||||
|
||||
187
src/stanza.c
187
src/stanza.c
@@ -64,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++;
|
||||
|
||||
@@ -74,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;
|
||||
@@ -114,7 +113,7 @@ 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;
|
||||
|
||||
@@ -169,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;
|
||||
@@ -205,7 +204,7 @@ int xmpp_stanza_release(xmpp_stanza_t *const stanza)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t *const stanza)
|
||||
xmpp_ctx_t *xmpp_stanza_get_context(const xmpp_stanza_t *stanza)
|
||||
{
|
||||
return stanza->ctx;
|
||||
}
|
||||
@@ -218,7 +217,7 @@ xmpp_ctx_t *xmpp_stanza_get_context(const 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);
|
||||
}
|
||||
@@ -231,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);
|
||||
}
|
||||
@@ -242,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;
|
||||
@@ -295,11 +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;
|
||||
|
||||
@@ -317,9 +313,8 @@ static void _render_update(int *written,
|
||||
* 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;
|
||||
@@ -444,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;
|
||||
@@ -507,7 +500,7 @@ 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;
|
||||
@@ -531,7 +524,7 @@ int xmpp_stanza_set_name(xmpp_stanza_t *stanza, const char *const name)
|
||||
*
|
||||
* @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;
|
||||
@@ -546,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;
|
||||
@@ -569,7 +562,7 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t *const stanza)
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
int xmpp_stanza_get_attributes(xmpp_stanza_t *const stanza,
|
||||
int xmpp_stanza_get_attributes(xmpp_stanza_t *stanza,
|
||||
const char **attr,
|
||||
int attrlen)
|
||||
{
|
||||
@@ -611,9 +604,9 @@ 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;
|
||||
@@ -652,7 +645,7 @@ 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);
|
||||
}
|
||||
@@ -727,7 +720,7 @@ 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;
|
||||
@@ -756,8 +749,8 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza, const char *const text)
|
||||
* @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;
|
||||
@@ -786,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");
|
||||
}
|
||||
@@ -801,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");
|
||||
}
|
||||
@@ -816,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");
|
||||
}
|
||||
@@ -831,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");
|
||||
}
|
||||
@@ -846,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");
|
||||
}
|
||||
@@ -862,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;
|
||||
|
||||
@@ -888,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;
|
||||
@@ -916,9 +909,9 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t *const stanza,
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_ns(xmpp_stanza_t *const stanza,
|
||||
const char *const name,
|
||||
const char *const 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 *child;
|
||||
const char *child_ns;
|
||||
@@ -947,7 +940,7 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name_and_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;
|
||||
}
|
||||
@@ -960,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;
|
||||
}
|
||||
@@ -976,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;
|
||||
@@ -1027,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;
|
||||
@@ -1046,7 +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);
|
||||
}
|
||||
@@ -1062,7 +1055,7 @@ int xmpp_stanza_set_id(xmpp_stanza_t *const stanza, const char *const id)
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
@@ -1079,7 +1072,7 @@ int xmpp_stanza_set_type(xmpp_stanza_t *const stanza, const char *const type)
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
@@ -1096,7 +1089,7 @@ int xmpp_stanza_set_to(xmpp_stanza_t *const stanza, const char *const to)
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
@@ -1112,8 +1105,7 @@ int xmpp_stanza_set_from(xmpp_stanza_t *const stanza, const char *const from)
|
||||
*
|
||||
* @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;
|
||||
@@ -1133,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;
|
||||
@@ -1157,7 +1148,7 @@ 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;
|
||||
@@ -1212,16 +1203,16 @@ copy_error:
|
||||
*
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *const stanza,
|
||||
const char *const error_type,
|
||||
const char *const condition,
|
||||
const char *const text)
|
||||
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;
|
||||
xmpp_stanza_t *error = NULL;
|
||||
xmpp_stanza_t *item = NULL;
|
||||
xmpp_stanza_t *text_stanza = NULL;
|
||||
const char *to;
|
||||
|
||||
if (!error_type || !condition)
|
||||
@@ -1230,41 +1221,53 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *const stanza,
|
||||
reply = xmpp_stanza_reply(stanza);
|
||||
if (!reply)
|
||||
goto quit_err;
|
||||
|
||||
xmpp_stanza_set_type(reply, "error");
|
||||
if (xmpp_stanza_set_type(reply, "error") != XMPP_EOK)
|
||||
goto quit_err;
|
||||
to = xmpp_stanza_get_to(stanza);
|
||||
if (to)
|
||||
xmpp_stanza_set_from(reply, to);
|
||||
if (xmpp_stanza_set_from(reply, to) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
|
||||
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);
|
||||
if (xmpp_stanza_set_name(error, "error") != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_set_type(error, error_type) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_add_child(reply, error) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
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);
|
||||
if (xmpp_stanza_set_name(item, condition) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_add_child(error, item) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
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);
|
||||
if (xmpp_stanza_set_name(item, "text") != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_set_ns(item, XMPP_NS_STANZAS_IETF) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_add_child(error, item) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
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);
|
||||
if (xmpp_stanza_set_text(text_stanza, text) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
if (xmpp_stanza_add_child(item, text_stanza) != XMPP_EOK)
|
||||
goto quit_err;
|
||||
xmpp_stanza_release(text_stanza);
|
||||
}
|
||||
|
||||
@@ -1273,14 +1276,20 @@ xmpp_stanza_t *xmpp_stanza_reply_error(xmpp_stanza_t *const stanza,
|
||||
quit_err:
|
||||
if (reply)
|
||||
xmpp_stanza_release(reply);
|
||||
if (error)
|
||||
xmpp_stanza_release(error);
|
||||
if (item)
|
||||
xmpp_stanza_release(item);
|
||||
if (text_stanza)
|
||||
xmpp_stanza_release(text_stanza);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
const char *name,
|
||||
const char *type,
|
||||
const char *id,
|
||||
const char *to)
|
||||
{
|
||||
xmpp_stanza_t *stanza = xmpp_stanza_new(ctx);
|
||||
int ret;
|
||||
@@ -1314,9 +1323,9 @@ static xmpp_stanza_t *_stanza_new_with_attrs(xmpp_ctx_t *ctx,
|
||||
* @ingroup Stanza
|
||||
*/
|
||||
xmpp_stanza_t *xmpp_message_new(xmpp_ctx_t *ctx,
|
||||
const char *const type,
|
||||
const char *const to,
|
||||
const char *const id)
|
||||
const char *type,
|
||||
const char *to,
|
||||
const char *id)
|
||||
{
|
||||
return _stanza_new_with_attrs(ctx, "message", type, id, to);
|
||||
}
|
||||
@@ -1355,7 +1364,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;
|
||||
@@ -1401,8 +1410,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);
|
||||
}
|
||||
@@ -1433,9 +1441,8 @@ 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);
|
||||
|
||||
214
src/tls.c
Normal file
214
src/tls.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/* tls.c
|
||||
** strophe XMPP client library -- generic TLS functions
|
||||
**
|
||||
** Copyright (C) 2021 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
|
||||
**
|
||||
** This software is provided AS-IS with no warranty, either express
|
||||
** or implied.
|
||||
**
|
||||
** This program is dual licensed under the MIT and GPLv3 licenses.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Generic TLS functionality.
|
||||
*/
|
||||
|
||||
/** @defgroup TLS SSL/TLS specific functionality
|
||||
* These functions provide SSL/TLS specific functionality.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strophe.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct _dnsname_t {
|
||||
char **data;
|
||||
size_t cur, max;
|
||||
};
|
||||
|
||||
const size_t tlscert_dnsnames_increment = 4;
|
||||
|
||||
/** Get the Strophe context which is assigned to this certificate.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
*
|
||||
* @return the Strophe context object where this certificate originates from
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert)
|
||||
{
|
||||
return cert->ctx;
|
||||
}
|
||||
|
||||
/** Get the Strophe connection which is assigned to this certificate.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
*
|
||||
* @return the Strophe connection object where this certificate originates from
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert)
|
||||
{
|
||||
return cert->conn;
|
||||
}
|
||||
|
||||
/** Get the complete PEM of this certificate.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
*
|
||||
* @return a string containing the PEM of this certificate
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert)
|
||||
{
|
||||
return cert->pem;
|
||||
}
|
||||
|
||||
/** Get the dnsName entries out of the SubjectAlternativeNames.
|
||||
*
|
||||
* Note: Max. `MAX_NUM_DNSNAMES` are supported.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
* @param n which dnsName entry
|
||||
*
|
||||
* @return a string with the n'th dnsName
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n)
|
||||
{
|
||||
if (n >= cert->dnsnames->cur)
|
||||
return NULL;
|
||||
return cert->dnsnames->data[n];
|
||||
}
|
||||
|
||||
/** Get various parts of the certificate as String.
|
||||
*
|
||||
* c.f. \ref xmpp_cert_element_t for details.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
* @param elmnt which part of the certificate
|
||||
*
|
||||
* @return a string with the part of the certificate
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
|
||||
xmpp_cert_element_t elmnt)
|
||||
{
|
||||
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
|
||||
return NULL;
|
||||
return cert->elements[elmnt];
|
||||
}
|
||||
|
||||
/** Get a descriptive string for each xmpp_cert_element_t.
|
||||
*
|
||||
* c.f. \ref xmpp_cert_element_t for details.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
* @param elmnt which element
|
||||
*
|
||||
* @return a string with the description
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt)
|
||||
{
|
||||
static const char *descriptions[] = {
|
||||
"X.509 Version",
|
||||
"SerialNumber",
|
||||
"Subject",
|
||||
"Issuer",
|
||||
"Issued On",
|
||||
"Expires On",
|
||||
"Public Key Algorithm",
|
||||
"Certificate Signature Algorithm",
|
||||
"Fingerprint SHA-1",
|
||||
"Fingerprint SHA-256",
|
||||
};
|
||||
if (elmnt >= XMPP_CERT_ELEMENT_MAX)
|
||||
return NULL;
|
||||
return descriptions[elmnt];
|
||||
}
|
||||
|
||||
/** Allocate and initialize a Strophe TLS certificate object.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
*
|
||||
* @return a certificate object or NULL
|
||||
*/
|
||||
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx)
|
||||
{
|
||||
xmpp_tlscert_t *tlscert = xmpp_alloc(ctx, sizeof(*tlscert));
|
||||
if (!tlscert)
|
||||
return NULL;
|
||||
memset(tlscert, 0, sizeof(*tlscert));
|
||||
|
||||
tlscert->dnsnames = xmpp_alloc(ctx, sizeof(*tlscert->dnsnames));
|
||||
if (!tlscert->dnsnames) {
|
||||
xmpp_free(ctx, tlscert);
|
||||
return NULL;
|
||||
}
|
||||
memset(tlscert->dnsnames, 0, sizeof(*tlscert->dnsnames));
|
||||
|
||||
tlscert->ctx = ctx;
|
||||
|
||||
return tlscert;
|
||||
}
|
||||
|
||||
/** Free a certificate object.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
void xmpp_tlscert_free(xmpp_tlscert_t *cert)
|
||||
{
|
||||
size_t n;
|
||||
for (n = 0; n < ARRAY_SIZE(cert->elements); ++n) {
|
||||
if (cert->elements[n])
|
||||
xmpp_free(cert->ctx, cert->elements[n]);
|
||||
}
|
||||
if (cert->dnsnames->data) {
|
||||
for (n = 0; n < cert->dnsnames->cur; ++n) {
|
||||
if (cert->dnsnames->data[n])
|
||||
xmpp_free(cert->ctx, cert->dnsnames->data[n]);
|
||||
}
|
||||
}
|
||||
xmpp_free(cert->ctx, cert->dnsnames->data);
|
||||
xmpp_free(cert->ctx, cert->dnsnames);
|
||||
if (cert->pem)
|
||||
xmpp_free(cert->ctx, cert->pem);
|
||||
xmpp_free(cert->ctx, cert);
|
||||
}
|
||||
|
||||
/** Add a dnsName to the Strophe TLS certificate object.
|
||||
*
|
||||
* @param cert a Strophe TLS certificate object
|
||||
* @param dnsname dnsName that shall be stored
|
||||
*
|
||||
* @return classic Unix style - 0=success, 1=error
|
||||
*/
|
||||
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname)
|
||||
{
|
||||
if ((cert->dnsnames->cur + 1) >= cert->dnsnames->max) {
|
||||
char **dnsnames =
|
||||
xmpp_realloc(cert->ctx, cert->dnsnames->data,
|
||||
(cert->dnsnames->max + tlscert_dnsnames_increment) *
|
||||
sizeof(char **));
|
||||
if (!dnsnames)
|
||||
return 1;
|
||||
cert->dnsnames->data = dnsnames;
|
||||
cert->dnsnames->max += tlscert_dnsnames_increment;
|
||||
}
|
||||
cert->dnsnames->data[cert->dnsnames->cur++] =
|
||||
xmpp_strdup(cert->ctx, dnsname);
|
||||
return 0;
|
||||
}
|
||||
25
src/tls.h
25
src/tls.h
@@ -21,12 +21,28 @@
|
||||
|
||||
typedef struct _tls tls_t;
|
||||
|
||||
typedef struct _dnsname_t dnsname_t;
|
||||
|
||||
struct _xmpp_tlscert_t {
|
||||
xmpp_ctx_t *ctx;
|
||||
xmpp_conn_t *conn;
|
||||
char *pem;
|
||||
char *elements[XMPP_CERT_ELEMENT_MAX];
|
||||
dnsname_t *dnsnames;
|
||||
};
|
||||
|
||||
/* provided by the real TLS implementation */
|
||||
|
||||
void tls_initialize(void);
|
||||
void tls_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);
|
||||
|
||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn);
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename);
|
||||
|
||||
int tls_start(tls_t *tls);
|
||||
@@ -35,10 +51,15 @@ 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);
|
||||
|
||||
/* provided by tls.c */
|
||||
|
||||
xmpp_tlscert_t *tlscert_new(xmpp_ctx_t *ctx);
|
||||
int tlscert_add_dnsname(xmpp_tlscert_t *cert, const char *dnsname);
|
||||
|
||||
#endif /* __LIBSTROPHE_TLS_H__ */
|
||||
|
||||
@@ -33,6 +33,21 @@ 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);
|
||||
@@ -46,6 +61,12 @@ void tls_free(tls_t *tls)
|
||||
return;
|
||||
}
|
||||
|
||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
|
||||
{
|
||||
UNUSED(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
{
|
||||
UNUSED(tls);
|
||||
@@ -78,7 +99,7 @@ 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)
|
||||
{
|
||||
UNUSED(tls);
|
||||
UNUSED(buff);
|
||||
@@ -86,7 +107,7 @@ int tls_read(tls_t *tls, void *const buff, const size_t 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);
|
||||
|
||||
334
src/tls_gnutls.c
334
src/tls_gnutls.c
@@ -13,20 +13,21 @@
|
||||
* 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"
|
||||
#include "sock.h"
|
||||
|
||||
/* FIXME this shouldn't be a constant string */
|
||||
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
struct _tls {
|
||||
xmpp_ctx_t *ctx; /* do we need this? */
|
||||
sock_t sock;
|
||||
xmpp_conn_t *conn;
|
||||
gnutls_session_t session;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
gnutls_x509_crt_t client_cert;
|
||||
int lasterror;
|
||||
};
|
||||
|
||||
@@ -46,19 +47,299 @@ 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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, gnutls_x509_crt_t cert)
|
||||
{
|
||||
int res;
|
||||
char buf[512], smallbuf[64];
|
||||
size_t size, m;
|
||||
unsigned int algo, n;
|
||||
gnutls_datum_t data;
|
||||
time_t time_val;
|
||||
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
|
||||
|
||||
gnutls_x509_crt_export2(cert, GNUTLS_X509_FMT_PEM, &data);
|
||||
tlscert->pem = xmpp_alloc(ctx, data.size + 1);
|
||||
memcpy(tlscert->pem, data.data, data.size);
|
||||
tlscert->pem[data.size] = '\0';
|
||||
gnutls_free(data.data);
|
||||
|
||||
size = sizeof(buf);
|
||||
gnutls_x509_crt_get_dn(cert, buf, &size);
|
||||
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, buf);
|
||||
size = sizeof(buf);
|
||||
gnutls_x509_crt_get_issuer_dn(cert, buf, &size);
|
||||
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, buf);
|
||||
|
||||
time_val = gnutls_x509_crt_get_activation_time(cert);
|
||||
tlscert->elements[XMPP_CERT_NOTBEFORE] = xmpp_strdup(ctx, ctime(&time_val));
|
||||
tlscert->elements[XMPP_CERT_NOTBEFORE]
|
||||
[strlen(tlscert->elements[XMPP_CERT_NOTBEFORE]) - 1] =
|
||||
'\0';
|
||||
time_val = gnutls_x509_crt_get_expiration_time(cert);
|
||||
tlscert->elements[XMPP_CERT_NOTAFTER] = xmpp_strdup(ctx, ctime(&time_val));
|
||||
tlscert->elements[XMPP_CERT_NOTAFTER]
|
||||
[strlen(tlscert->elements[XMPP_CERT_NOTAFTER]) - 1] = '\0';
|
||||
|
||||
size = sizeof(smallbuf);
|
||||
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, smallbuf, &size);
|
||||
hex_encode(buf, smallbuf, size);
|
||||
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] = xmpp_strdup(ctx, buf);
|
||||
size = sizeof(smallbuf);
|
||||
gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, smallbuf, &size);
|
||||
hex_encode(buf, smallbuf, size);
|
||||
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] = xmpp_strdup(ctx, buf);
|
||||
|
||||
xmpp_snprintf(buf, sizeof(buf), "%d", gnutls_x509_crt_get_version(cert));
|
||||
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
|
||||
|
||||
algo = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
|
||||
tlscert->elements[XMPP_CERT_KEYALG] =
|
||||
xmpp_strdup(ctx, gnutls_pk_algorithm_get_name(algo));
|
||||
algo = gnutls_x509_crt_get_signature_algorithm(cert);
|
||||
tlscert->elements[XMPP_CERT_SIGALG] =
|
||||
xmpp_strdup(ctx, gnutls_sign_get_name(algo));
|
||||
|
||||
size = sizeof(smallbuf);
|
||||
gnutls_x509_crt_get_serial(cert, smallbuf, &size);
|
||||
hex_encode(buf, smallbuf, size);
|
||||
tlscert->elements[XMPP_CERT_SERIALNUMBER] = xmpp_strdup(ctx, buf);
|
||||
|
||||
for (n = 0, m = 0, res = 0; res != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
|
||||
++n) {
|
||||
size = sizeof(buf);
|
||||
res = gnutls_x509_crt_get_subject_alt_name(cert, n, buf, &size, NULL);
|
||||
if (res == GNUTLS_SAN_DNSNAME) {
|
||||
if (tlscert_add_dnsname(tlscert, buf))
|
||||
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", m, buf);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
return tlscert;
|
||||
}
|
||||
|
||||
static int _tls_verify(gnutls_session_t session)
|
||||
{
|
||||
tls_t *tls = gnutls_session_get_ptr(session);
|
||||
const gnutls_datum_t *cert_list;
|
||||
gnutls_certificate_type_t type;
|
||||
gnutls_datum_t out;
|
||||
unsigned int cert_list_size = 0, status;
|
||||
gnutls_x509_crt_t cert;
|
||||
|
||||
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
|
||||
return -1;
|
||||
|
||||
if (gnutls_certificate_verify_peers2(session, &status) < 0) {
|
||||
xmpp_error(tls->ctx, "tls", "Verify peers failed");
|
||||
return -1;
|
||||
}
|
||||
type = gnutls_certificate_type_get(session);
|
||||
if (gnutls_certificate_verification_status_print(status, type, &out, 0) <
|
||||
0) {
|
||||
xmpp_error(tls->ctx, "tls", "Status print failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return early if the Certificate is trusted
|
||||
* OR if we trust all Certificates */
|
||||
if (status == 0 || tls->conn->tls_trust)
|
||||
return 0;
|
||||
|
||||
if (!tls->conn->certfail_handler) {
|
||||
xmpp_error(tls->ctx, "tls",
|
||||
"No certfail handler set, canceling connection attempt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
|
||||
|
||||
/* OpenSSL displays the certificate chain in reverse order than GnuTLS.
|
||||
* To show consistent behavior to the user, traverse the list from the
|
||||
* end.
|
||||
*/
|
||||
while (cert_list_size--) {
|
||||
gnutls_x509_crt_init(&cert);
|
||||
|
||||
gnutls_x509_crt_import(cert, &cert_list[cert_list_size],
|
||||
GNUTLS_X509_FMT_DER);
|
||||
|
||||
xmpp_tlscert_t *tlscert = _x509_to_tlscert(tls->ctx, cert);
|
||||
|
||||
if (!tlscert) {
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
gnutls_free(out.data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls->conn->certfail_handler(tlscert, (char *)out.data) == 0) {
|
||||
xmpp_tlscert_free(tlscert);
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
gnutls_free(out.data);
|
||||
return -1;
|
||||
}
|
||||
xmpp_tlscert_free(tlscert);
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
}
|
||||
gnutls_free(out.data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tls_t *tls_new(xmpp_conn_t *conn)
|
||||
{
|
||||
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(tls_t));
|
||||
|
||||
if (tls) {
|
||||
memset(tls, 0, sizeof(*tls));
|
||||
tls->ctx = conn->ctx;
|
||||
tls->sock = conn->sock;
|
||||
tls->conn = conn;
|
||||
gnutls_init(&tls->session, GNUTLS_CLIENT);
|
||||
|
||||
gnutls_certificate_allocate_credentials(&tls->cred);
|
||||
tls_set_credentials(tls, CAFILE);
|
||||
tls_set_credentials(tls, NULL);
|
||||
|
||||
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_certificate_set_verify_function(tls->cred, _tls_verify);
|
||||
|
||||
gnutls_set_default_priority(tls->session);
|
||||
gnutls_session_set_ptr(tls->session, tls);
|
||||
|
||||
/* fixme: this may require setting a callback on win32? */
|
||||
gnutls_transport_set_int(tls->session, conn->sock);
|
||||
@@ -69,18 +350,45 @@ 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);
|
||||
}
|
||||
|
||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
|
||||
{
|
||||
xmpp_tlscert_t *tlscert = NULL;
|
||||
if (conn && conn->tls && conn->tls->session) {
|
||||
unsigned int list_size = 0;
|
||||
const gnutls_datum_t *der_cert =
|
||||
gnutls_certificate_get_peers(conn->tls->session, &list_size);
|
||||
if (der_cert && list_size) {
|
||||
gnutls_x509_crt_t cert;
|
||||
if (gnutls_x509_crt_init(&cert) < 0)
|
||||
return NULL;
|
||||
if (gnutls_x509_crt_import(cert, der_cert, GNUTLS_X509_FMT_DER) ==
|
||||
0)
|
||||
tlscert = _x509_to_tlscert(conn->ctx, cert);
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
}
|
||||
}
|
||||
return tlscert;
|
||||
}
|
||||
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
{
|
||||
int err;
|
||||
UNUSED(cafilename);
|
||||
|
||||
/* set trusted credentials -- takes a .pem filename */
|
||||
err = gnutls_certificate_set_x509_trust_file(tls->cred, cafilename,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
int err = gnutls_certificate_set_x509_system_trust(tls->cred);
|
||||
if (err >= 0 && tls->conn->tls_cafile)
|
||||
err = gnutls_certificate_set_x509_trust_file(
|
||||
tls->cred, tls->conn->tls_cafile, GNUTLS_X509_FMT_PEM);
|
||||
if (err >= 0 && tls->conn->tls_capath)
|
||||
err = gnutls_certificate_set_x509_trust_dir(
|
||||
tls->cred, tls->conn->tls_capath, GNUTLS_X509_FMT_PEM);
|
||||
if (err >= 0) {
|
||||
err = gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE,
|
||||
tls->cred);
|
||||
@@ -92,9 +400,9 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
|
||||
int tls_start(tls_t *tls)
|
||||
{
|
||||
sock_set_blocking(tls->sock);
|
||||
sock_set_blocking(tls->conn->sock);
|
||||
tls->lasterror = gnutls_handshake(tls->session);
|
||||
sock_set_nonblocking(tls->sock);
|
||||
sock_set_nonblocking(tls->conn->sock);
|
||||
|
||||
return tls->lasterror == GNUTLS_E_SUCCESS;
|
||||
}
|
||||
@@ -120,7 +428,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 +438,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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -66,6 +89,12 @@ 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_xmppaddr_to_string(GENERAL_NAME *name, char **res);
|
||||
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res);
|
||||
static GENERAL_NAMES *_tls_conn_get_names(xmpp_conn_t *conn);
|
||||
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert);
|
||||
|
||||
#define TLS_ERROR_STR(error, table) \
|
||||
_tls_error_str(error, table, ARRAY_SIZE(table))
|
||||
@@ -81,6 +110,7 @@ const char *tls_errors[] = {
|
||||
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),
|
||||
@@ -88,6 +118,7 @@ const char *tls_errors[] = {
|
||||
#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),
|
||||
@@ -148,30 +179,34 @@ const char *cert_errors[] = {
|
||||
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
|
||||
#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_INVALID_CALL),
|
||||
TLS_ERROR_FIELD(X509_V_ERR_STORE_LOOKUP),
|
||||
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
|
||||
#endif /* !LIBRESSL_VERSION_NUMBER */
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
|
||||
};
|
||||
#undef TLS_ERROR_FIELD
|
||||
|
||||
@@ -183,6 +218,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)
|
||||
@@ -193,6 +230,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();
|
||||
@@ -212,10 +250,265 @@ 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_conn_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_xmppaddr_to_string(name, &res))
|
||||
continue;
|
||||
if (j == (int)n) {
|
||||
xmpp_debug(conn->ctx, "tls", "extracted jid %s from id-on-xmppAddr",
|
||||
res);
|
||||
ret = xmpp_strdup(conn->ctx, res);
|
||||
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_conn_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_xmppaddr_to_string(name, NULL))
|
||||
continue;
|
||||
ret++;
|
||||
}
|
||||
GENERAL_NAMES_free(names);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _convert_ASN1TIME(ASN1_TIME *ansi_time, char *buf, size_t len)
|
||||
{
|
||||
BIO *bio = BIO_new(BIO_s_mem());
|
||||
int rc = ASN1_TIME_print(bio, ansi_time);
|
||||
if (rc <= 0) {
|
||||
BIO_free(bio);
|
||||
return 0;
|
||||
}
|
||||
rc = BIO_gets(bio, buf, len);
|
||||
if (rc <= 0) {
|
||||
BIO_free(bio);
|
||||
return 0;
|
||||
}
|
||||
BIO_free(bio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *_asn1_time_to_str(const xmpp_ctx_t *ctx, ASN1_TIME *t)
|
||||
{
|
||||
char buf[128];
|
||||
int res = _convert_ASN1TIME(t, buf, sizeof(buf));
|
||||
if (res) {
|
||||
return xmpp_strdup(ctx, buf);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
_get_fingerprint(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
|
||||
{
|
||||
unsigned char buf[EVP_MAX_MD_SIZE];
|
||||
unsigned int len;
|
||||
const EVP_MD *digest;
|
||||
switch (el) {
|
||||
case XMPP_CERT_FINGERPRINT_SHA1:
|
||||
digest = EVP_sha1();
|
||||
break;
|
||||
case XMPP_CERT_FINGERPRINT_SHA256:
|
||||
digest = EVP_sha256();
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
if (X509_digest(err_cert, digest, buf, &len) != 0) {
|
||||
char fingerprint[4 * EVP_MAX_MD_SIZE];
|
||||
hex_encode(fingerprint, buf, len);
|
||||
return xmpp_strdup(ctx, fingerprint);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
_get_alg(const xmpp_ctx_t *ctx, X509 *err_cert, xmpp_cert_element_t el)
|
||||
{
|
||||
int rc, alg_nid = NID_undef;
|
||||
|
||||
switch (el) {
|
||||
case XMPP_CERT_KEYALG: {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
alg_nid = OBJ_obj2nid(err_cert->cert_info->key->algor->algorithm);
|
||||
#else
|
||||
X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(err_cert);
|
||||
ASN1_OBJECT *ppkalg = NULL;
|
||||
rc = X509_PUBKEY_get0_param(&ppkalg, NULL, NULL, NULL, pubkey);
|
||||
if (rc) {
|
||||
alg_nid = OBJ_obj2nid(ppkalg);
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
case XMPP_CERT_SIGALG: {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
alg_nid = OBJ_obj2nid(err_cert->sig_alg->algorithm);
|
||||
#else
|
||||
const X509_ALGOR *palg;
|
||||
X509_get0_signature(NULL, &palg, err_cert);
|
||||
alg_nid = OBJ_obj2nid(palg->algorithm);
|
||||
#endif
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (alg_nid != NID_undef) {
|
||||
const char *alg = OBJ_nid2ln(alg_nid);
|
||||
if (alg) {
|
||||
return xmpp_strdup(ctx, alg);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xmpp_tlscert_t *_x509_to_tlscert(xmpp_ctx_t *ctx, X509 *cert)
|
||||
{
|
||||
char *subject, *issuer, buf[32];
|
||||
xmpp_tlscert_t *tlscert = tlscert_new(ctx);
|
||||
if (!tlscert)
|
||||
return NULL;
|
||||
|
||||
BIO *b = BIO_new(BIO_s_mem());
|
||||
if (!b)
|
||||
goto ERR_OUT;
|
||||
PEM_write_bio_X509(b, cert);
|
||||
BUF_MEM *bptr;
|
||||
BIO_get_mem_ptr(b, &bptr);
|
||||
tlscert->pem = xmpp_alloc(ctx, bptr->length + 1);
|
||||
if (!tlscert->pem)
|
||||
goto ERR_OUT;
|
||||
memcpy(tlscert->pem, bptr->data, bptr->length);
|
||||
tlscert->pem[bptr->length] = '\0';
|
||||
BIO_free(b);
|
||||
|
||||
subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
|
||||
if (!subject)
|
||||
goto ERR_OUT;
|
||||
tlscert->elements[XMPP_CERT_SUBJECT] = xmpp_strdup(ctx, subject);
|
||||
OPENSSL_free(subject);
|
||||
issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
|
||||
if (!issuer)
|
||||
goto ERR_OUT;
|
||||
tlscert->elements[XMPP_CERT_ISSUER] = xmpp_strdup(ctx, issuer);
|
||||
OPENSSL_free(issuer);
|
||||
|
||||
tlscert->elements[XMPP_CERT_NOTBEFORE] =
|
||||
_asn1_time_to_str(ctx, X509_get_notBefore(cert));
|
||||
tlscert->elements[XMPP_CERT_NOTAFTER] =
|
||||
_asn1_time_to_str(ctx, X509_get_notAfter(cert));
|
||||
|
||||
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA1] =
|
||||
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA1);
|
||||
tlscert->elements[XMPP_CERT_FINGERPRINT_SHA256] =
|
||||
_get_fingerprint(ctx, cert, XMPP_CERT_FINGERPRINT_SHA256);
|
||||
|
||||
xmpp_snprintf(buf, sizeof(buf), "%ld", X509_get_version(cert) + 1);
|
||||
tlscert->elements[XMPP_CERT_VERSION] = xmpp_strdup(ctx, buf);
|
||||
|
||||
tlscert->elements[XMPP_CERT_KEYALG] = _get_alg(ctx, cert, XMPP_CERT_KEYALG);
|
||||
tlscert->elements[XMPP_CERT_SIGALG] = _get_alg(ctx, cert, XMPP_CERT_SIGALG);
|
||||
|
||||
ASN1_INTEGER *serial = X509_get_serialNumber(cert);
|
||||
BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL);
|
||||
if (bn) {
|
||||
char *serialnumber = BN_bn2hex(bn);
|
||||
if (serialnumber) {
|
||||
tlscert->elements[XMPP_CERT_SERIALNUMBER] =
|
||||
xmpp_strdup(ctx, serialnumber);
|
||||
OPENSSL_free(serialnumber);
|
||||
}
|
||||
BN_free(bn);
|
||||
}
|
||||
|
||||
GENERAL_NAMES *names = _tls_cert_get_names(cert);
|
||||
if (names) {
|
||||
int j, num_names = sk_GENERAL_NAME_num(names);
|
||||
size_t n = 0;
|
||||
for (j = 0; j < num_names; ++j) {
|
||||
char *res;
|
||||
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, j);
|
||||
if (_tls_dnsname_to_string(name, &res))
|
||||
continue;
|
||||
if (tlscert_add_dnsname(tlscert, res))
|
||||
xmpp_debug(ctx, "tls", "Can't store dnsName(%zu): %s", n, res);
|
||||
n++;
|
||||
OPENSSL_free(res);
|
||||
}
|
||||
GENERAL_NAMES_free(names);
|
||||
}
|
||||
|
||||
return tlscert;
|
||||
ERR_OUT:
|
||||
xmpp_tlscert_free(tlscert);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _tls_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
||||
{
|
||||
if (preverify_ok == 1)
|
||||
return 1;
|
||||
|
||||
SSL *ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
|
||||
SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||
xmpp_conn_t *conn = SSL_get_app_data(ssl);
|
||||
|
||||
if (!conn->certfail_handler) {
|
||||
xmpp_error(conn->ctx, "tls",
|
||||
"No certfail handler set, canceling connection attempt");
|
||||
return 0;
|
||||
}
|
||||
|
||||
X509 *err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
|
||||
|
||||
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, err_cert);
|
||||
|
||||
if (!tlscert)
|
||||
return 0;
|
||||
|
||||
xmpp_debug(conn->ctx, "tls", "preverify_ok:%d\nSubject: %s\nIssuer: %s",
|
||||
preverify_ok, tlscert->elements[XMPP_CERT_SUBJECT],
|
||||
tlscert->elements[XMPP_CERT_ISSUER]);
|
||||
|
||||
int ret = conn->certfail_handler(
|
||||
tlscert,
|
||||
X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
|
||||
|
||||
xmpp_tlscert_free(tlscert);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
tls_t *tls_new(xmpp_conn_t *conn)
|
||||
{
|
||||
tls_t *tls = xmpp_alloc(conn->ctx, sizeof(*tls));
|
||||
int mode;
|
||||
|
||||
if (tls) {
|
||||
int ret;
|
||||
@@ -243,7 +536,23 @@ 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 */
|
||||
|
||||
SSL_CTX_set_client_cert_cb(tls->ssl_ctx, NULL);
|
||||
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);
|
||||
|
||||
ret = SSL_CTX_set_default_verify_paths(tls->ssl_ctx);
|
||||
@@ -255,21 +564,35 @@ tls_t *tls_new(xmpp_conn_t *conn)
|
||||
*/
|
||||
xmpp_error(tls->ctx, "tls",
|
||||
"SSL_CTX_set_default_verify_paths() failed");
|
||||
goto err_free_ctx;
|
||||
goto err_free_cert;
|
||||
}
|
||||
|
||||
if (conn->tls_cafile || conn->tls_capath) {
|
||||
if (SSL_CTX_load_verify_locations(tls->ssl_ctx, conn->tls_cafile,
|
||||
conn->tls_capath) == 0) {
|
||||
xmpp_error(tls->ctx, "tls",
|
||||
"SSL_CTX_load_verify_locations() failed");
|
||||
_tls_log_error(tls->ctx);
|
||||
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, NULL);
|
||||
/* Trust server's certificate when user sets the flag explicitly.
|
||||
* Otherwise call the verification callback */
|
||||
if (conn->tls_trust)
|
||||
SSL_set_verify(tls->ssl, SSL_VERIFY_NONE, NULL);
|
||||
else
|
||||
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, _tls_verify);
|
||||
SSL_set_app_data(tls->ssl, conn);
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
/* Hostname verification is supported in OpenSSL 1.0.2 and newer. */
|
||||
param = SSL_get0_param(tls->ssl);
|
||||
@@ -295,6 +618,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:
|
||||
@@ -306,10 +631,24 @@ 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);
|
||||
}
|
||||
|
||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
|
||||
{
|
||||
if (conn && conn->tls && conn->tls->ssl) {
|
||||
X509 *cert = SSL_get_peer_certificate(conn->tls->ssl);
|
||||
if (cert) {
|
||||
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
|
||||
X509_free(cert);
|
||||
return tlscert;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
{
|
||||
UNUSED(tls);
|
||||
@@ -346,6 +685,8 @@ int tls_start(tls_t *tls)
|
||||
xmpp_debug(tls->ctx, "tls",
|
||||
"Certificate verification FAILED, result=%s(%ld)",
|
||||
TLS_ERROR_STR((int)x509_res, cert_errors), x509_res);
|
||||
if (ret > 0)
|
||||
xmpp_debug(tls->ctx, "tls", "User decided to connect anyways");
|
||||
}
|
||||
_tls_dump_cert_info(tls);
|
||||
|
||||
@@ -399,7 +740,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;
|
||||
|
||||
@@ -409,7 +750,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;
|
||||
|
||||
@@ -503,3 +844,111 @@ 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_conn_get_names(xmpp_conn_t *conn)
|
||||
{
|
||||
X509 *client_cert;
|
||||
GENERAL_NAMES *names = NULL;
|
||||
client_cert = _tls_cert_read(conn);
|
||||
if (!client_cert)
|
||||
return NULL;
|
||||
names = _tls_cert_get_names(client_cert);
|
||||
if (!conn->tls || !conn->tls->client_cert)
|
||||
X509_free(client_cert);
|
||||
return names;
|
||||
}
|
||||
|
||||
static GENERAL_NAMES *_tls_cert_get_names(X509 *client_cert)
|
||||
{
|
||||
int san = X509_get_ext_by_NID(client_cert, NID_subject_alt_name, 0);
|
||||
X509_EXTENSION *san_ext = X509_get_ext(client_cert, san);
|
||||
if (!san_ext)
|
||||
return NULL;
|
||||
ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(san_ext);
|
||||
if (!data)
|
||||
return NULL;
|
||||
const unsigned char *d = ASN1_STRING_get0_data(data);
|
||||
if (!d)
|
||||
return NULL;
|
||||
return d2i_GENERAL_NAMES(NULL, &d, ASN1_STRING_length(data));
|
||||
}
|
||||
|
||||
/** 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_xmppaddr_to_string(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;
|
||||
}
|
||||
|
||||
static int _tls_dnsname_to_string(GENERAL_NAME *name, char **res)
|
||||
{
|
||||
ASN1_STRING *str;
|
||||
if (!name || name->type != GEN_DNS)
|
||||
return 1;
|
||||
str = GENERAL_NAME_get0_value(name, NULL);
|
||||
if (str == NULL)
|
||||
return 1;
|
||||
if (!res)
|
||||
return 0;
|
||||
if (ASN1_STRING_to_UTF8((unsigned char **)res, str) < 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -207,6 +222,13 @@ void tls_free(tls_t *tls)
|
||||
return;
|
||||
}
|
||||
|
||||
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
|
||||
{
|
||||
/* always fail */
|
||||
xmpp_error(conn->ctx, "tls", "tls_peer_cert() not implemented");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tls_set_credentials(tls_t *tls, const char *cafilename)
|
||||
{
|
||||
UNUSED(tls);
|
||||
@@ -412,7 +434,7 @@ 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;
|
||||
|
||||
@@ -557,7 +579,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];
|
||||
|
||||
45
src/util.c
45
src/util.c
@@ -36,21 +36,41 @@
|
||||
* @param ctx a Strophe context object
|
||||
* @param s a string
|
||||
*
|
||||
* @return a new allocates string with the same data as s or NULL on error
|
||||
* @return a newly allocated 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;
|
||||
return xmpp_strndup(ctx, s, SIZE_MAX);
|
||||
}
|
||||
|
||||
len = strlen(s);
|
||||
copy = xmpp_alloc(ctx, len + 1);
|
||||
/** Duplicate a string with a maximum length.
|
||||
* This function replaces the standard strndup library call with a version
|
||||
* that uses the Strophe context object's allocator.
|
||||
*
|
||||
* @param ctx a Strophe context object
|
||||
* @param s a string
|
||||
* @param len the maximum length of the string to copy
|
||||
*
|
||||
* @return a newly allocated string that contains at most `len` symbols
|
||||
* of the original string or NULL on error
|
||||
*/
|
||||
char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
|
||||
{
|
||||
char *copy;
|
||||
size_t l;
|
||||
|
||||
l = strlen(s);
|
||||
if (l > len)
|
||||
l = len;
|
||||
|
||||
copy = xmpp_alloc(ctx, l + 1);
|
||||
if (!copy) {
|
||||
xmpp_error(ctx, "xmpp", "failed to allocate required memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(copy, s, len + 1);
|
||||
memcpy(copy, s, l);
|
||||
copy[l] = '\0';
|
||||
|
||||
return copy;
|
||||
}
|
||||
@@ -135,8 +155,17 @@ 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);
|
||||
}
|
||||
|
||||
void hex_encode(char *writebuf, void *readbuf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
sprintf(writebuf, "%02x", ((unsigned char *)readbuf)[i]);
|
||||
writebuf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,7 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr);
|
||||
uint64_t time_stamp(void);
|
||||
uint64_t time_elapsed(uint64_t t1, uint64_t t2);
|
||||
|
||||
/* misc functions */
|
||||
void hex_encode(char *writebuf, void *readbuf, size_t len);
|
||||
|
||||
#endif /* __LIBSTROPHE_UTIL_H__ */
|
||||
|
||||
336
strophe.h
336
strophe.h
@@ -122,18 +122,22 @@ 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);
|
||||
typedef struct _xmpp_tlscert_t xmpp_tlscert_t;
|
||||
|
||||
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log);
|
||||
void xmpp_ctx_free(xmpp_ctx_t *ctx);
|
||||
|
||||
/* set the verbosity level of the ctx */
|
||||
void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level);
|
||||
|
||||
/* free some blocks returned by other APIs, for example the
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -146,10 +150,10 @@ typedef enum {
|
||||
|
||||
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;
|
||||
@@ -213,118 +217,159 @@ typedef enum {
|
||||
XMPP_SE_XML_NOT_WELL_FORMED
|
||||
} xmpp_error_type_t;
|
||||
|
||||
/** Certificate Elements
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
typedef enum {
|
||||
XMPP_CERT_VERSION, /**< X.509 Version */
|
||||
XMPP_CERT_SERIALNUMBER, /**< SerialNumber */
|
||||
XMPP_CERT_SUBJECT, /**< Subject */
|
||||
XMPP_CERT_ISSUER, /**< Issuer */
|
||||
XMPP_CERT_NOTBEFORE, /**< Issued on */
|
||||
XMPP_CERT_NOTAFTER, /**< Expires on */
|
||||
XMPP_CERT_KEYALG, /**< Public Key Algorithm */
|
||||
XMPP_CERT_SIGALG, /**< Certificate Signature Algorithm */
|
||||
XMPP_CERT_FINGERPRINT_SHA1, /**< Fingerprint SHA-1 */
|
||||
XMPP_CERT_FINGERPRINT_SHA256, /**< Fingerprint SHA-256 */
|
||||
XMPP_CERT_ELEMENT_MAX /**< Last element of the enum */
|
||||
} xmpp_cert_element_t;
|
||||
|
||||
typedef struct {
|
||||
xmpp_error_type_t type;
|
||||
char *text;
|
||||
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);
|
||||
/** The Handler function which will be called when the TLS stack can't
|
||||
* verify the authenticity of a Certificate that gets presented by
|
||||
* the server we're trying to connect to.
|
||||
*
|
||||
* When this function is called and details of the `cert` have to be
|
||||
* kept, please copy them yourself. The `cert` object will be free'd
|
||||
* automatically when this function returns.
|
||||
*
|
||||
* NB: `errormsg` is specific per certificate on OpenSSL and the same
|
||||
* for all certificates on GnuTLS.
|
||||
*
|
||||
* @param cert a Strophe certificate object
|
||||
* @param errormsg The error that caused this.
|
||||
*
|
||||
* @return 0 if the connection attempt should be terminated,
|
||||
* 1 if the connection should be established.
|
||||
*
|
||||
* @ingroup TLS
|
||||
*/
|
||||
typedef int (*xmpp_certfail_handler)(const xmpp_tlscert_t *cert,
|
||||
const char *const errormsg);
|
||||
|
||||
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);
|
||||
int xmpp_conn_is_connecting(xmpp_conn_t *const conn);
|
||||
int xmpp_conn_is_connected(xmpp_conn_t *const conn);
|
||||
int xmpp_conn_is_disconnected(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);
|
||||
|
||||
int xmpp_connect_client(xmpp_conn_t *const conn,
|
||||
const char *const altdomain,
|
||||
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_cafile(xmpp_conn_t *const conn, const char *path);
|
||||
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
|
||||
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
|
||||
xmpp_certfail_handler hndl);
|
||||
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
|
||||
void xmpp_conn_set_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 *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,
|
||||
int xmpp_connect_component(xmpp_conn_t *conn,
|
||||
const char *server,
|
||||
unsigned short port,
|
||||
xmpp_conn_handler callback,
|
||||
void *const userdata);
|
||||
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,
|
||||
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(xmpp_conn_t *conn, xmpp_stanza_t *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_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 handler returns false it is removed */
|
||||
typedef int (*xmpp_timed_handler)(xmpp_conn_t *const conn,
|
||||
void *const userdata);
|
||||
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_global_timed_handler)(xmpp_ctx_t *const ctx,
|
||||
void *const userdata);
|
||||
typedef int (*xmpp_global_timed_handler)(xmpp_ctx_t *ctx, void *userdata);
|
||||
|
||||
void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||
void xmpp_global_timed_handler_add(xmpp_ctx_t *ctx,
|
||||
xmpp_global_timed_handler handler,
|
||||
const unsigned long period,
|
||||
void *const userdata);
|
||||
void xmpp_global_timed_handler_delete(xmpp_ctx_t *const ctx,
|
||||
unsigned long period,
|
||||
void *userdata);
|
||||
void xmpp_global_timed_handler_delete(xmpp_ctx_t *ctx,
|
||||
xmpp_global_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_handler)(xmpp_conn_t *conn,
|
||||
xmpp_stanza_t *stanza,
|
||||
void *userdata);
|
||||
|
||||
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);
|
||||
void xmpp_handler_delete(xmpp_conn_t *const conn, xmpp_handler handler);
|
||||
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 *const conn,
|
||||
void xmpp_id_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 *id,
|
||||
void *userdata);
|
||||
void xmpp_id_handler_delete(xmpp_conn_t *conn,
|
||||
xmpp_handler handler,
|
||||
const char *const id);
|
||||
const char *id);
|
||||
|
||||
/*
|
||||
void xmpp_register_stanza_handler(conn, stanza, xmlns, type, handler)
|
||||
@@ -337,94 +382,88 @@ 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);
|
||||
|
||||
xmpp_ctx_t *xmpp_stanza_get_context(const 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 *const stanza);
|
||||
int xmpp_stanza_is_tag(xmpp_stanza_t *const 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_child_by_name_and_ns(xmpp_stanza_t *const stanza,
|
||||
const char *const name,
|
||||
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 *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_error(xmpp_stanza_t *const stanza,
|
||||
const char *const error_type,
|
||||
const char *const condition,
|
||||
const char *const text);
|
||||
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);
|
||||
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 */
|
||||
|
||||
@@ -440,10 +479,21 @@ 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);
|
||||
|
||||
/* TLS certificates */
|
||||
|
||||
xmpp_ctx_t *xmpp_tlscert_get_ctx(const xmpp_tlscert_t *cert);
|
||||
xmpp_conn_t *xmpp_tlscert_get_conn(const xmpp_tlscert_t *cert);
|
||||
const char *xmpp_tlscert_get_pem(const xmpp_tlscert_t *cert);
|
||||
const char *xmpp_tlscert_get_dnsname(const xmpp_tlscert_t *cert, size_t n);
|
||||
const char *xmpp_tlscert_get_string(const xmpp_tlscert_t *cert,
|
||||
xmpp_cert_element_t elmnt);
|
||||
const char *xmpp_tlscert_get_description(xmpp_cert_element_t elmnt);
|
||||
void xmpp_tlscert_free(xmpp_tlscert_t *cert);
|
||||
|
||||
/* UUID */
|
||||
|
||||
|
||||
16
tests/cert.pem
Normal file
16
tests/cert.pem
Normal 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-----
|
||||
5
tests/key.pem
Normal file
5
tests/key.pem
Normal file
@@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MF8CAQEEGF7SsbTSOjzb97nFc7Qbt4sic+1nZk+ETqAKBggqhkjOPQMBAaE0AzIA
|
||||
BI/tSR5cZ9iHCVw0JwmKLvV3TbxPg3kDdouB0R2WKEdEWwXMIHkE85RReISg+9/J
|
||||
DQ==
|
||||
-----END EC PRIVATE KEY-----
|
||||
@@ -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)
|
||||
|
||||
29
tests/test.h
29
tests/test.h
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "ostypes.h"
|
||||
|
||||
@@ -33,17 +34,17 @@
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
#define COMPARE(v1, v2) \
|
||||
do { \
|
||||
const char *__v1 = v1; \
|
||||
const char *__v2 = v2; \
|
||||
if (strcmp(__v1, __v2) != 0) { \
|
||||
printf("%s differs!\n" \
|
||||
"expected: %s\n" \
|
||||
"got: %s\n", \
|
||||
#v1, __v1, __v2); \
|
||||
exit(1); \
|
||||
} \
|
||||
#define COMPARE(v1, v2) \
|
||||
do { \
|
||||
const char *__v1 = v1; \
|
||||
const char *__v2 = v2; \
|
||||
if (strcmp(__v1, __v2) != 0) { \
|
||||
printf("Error: %s\n" \
|
||||
"Expected: %s\n" \
|
||||
"Got: %s\n", \
|
||||
#v1 " != " #v2, __v1, __v2); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define COMPARE_BUF(v1, len1, v2, len2) \
|
||||
@@ -53,9 +54,9 @@
|
||||
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)); \
|
||||
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)
|
||||
|
||||
@@ -22,7 +22,7 @@ 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;
|
||||
|
||||
@@ -30,7 +30,7 @@ void *my_alloc(const size_t size, void *const userdata)
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void my_free(void *p, void *const userdata)
|
||||
void my_free(void *p, void *userdata)
|
||||
{
|
||||
(void)userdata;
|
||||
|
||||
@@ -38,7 +38,7 @@ void my_free(void *p, void *const userdata)
|
||||
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;
|
||||
|
||||
@@ -46,10 +46,10 @@ void *my_realloc(void *p, const size_t size, void *const userdata)
|
||||
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)
|
||||
|
||||
49
tests/test_fuzz.c
Normal file
49
tests/test_fuzz.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "strophe.h"
|
||||
#include "parser.h"
|
||||
|
||||
void xmpp_initialize(void);
|
||||
|
||||
void cbtest_handle_start(char *name, char **attrs, void *userdata)
|
||||
{
|
||||
(void)name;
|
||||
(void)attrs;
|
||||
(void)userdata;
|
||||
}
|
||||
|
||||
void cbtest_handle_end(char *name, void *userdata)
|
||||
{
|
||||
(void)name;
|
||||
(void)userdata;
|
||||
}
|
||||
|
||||
void cbtest_handle_stanza(xmpp_stanza_t *stanza, void *userdata)
|
||||
{
|
||||
(void)stanza;
|
||||
(void)userdata;
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
||||
{
|
||||
xmpp_ctx_t *ctx;
|
||||
parser_t *parser;
|
||||
|
||||
char *dup = malloc(Size);
|
||||
memcpy(dup, Data, Size);
|
||||
|
||||
ctx = xmpp_ctx_new(NULL, NULL);
|
||||
parser = parser_new(ctx, cbtest_handle_start, cbtest_handle_end,
|
||||
cbtest_handle_stanza, NULL);
|
||||
|
||||
parser_feed(parser, dup, Size);
|
||||
|
||||
free(dup);
|
||||
parser_free(parser);
|
||||
xmpp_ctx_free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -21,19 +21,20 @@
|
||||
#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)
|
||||
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;
|
||||
@@ -41,6 +42,7 @@ int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
|
||||
(void)fmt;
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_SNPRINTF */
|
||||
|
||||
uint64_t time_stamp(void)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#define MAGICPTR ((void *)0xfeedbeef)
|
||||
static unsigned long used_blocks = 0;
|
||||
|
||||
@@ -107,9 +109,62 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
|
||||
assert(stanza != NULL);
|
||||
ret = xmpp_stanza_to_text(stanza, &buf, &buflen);
|
||||
assert(ret == XMPP_EOK);
|
||||
assert(strcmp(buf, str) == 0);
|
||||
COMPARE(str, buf);
|
||||
xmpp_free(ctx, buf);
|
||||
xmpp_stanza_release(stanza);
|
||||
|
||||
/* Error path. */
|
||||
stanza = xmpp_stanza_new_from_string(ctx, "<uu><uu>tt");
|
||||
assert(stanza == NULL);
|
||||
}
|
||||
|
||||
static void test_stanza_error(xmpp_ctx_t *ctx)
|
||||
{
|
||||
xmpp_stanza_t *stanza;
|
||||
xmpp_stanza_t *error;
|
||||
xmpp_stanza_t *item;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
const char *attr[10];
|
||||
int attrlen = ARRAY_SIZE(attr);
|
||||
int ret;
|
||||
|
||||
static const char *str =
|
||||
"<iq from='romeo@montague.lit/home' to='juliet@capulet.lit/chamber' "
|
||||
"type='get' id='e2e1'><ping xmlns='urn:xmpp:ping'/></iq>";
|
||||
static const char *str_error =
|
||||
"<error type=\"cancel\"><service-unavailable "
|
||||
"xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/></error>";
|
||||
|
||||
stanza = xmpp_stanza_new_from_string(ctx, str);
|
||||
assert(stanza != NULL);
|
||||
error =
|
||||
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
|
||||
assert(error != NULL);
|
||||
|
||||
assert(xmpp_stanza_get_to(error) != NULL);
|
||||
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));
|
||||
assert(xmpp_stanza_get_from(error) != NULL);
|
||||
COMPARE("juliet@capulet.lit/chamber", xmpp_stanza_get_from(error));
|
||||
assert(xmpp_stanza_get_id(error) != NULL);
|
||||
COMPARE("e2e1", xmpp_stanza_get_id(error));
|
||||
assert(xmpp_stanza_get_type(error) != NULL);
|
||||
COMPARE("error", xmpp_stanza_get_type(error));
|
||||
|
||||
ret = xmpp_stanza_get_attributes(error, attr, attrlen);
|
||||
/* attr contains both attribute name and value. */
|
||||
assert(ret == 8);
|
||||
|
||||
item = xmpp_stanza_get_child_by_name(error, "error");
|
||||
assert(item != NULL);
|
||||
|
||||
ret = xmpp_stanza_to_text(item, &buf, &buflen);
|
||||
assert(ret == XMPP_EOK);
|
||||
COMPARE(str_error, buf);
|
||||
|
||||
xmpp_free(ctx, buf);
|
||||
xmpp_stanza_release(stanza);
|
||||
xmpp_stanza_release(error);
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -122,6 +177,7 @@ int main()
|
||||
|
||||
test_stanza_add_child(ctx);
|
||||
test_stanza_from_string(ctx);
|
||||
test_stanza_error(ctx);
|
||||
|
||||
xmpp_ctx_free(ctx);
|
||||
xmpp_shutdown();
|
||||
|
||||
69
tests/test_xmppaddr.c
Normal file
69
tests/test_xmppaddr.c
Normal 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
14
travis/before_script.sh
Executable 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
|
||||
Reference in New Issue
Block a user