Skip to content

Commit

Permalink
First version of XEP-0138 support
Browse files Browse the repository at this point in the history
Signed-off-by: Steffen Jaeckel <[email protected]>
  • Loading branch information
sjaeckel committed Jan 26, 2024
1 parent bfd0872 commit 6e80fcd
Show file tree
Hide file tree
Showing 9 changed files with 419 additions and 65 deletions.
7 changes: 5 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ COVERAGE_POST=@COVERAGE_POST@
PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@

ZLIB_CFLAGS=@ZLIB_CFLAGS@
ZLIB_LIBS=@ZLIB_LIBS@

if TLS_WITH_GNUTLS
SSL_CFLAGS = @gnutls_CFLAGS@
SSL_LIBS = @gnutls_LIBS@
Expand All @@ -32,8 +35,8 @@ STROPHE_LIBS = $(COVERAGE_PRE) libstrophe.la $(COVERAGE_POST) $(COVERAGE_LDFLAGS
## Main build targets
lib_LTLIBRARIES = libstrophe.la

libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) -no-undefined
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) $(COVERAGE_CFLAGS) $(ZLIB_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) $(MINGW_LIBS) $(ZLIB_LIBS) -no-undefined
# Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' -version-info @VERSION_INFO@

Expand Down
16 changes: 16 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
AC_ARG_ENABLE([getrandom],
[AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])])
AC_ARG_ENABLE([zlib],
[AS_HELP_STRING([--disable-zlib], [disable compression support])])

AC_ARG_ENABLE([fuzzing],
[AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])],
Expand Down Expand Up @@ -247,6 +249,18 @@ fi

fi

if test "x$enable_zlib" != xno; then
PKG_CHECK_MODULES([zlib], [zlib >= 1.2.0],
[
PC_REQUIRES="libzlib ${PC_REQUIRES}"
ZLIB_CFLAGS=$zlib_CFLAGS
ZLIB_LIBS=$zlib_LIBS
AC_DEFINE([HAVE_ZLIB])
],
[AC_MSG_ERROR([zlib not found])])
# TODO: if pkg-config doesn't find, check the library manually
fi

m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir],
Expand Down Expand Up @@ -290,5 +304,7 @@ AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS)
AC_SUBST(WARNING_FLAGS)
AC_SUBST(ZLIB_CFLAGS)
AC_SUBST(ZLIB_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT
9 changes: 8 additions & 1 deletion examples/bot.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ static void usage(int exit_code)
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
"--legacy-ssl\n");
"--legacy-ssl\n"
" --zlib Enable compression via zlib.\n"
" --dont-flush When using zlib, don't flush after "
"compression.\n");

exit(exit_code);
}
Expand Down Expand Up @@ -244,6 +247,10 @@ 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], "--zlib") == 0)
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
else if (strcmp(argv[i], "--dont-flush") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH;
else if ((strcmp(argv[i], "--jid") == 0) && (++i < argc))
jid = argv[i];
else if ((strcmp(argv[i], "--pass") == 0) && (++i < argc))
Expand Down
7 changes: 7 additions & 0 deletions examples/complex.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ static void usage(int exit_code)
" --enable-certfail Enable certfail handler.\n"
" --legacy-ssl Use old style SSL.\n"
" --legacy-auth Allow legacy authentication.\n"
" --zlib Enable compression via zlib.\n"
" --dont-flush When using zlib, don't flush after "
"compression.\n"
" --verbose Increase the verbosity level.\n"
" --tcp-keepalive Configure TCP keepalive.\n\n"
"Note: --disable-tls conflicts with --mandatory-tls or "
Expand Down Expand Up @@ -273,6 +276,10 @@ 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], "--zlib") == 0)
flags |= XMPP_CONN_FLAG_ENABLE_COMPRESSION;
else if (strcmp(argv[i], "--dont-flush") == 0)
flags |= XMPP_CONN_FLAG_COMPRESSION_DONT_FLUSH;
else if (strcmp(argv[i], "--verbose") == 0)
verbosity++;
else if (strcmp(argv[i], "--tcp-keepalive") == 0)
Expand Down
166 changes: 127 additions & 39 deletions src/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@

static void _auth(xmpp_conn_t *conn);
static void _auth_legacy(xmpp_conn_t *conn);
static void _handle_open_compress(xmpp_conn_t *conn);
static void _handle_open_sasl(xmpp_conn_t *conn);
static void _handle_open_tls(xmpp_conn_t *conn);

Expand All @@ -72,6 +73,9 @@ static int _handle_component_hs_response(xmpp_conn_t *conn,

static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata);
static int _handle_features_compress(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,
Expand Down Expand Up @@ -207,10 +211,61 @@ static int _handle_missing_features(xmpp_conn_t *conn, void *userdata)
return 0;
}

typedef void (*text_handler)(xmpp_conn_t *conn, const char *text);
static void _foreach_child(xmpp_conn_t *conn,
xmpp_stanza_t *parent,
const char *name,
text_handler hndl)
{
xmpp_stanza_t *children;
for (children = xmpp_stanza_get_children(parent); children;
children = xmpp_stanza_get_next(children)) {
const char *child_name = xmpp_stanza_get_name(children);
if (child_name && strcmp(child_name, name) == 0) {
char *text = xmpp_stanza_get_text(children);
if (text == NULL)
continue;

hndl(conn, text);

strophe_free(conn->ctx, text);
}
}
}

static void _handle_sasl_children(xmpp_conn_t *conn, const char *text)
{
if (strcasecmp(text, "PLAIN") == 0) {
conn->sasl_support |= SASL_MASK_PLAIN;
} else if (strcasecmp(text, "EXTERNAL") == 0 &&
(conn->tls_client_cert || conn->tls_client_key)) {
conn->sasl_support |= SASL_MASK_EXTERNAL;
} else if (strcasecmp(text, "DIGEST-MD5") == 0) {
conn->sasl_support |= SASL_MASK_DIGESTMD5;
} else if (strcasecmp(text, "ANONYMOUS") == 0) {
conn->sasl_support |= SASL_MASK_ANONYMOUS;
} else {
size_t n;
for (n = 0; n < scram_algs_num; ++n) {
if (strcasecmp(text, scram_algs[n]->scram_name) == 0) {
conn->sasl_support |= scram_algs[n]->mask;
break;
}
}
}
}

static void _handle_compression_children(xmpp_conn_t *conn, const char *text)
{
if (strcasecmp(text, "zlib") == 0) {
conn->compression_supported = 1;
}
}

static int
_handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
xmpp_stanza_t *child, *mech;
xmpp_stanza_t *child, *children;
const char *ns;
char *text;

Expand All @@ -222,56 +277,33 @@ _handle_features(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
/* check for TLS */
if (!conn->secured) {
if (!conn->tls_disabled) {
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
if (child) {
ns = xmpp_stanza_get_ns(child);
conn->tls_support = ns != NULL && strcmp(ns, XMPP_NS_TLS) == 0;
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "starttls",
XMPP_NS_TLS)) {
conn->tls_support = 1;
}
} else {
conn->tls_support = 0;
}
}

/* check for SASL */
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
ns = child ? xmpp_stanza_get_ns(child) : NULL;
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) {
for (mech = xmpp_stanza_get_children(child); mech;
mech = xmpp_stanza_get_next(mech)) {
if (xmpp_stanza_get_name(mech) &&
strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
text = xmpp_stanza_get_text(mech);
if (text == NULL)
continue;

if (strcasecmp(text, "PLAIN") == 0) {
conn->sasl_support |= SASL_MASK_PLAIN;
} else if (strcasecmp(text, "EXTERNAL") == 0 &&
(conn->tls_client_cert || conn->tls_client_key)) {
conn->sasl_support |= SASL_MASK_EXTERNAL;
} else if (strcasecmp(text, "DIGEST-MD5") == 0) {
conn->sasl_support |= SASL_MASK_DIGESTMD5;
} else if (strcasecmp(text, "ANONYMOUS") == 0) {
conn->sasl_support |= SASL_MASK_ANONYMOUS;
} else {
size_t n;
for (n = 0; n < scram_algs_num; ++n) {
if (strcasecmp(text, scram_algs[n]->scram_name) == 0) {
conn->sasl_support |= scram_algs[n]->mask;
break;
}
}
}

strophe_free(conn->ctx, text);
}
}
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "mechanisms",
XMPP_NS_SASL);
if (child) {
_foreach_child(conn, child, "mechanism", _handle_sasl_children);
}

/* Disable PLAIN when other secure mechanisms are supported */
if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
conn->sasl_support &= ~SASL_MASK_PLAIN;

/* check for compression */
child = xmpp_stanza_get_child_by_name_and_ns(stanza, "compression",
XMPP_NS_COMPRESSION);
if (conn->compression_allowed && child) {
_foreach_child(conn, child, "method", _handle_compression_children);
}

_auth(conn);

return 0;
Expand Down Expand Up @@ -339,7 +371,9 @@ _handle_sasl_result(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
(char *)userdata);

/* reset parser */
conn_prepare_reset(conn, _handle_open_sasl);
conn_prepare_reset(conn, conn->compression_allowed
? _handle_open_compress
: _handle_open_sasl);

/* send stream tag */
conn_open_stream(conn);
Expand Down Expand Up @@ -950,6 +984,17 @@ static void _handle_open_sasl(xmpp_conn_t *conn)
NULL);
}

/* called when stream:stream tag received after compression has been enabled */
static void _handle_open_compress(xmpp_conn_t *conn)
{
strophe_debug(conn->ctx, "xmpp", "Reopened stream successfully.");

/* setup stream:features handlers */
handler_add(conn, _handle_features_compress, XMPP_NS_STREAMS, "features",
NULL, NULL);
handler_add_timed(conn, _handle_missing_features, FEATURES_TIMEOUT, NULL);
}

static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
{
xmpp_stanza_t *iq, *res, *text;
Expand Down Expand Up @@ -1006,6 +1051,49 @@ static int _do_bind(xmpp_conn_t *conn, xmpp_stanza_t *bind)
return 0;
}

static int _handle_compress_result(xmpp_conn_t *const conn,
xmpp_stanza_t *const stanza,
void *const userdata)
{
const char *name = xmpp_stanza_get_name(stanza);

if (!name)
return 0;
if (strcmp(name, "compressed") == 0) {
/* Stream compression enabled, we need to restart the stream */
strophe_debug(conn->ctx, "xmpp", "Stream compression enabled");

/* reset parser */
conn_prepare_reset(conn, _handle_open_sasl);

/* make compression effective */
conn->compress = 1;

/* send stream tag */
conn_open_stream(conn);
}
return 0;
}

static int _handle_features_compress(xmpp_conn_t *conn,
xmpp_stanza_t *stanza,
void *userdata)
{
const char *compress = "<compress xmlns='" XMPP_NS_COMPRESSION
"'><method>zlib</method></compress>";

UNUSED(userdata);

/* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features);

send_raw(conn, compress, strlen(compress), XMPP_QUEUE_STROPHE, NULL);
handler_add(conn, _handle_compress_result, XMPP_NS_COMPRESSION, NULL, NULL,
NULL);

return 0;
}

static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
Expand Down
8 changes: 8 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <stdio.h>
#include <stdarg.h>
#include <zlib.h>

#include "strophe.h"
#include "ostypes.h"
Expand Down Expand Up @@ -249,6 +250,13 @@ struct _xmpp_conn_t {
int sm_disable;
xmpp_sm_state_t *sm_state;

int compression_allowed, compression_supported;
int compress, compression_dont_flush;
struct zlib_compression {
void *buffer, *buffer_end;
z_stream stream;
} compression, decompression;

char *lang;
char *domain;
char *jid;
Expand Down
Loading

0 comments on commit 6e80fcd

Please sign in to comment.