1 Commits

Author SHA1 Message Date
Dmitry Podgorny
9dfe01bf83 WIP examples: PLAIN auth mechanism over raw connection 2017-07-15 21:38:46 +03:00
31 changed files with 783 additions and 1028 deletions

1
.gitignore vendored
View File

@@ -34,6 +34,7 @@ examples/active
examples/basic examples/basic
examples/bot examples/bot
examples/component examples/component
examples/ext_auth
examples/roster examples/roster
examples/uuid examples/uuid
examples/vcard examples/vcard

View File

@@ -1,15 +1,15 @@
language: c language: c
install: install:
- sudo apt-get update - sudo apt-get update
- sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev libc-ares-dev - sudo apt-get -y install libtool pkg-config libexpat1-dev libxml2-dev libssl-dev check
before_script: before_script:
- ./bootstrap.sh - ./bootstrap.sh
script: script:
- ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check - ./configure ${CONFIGURE_OPT} && make && make check-TESTS
env: env:
- CONFIGURE_OPT="--without-libxml2" - CONFIGURE_OPT="--without-libxml2"
- CONFIGURE_OPT="--with-libxml2" - CONFIGURE_OPT="--with-libxml2"
- CONFIGURE_OPT="--disable-tls" - CONFIGURE_OPT="--disable-tls --without-libxml2"
- CONFIGURE_OPT="--enable-cares" - CONFIGURE_OPT="--disable-tls --with-libxml2"
matrix: matrix:
fast_finish: true fast_finish: true

View File

@@ -1,12 +1,3 @@
0.9.3
- PLAIN mechanism is used only when no other mechanisms are supported
- Legacy authentication is disabled by default, can be enabled with
connection flag XMPP_CONN_FLAG_LEGACY_AUTH
- Session is not established if it is optional
- Fixed a bug causing a reused connection not to cleanup properly
- Improved debug logging in OpenSSL module
- Few memory leaks fixed
0.9.2 0.9.2
- OpenSSL tls module verifies certificate by default. Set flag - OpenSSL tls module verifies certificate by default. Set flag
XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification XMPP_CONN_FLAG_TRUST_TLS to ignore result of the verification
@@ -17,12 +8,7 @@
userdata userdata
- System handlers are deleted on xmpp_conn_t reconnection. Old system - System handlers are deleted on xmpp_conn_t reconnection. Old system
handlers could cause problems handlers could cause problems
- Default timeout for xmpp_run() is increased from 1 millisecond to 1
second in order to reduce CPU consumption
- Reduced memory usage in expat module
- New functions: - New functions:
- xmpp_error_new()
- xmpp_send_error()
- xmpp_ctx_set_timeout() - xmpp_ctx_set_timeout()
- xmpp_sha1_digest() - xmpp_sha1_digest()

View File

@@ -1,6 +1,7 @@
AUTOMAKE_OPTIONS = subdir-objects AUTOMAKE_OPTIONS = subdir-objects
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -g -Wall
PARSER_CFLAGS=@PARSER_CFLAGS@ PARSER_CFLAGS=@PARSER_CFLAGS@
PARSER_LIBS=@PARSER_LIBS@ PARSER_LIBS=@PARSER_LIBS@
@@ -8,16 +9,15 @@ PARSER_LIBS=@PARSER_LIBS@
SSL_CFLAGS = @openssl_CFLAGS@ SSL_CFLAGS = @openssl_CFLAGS@
SSL_LIBS = @openssl_LIBS@ SSL_LIBS = @openssl_LIBS@
RESOLV_CFLAGS = @RESOLV_CFLAGS@
RESOLV_LIBS = @RESOLV_LIBS@ RESOLV_LIBS = @RESOLV_LIBS@
STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Wno-unused-parameter STROPHE_FLAGS = -I$(top_srcdir) -Wall -Wextra -Werror -Wno-unused-parameter
STROPHE_LIBS = libstrophe.la STROPHE_LIBS = libstrophe.la
## Main build targets ## Main build targets
lib_LTLIBRARIES = libstrophe.la lib_LTLIBRARIES = libstrophe.la
libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS) $(RESOLV_CFLAGS) libstrophe_la_CFLAGS = $(SSL_CFLAGS) $(STROPHE_FLAGS) $(PARSER_CFLAGS)
libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined libstrophe_la_LDFLAGS = $(SSL_LIBS) $(PARSER_LIBS) $(RESOLV_LIBS) -no-undefined
# Export only public API # Export only public API
libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_' libstrophe_la_LDFLAGS += -export-symbols-regex '^xmpp_'
@@ -98,6 +98,7 @@ noinst_PROGRAMS = \
examples/basic \ examples/basic \
examples/bot \ examples/bot \
examples/component \ examples/component \
examples/ext_auth \
examples/roster \ examples/roster \
examples/uuid \ examples/uuid \
examples/vcard examples/vcard
@@ -114,6 +115,9 @@ examples_bot_LDADD = $(STROPHE_LIBS)
examples_component_SOURCES = examples/component.c examples_component_SOURCES = examples/component.c
examples_component_CFLAGS = $(STROPHE_FLAGS) examples_component_CFLAGS = $(STROPHE_FLAGS)
examples_component_LDADD = $(STROPHE_LIBS) examples_component_LDADD = $(STROPHE_LIBS)
examples_ext_auth_SOURCES = examples/ext_auth.c
examples_ext_auth_CFLAGS = $(STROPHE_FLAGS)
examples_ext_auth_LDADD = $(STROPHE_LIBS)
examples_roster_SOURCES = examples/roster.c examples_roster_SOURCES = examples/roster.c
examples_roster_CFLAGS = $(STROPHE_FLAGS) examples_roster_CFLAGS = $(STROPHE_FLAGS)
examples_roster_LDADD = $(STROPHE_LIBS) examples_roster_LDADD = $(STROPHE_LIBS)

View File

@@ -1,4 +1,4 @@
AC_INIT([libstrophe], [0.9.3], [jack@metajack.im]) AC_INIT([libstrophe], [0.9.1], [jack@metajack.im])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
LT_INIT([dlopen]) LT_INIT([dlopen])
@@ -21,8 +21,6 @@ AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])]) [AS_HELP_STRING([--with-libxml2], [use libxml2 for XML parsing, expat is the default])])
AC_ARG_ENABLE([tls], AC_ARG_ENABLE([tls],
[AS_HELP_STRING([--disable-tls], [disable TLS support])]) [AS_HELP_STRING([--disable-tls], [disable TLS support])])
AC_ARG_ENABLE([cares],
[AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])])
if test "x$enable_tls" != xno; then if test "x$enable_tls" != xno; then
PKG_CHECK_MODULES([openssl], [openssl], PKG_CHECK_MODULES([openssl], [openssl],
@@ -86,18 +84,6 @@ AC_MSG_NOTICE([libstrophe will use the $with_parser XML parser])
AC_SEARCH_LIBS([socket], [socket]) AC_SEARCH_LIBS([socket], [socket])
if test "x$enable_cares" = xyes; then
PKG_CHECK_MODULES([libcares], [libcares >= 1.7.0],
[
PC_REQUIRES="libcares ${PC_REQUIRES}"
RESOLV_CFLAGS=$libcares_CFLAGS
RESOLV_LIBS=$libcares_LIBS
AC_DEFINE([HAVE_CARES])
],
[AC_MSG_ERROR([libcares not found])])
# TODO: if pkg-config doesn't find, check the library manually
else
AS_CASE([$PLATFORM], AS_CASE([$PLATFORM],
[bsd], [RESOLV_LIBS=""], [bsd], [RESOLV_LIBS=""],
[qnx], [RESOLV_LIBS="-lsocket"], [qnx], [RESOLV_LIBS="-lsocket"],
@@ -124,8 +110,6 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
LIBS="${LIBS_TMP}" LIBS="${LIBS_TMP}"
PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}" PC_LIBS="${RESOLV_LIBS} ${PC_LIBS}"
fi
m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR], m4_ifdef([PKG_INSTALLDIR], [PKG_INSTALLDIR],
[AC_ARG_WITH([pkgconfigdir], [AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir],
@@ -142,7 +126,6 @@ AC_SUBST([PC_LIBS], [${PC_LIBS}])
AC_SUBST(PARSER_CFLAGS) AC_SUBST(PARSER_CFLAGS)
AC_SUBST(PARSER_LIBS) AC_SUBST(PARSER_LIBS)
AC_SUBST(RESOLV_CFLAGS)
AC_SUBST(RESOLV_LIBS) AC_SUBST(RESOLV_LIBS)
AC_CONFIG_FILES([Makefile libstrophe.pc]) AC_CONFIG_FILES([Makefile libstrophe.pc])
AC_OUTPUT AC_OUTPUT

290
examples/ext_auth.c Normal file
View File

@@ -0,0 +1,290 @@
/* ext_auth.c
* strophe XMPP client library -- PLAIN mechanism example with a raw connection
*
* Copyright (C) 2016 Dmitry Podgorny <pasis.ua@gmail.com>
*
* This software is provided AS-IS with no warranty, either express
* or implied.
*
* This program is dual licensed under the MIT and GPLv3 licenses.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strophe.h>
typedef struct {
xmpp_ctx_t *ctx;
const char *jid;
const char *pass;
char *domain;
int authenticated;
} xmpp_auth_t;
#define FEATURES_TIMEOUT 5000 /* 5 seconds */
static int _handle_error(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
fprintf(stderr, "DEBUG: received stream error\n");
xmpp_disconnect(conn);
return 0;
}
static int _handle_proceedtls_default(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
const char *name = xmpp_stanza_get_name(stanza);
(void)auth;
if (strcmp(name, "proceed") == 0) {
if (xmpp_conn_tls_start(conn) == 0) {
xmpp_handler_delete(conn, _handle_error);
xmpp_conn_open_stream_default(conn);
} else {
/* failed tls spoils the connection, so disconnect */
xmpp_disconnect(conn);
}
} else
xmpp_disconnect(conn);
return 0;
}
static int _plain_mechanim_exists(xmpp_ctx_t *ctx, xmpp_stanza_t *features)
{
xmpp_stanza_t *mechanisms;
xmpp_stanza_t *child;
char *text;
int found = 0;
mechanisms = xmpp_stanza_get_child_by_name(features, "mechanisms");
child = mechanisms ? xmpp_stanza_get_children(mechanisms) : NULL;
while (!found && mechanisms && child) {
/* TODO xmpp_stanza_get_name(child) is "mechanism" */
text = xmpp_stanza_get_text(child);
found = text && strcmp(text, "PLAIN") == 0;
xmpp_free(ctx, text);
child = xmpp_stanza_get_next(child);
}
return found;
}
static char *_plain_mechanism_authdata(xmpp_auth_t *auth)
{
char *node, *b64;
unsigned char *msg;
size_t node_len, pass_len;
node = xmpp_jid_node(auth->ctx, auth->jid);
node_len = strlen(node);
pass_len = strlen(auth->pass);
msg = malloc(node_len + pass_len + 2);
msg[0] = '\0';
memcpy(msg + 1, node, node_len);
msg[node_len + 1] = '\0';
memcpy(msg + node_len + 2, auth->pass, pass_len);
b64 = xmpp_base64_encode(auth->ctx, msg, node_len + pass_len + 2);
free(msg);
xmpp_free(auth->ctx, node);
return b64;
}
static int _plain_mechanism_handle_result(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
const char *name;
name = xmpp_stanza_get_name(stanza);
if (strcmp(name, "success") == 0) {
/* SASL PLAIN auth successful, we need to restart the stream */
fprintf(stderr, "DEBUG: SASL PLAIN auth successful\n");
auth->authenticated = 1;
xmpp_handler_delete(conn, _handle_error);
xmpp_conn_open_stream_default(conn);
} else {
fprintf(stderr, "DEBUG: SASL authentication failed: %s\n", name);
xmpp_disconnect(conn);
}
return 0;
}
static int _handle_missing_features(xmpp_conn_t * const conn,
void * const userdata)
{
fprintf(stderr, "DEBUG: timeout\n");
xmpp_disconnect(conn);
return 0;
}
static int _handle_features(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
xmpp_ctx_t *ctx = auth->ctx;
xmpp_stanza_t *plain, *child;
char *str;
xmpp_timed_handler_delete(conn, _handle_missing_features);
if (auth->authenticated) {
/* after successful SASL authentication */
/* TODO bind, session and we'are done */
xmpp_disconnect(conn); /* XXX */
return 0;
}
/* secure connection if possible */
child = xmpp_stanza_get_child_by_name(stanza, "starttls");
if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0)) {
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(child, "starttls");
xmpp_stanza_set_ns(child, XMPP_NS_TLS);
xmpp_handler_add(conn, _handle_proceedtls_default,
XMPP_NS_TLS, NULL, NULL, userdata);
xmpp_send(conn, child);
xmpp_stanza_release(child);
return 0;
}
/* check if PLAIN mechanism is supported */
if (!_plain_mechanim_exists(ctx, stanza)) {
fprintf(stderr, "DEBUG: PLAIN mechanism is NOT supported\n");
xmpp_disconnect(conn);
return 0;
}
/* perform authentication */
plain = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(plain, "auth");
xmpp_stanza_set_ns(plain, XMPP_NS_SASL);
xmpp_stanza_set_attribute(plain, "mechanism", "PLAIN");
str = _plain_mechanism_authdata(auth);
child = xmpp_stanza_new(ctx);
xmpp_stanza_set_text(child, str);
xmpp_free(ctx, str);
xmpp_stanza_add_child(plain, child);
xmpp_stanza_release(child);
xmpp_handler_add(conn, _plain_mechanism_handle_result,
XMPP_NS_SASL, NULL, NULL, userdata);
xmpp_send(conn, plain);
xmpp_stanza_release(plain);
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)
{
xmpp_auth_t *auth = (xmpp_auth_t *)userdata;
xmpp_ctx_t *ctx = auth->ctx;
int secured;
if (status == XMPP_CONN_RAW_CONNECT) {
fprintf(stderr, "DEBUG: raw connection established\n");
xmpp_conn_open_stream_default(conn);
} else if (status == XMPP_CONN_CONNECT) {
fprintf(stderr, "DEBUG: stream opened\n");
secured = xmpp_conn_is_secured(conn);
fprintf(stderr, "DEBUG: connection is %s.\n",
secured ? "secured" : "NOT secured");
/* setup handler for stream:error */
xmpp_handler_add(conn, _handle_error, XMPP_NS_STREAMS,
"error", NULL, NULL);
/* setup handlers for incoming <stream:features> */
xmpp_handler_add(conn, _handle_features, XMPP_NS_STREAMS,
"features", NULL, auth);
xmpp_timed_handler_add(conn, _handle_missing_features,
FEATURES_TIMEOUT, NULL);
} else {
fprintf(stderr, "DEBUG: disconnected\n");
xmpp_stop(ctx);
}
}
static xmpp_auth_t *xmpp_auth_new(void)
{
xmpp_auth_t *auth;
auth = malloc(sizeof(*auth));
if (auth != NULL) {
memset(auth, 0, sizeof(*auth));
}
return auth;
}
static void xmpp_auth_release(xmpp_auth_t *auth)
{
free(auth);
}
int main(int argc, char **argv)
{
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
xmpp_log_t *log;
xmpp_auth_t *auth;
const char *jid;
const char *pass;
const char *host = NULL;
if (argc < 3 || argc > 4) {
fprintf(stderr, "Usage: %s <jid> <pass> [<host>]\n", argv[0]);
return 1;
}
jid = argv[1];
pass = argv[2];
if (argc > 3)
host = argv[3];
/*
* Note, this example doesn't handle errors. Applications should check
* return values of non-void functions.
*/
xmpp_initialize();
log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx);
xmpp_conn_set_jid(conn, jid);
/* private data */
auth = xmpp_auth_new();
auth->ctx = ctx;
auth->jid = jid;
auth->pass = pass;
auth->domain = xmpp_jid_domain(ctx, jid);
xmpp_connect_raw(conn, host, 0, conn_handler, auth);
xmpp_run(ctx);
/* release private data */
xmpp_auth_release(auth);
xmpp_conn_release(conn);
xmpp_ctx_free(ctx);
xmpp_shutdown();
return 0;
}

View File

@@ -62,7 +62,7 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := libexpat LOCAL_MODULE := libexpat
LOCAL_CFLAGS := -DHAVE_MEMMOVE -DXML_DEV_URANDOM LOCAL_CFLAGS := -DHAVE_MEMMOVE
#LOCAL_C_INCLUDES := \ #LOCAL_C_INCLUDES := \
# $(LOCAL_PATH)/expat # $(LOCAL_PATH)/expat

View File

@@ -1,2 +1,2 @@
APP_ABI := armeabi-v7a arm64-v8a APP_ABI := armeabi armeabi-v7a mips x86
APP_PLATFORM := android-19 APP_PLATFORM := android-19

View File

@@ -61,7 +61,6 @@
#endif #endif
static void _auth(xmpp_conn_t * const conn); static void _auth(xmpp_conn_t * const conn);
static void _auth_legacy(xmpp_conn_t *conn);
static void _handle_open_sasl(xmpp_conn_t * const 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_tls(xmpp_conn_t * const conn);
@@ -70,6 +69,11 @@ static int _handle_component_hs_response(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata); void * const userdata);
static int _handle_missing_legacy(xmpp_conn_t * const conn,
void * const userdata);
static int _handle_legacy(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza,
void * const userdata);
static int _handle_features_sasl(xmpp_conn_t * const conn, static int _handle_features_sasl(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata); void * const userdata);
@@ -215,7 +219,6 @@ static int _handle_features(xmpp_conn_t * const conn,
void * const userdata) void * const userdata)
{ {
xmpp_stanza_t *child, *mech; xmpp_stanza_t *child, *mech;
const char *ns;
char *text; char *text;
/* remove the handler that detects missing stream:features */ /* remove the handler that detects missing stream:features */
@@ -225,10 +228,8 @@ static int _handle_features(xmpp_conn_t * const conn,
if (!conn->secured) { if (!conn->secured) {
if (!conn->tls_disabled) { if (!conn->tls_disabled) {
child = xmpp_stanza_get_child_by_name(stanza, "starttls"); child = xmpp_stanza_get_child_by_name(stanza, "starttls");
if (child) { if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_TLS) == 0))
ns = xmpp_stanza_get_ns(child); conn->tls_support = 1;
conn->tls_support = ns != NULL && strcmp(ns, XMPP_NS_TLS) == 0;
}
} else { } else {
conn->tls_support = 0; conn->tls_support = 0;
} }
@@ -236,15 +237,11 @@ static int _handle_features(xmpp_conn_t * const conn,
/* check for SASL */ /* check for SASL */
child = xmpp_stanza_get_child_by_name(stanza, "mechanisms"); child = xmpp_stanza_get_child_by_name(stanza, "mechanisms");
ns = child ? xmpp_stanza_get_ns(child) : NULL; if (child && (strcmp(xmpp_stanza_get_ns(child), XMPP_NS_SASL) == 0)) {
if (child && ns && strcmp(ns, XMPP_NS_SASL) == 0) {
for (mech = xmpp_stanza_get_children(child); mech; for (mech = xmpp_stanza_get_children(child); mech;
mech = xmpp_stanza_get_next(mech)) { mech = xmpp_stanza_get_next(mech)) {
if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) { if (xmpp_stanza_get_name(mech) && strcmp(xmpp_stanza_get_name(mech), "mechanism") == 0) {
text = xmpp_stanza_get_text(mech); text = xmpp_stanza_get_text(mech);
if (text == NULL)
continue;
if (strcasecmp(text, "PLAIN") == 0) if (strcasecmp(text, "PLAIN") == 0)
conn->sasl_support |= SASL_MASK_PLAIN; conn->sasl_support |= SASL_MASK_PLAIN;
else if (strcasecmp(text, "DIGEST-MD5") == 0) else if (strcasecmp(text, "DIGEST-MD5") == 0)
@@ -259,10 +256,6 @@ static int _handle_features(xmpp_conn_t * const conn,
} }
} }
/* Disable PLAIN when other secure mechanisms are supported */
if (conn->sasl_support & ~(SASL_MASK_PLAIN | SASL_MASK_ANONYMOUS))
conn->sasl_support &= ~SASL_MASK_PLAIN;
_auth(conn); _auth(conn);
return 0; return 0;
@@ -557,11 +550,9 @@ static xmpp_stanza_t *_make_sasl_auth(xmpp_conn_t * const conn,
*/ */
static void _auth(xmpp_conn_t * const conn) static void _auth(xmpp_conn_t * const conn)
{ {
xmpp_stanza_t *auth; xmpp_stanza_t *auth, *authdata, *query, *child, *iq;
xmpp_stanza_t *authdata; char *str, *authid;
char *authid;
char *scram_init; char *scram_init;
char *str;
int anonjid; int anonjid;
/* if there is no node in conn->jid, we assume anonymous connect */ /* if there is no node in conn->jid, we assume anonymous connect */
@@ -728,12 +719,105 @@ static void _auth(xmpp_conn_t * const conn)
/* SASL PLAIN was tried */ /* SASL PLAIN was tried */
conn->sasl_support &= ~SASL_MASK_PLAIN; conn->sasl_support &= ~SASL_MASK_PLAIN;
} else if (conn->type == XMPP_CLIENT && conn->auth_legacy_enabled) { } else if (conn->type == XMPP_CLIENT) {
/* legacy client authentication */ /* legacy client authentication */
_auth_legacy(conn);
} else { iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
xmpp_error(conn->ctx, "auth", "Cannot authenticate with known methods"); if (!iq) {
xmpp_disconnect(conn); disconnect_mem_error(conn);
return;
}
query = xmpp_stanza_new(conn->ctx);
if (!query) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
child = xmpp_stanza_new(conn->ctx);
if (!child) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(child, "username");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
str = xmpp_jid_node(conn->ctx, conn->jid);
xmpp_stanza_set_text(authdata, str);
xmpp_free(conn->ctx, str);
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
child = xmpp_stanza_new(conn->ctx);
if (!child) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(child, "password");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_text(authdata, conn->pass);
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
child = xmpp_stanza_new(conn->ctx);
if (!child) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(child, "resource");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
str = xmpp_jid_resource(conn->ctx, conn->jid);
if (str) {
xmpp_stanza_set_text(authdata, str);
xmpp_free(conn->ctx, str);
} else {
xmpp_stanza_release(authdata);
xmpp_stanza_release(iq);
xmpp_error(conn->ctx, "auth",
"Cannot authenticate without resource");
xmpp_disconnect(conn);
return;
}
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
handler_add_timed(conn, _handle_missing_legacy,
LEGACY_TIMEOUT, NULL);
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
} }
} }
@@ -787,8 +871,7 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
{ {
xmpp_stanza_t *bind, *session, *iq, *res, *text, *opt; xmpp_stanza_t *bind, *session, *iq, *res, *text;
const char *ns;
char *resource; char *resource;
/* remove missing features handler */ /* remove missing features handler */
@@ -797,21 +880,16 @@ static int _handle_features_sasl(xmpp_conn_t * const conn,
/* we are expecting <bind/> and <session/> since this is a /* we are expecting <bind/> and <session/> since this is a
XMPP style connection */ XMPP style connection */
/* check whether resource binding is required */
bind = xmpp_stanza_get_child_by_name(stanza, "bind"); bind = xmpp_stanza_get_child_by_name(stanza, "bind");
if (bind) { if (bind && strcmp(xmpp_stanza_get_ns(bind), XMPP_NS_BIND) == 0) {
ns = xmpp_stanza_get_ns(bind); /* resource binding is required */
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0; conn->bind_required = 1;
} }
/* check whether session establishment is required */
session = xmpp_stanza_get_child_by_name(stanza, "session"); session = xmpp_stanza_get_child_by_name(stanza, "session");
if (session) { if (session && strcmp(xmpp_stanza_get_ns(session), XMPP_NS_SESSION) == 0) {
ns = xmpp_stanza_get_ns(session); /* session establishment required */
opt = xmpp_stanza_get_child_by_name(session, "optional"); conn->session_required = 1;
if (!opt)
conn->session_required = ns != NULL &&
strcmp(ns, XMPP_NS_SESSION) == 0;
} }
/* if bind is required, go ahead and start it */ /* if bind is required, go ahead and start it */
@@ -1014,15 +1092,6 @@ static int _handle_missing_session(xmpp_conn_t * const conn,
return 0; return 0;
} }
static int _handle_missing_legacy(xmpp_conn_t * const conn,
void * const userdata)
{
xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
"authentication request.");
xmpp_disconnect(conn);
return 0;
}
static int _handle_legacy(xmpp_conn_t * const conn, static int _handle_legacy(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, xmpp_stanza_t * const stanza,
void * const userdata) void * const userdata)
@@ -1059,97 +1128,13 @@ static int _handle_legacy(xmpp_conn_t * const conn,
return 0; return 0;
} }
static void _auth_legacy(xmpp_conn_t *conn) static int _handle_missing_legacy(xmpp_conn_t * const conn,
void * const userdata)
{ {
xmpp_stanza_t *iq; xmpp_error(conn->ctx, "xmpp", "Server did not reply to legacy "\
xmpp_stanza_t *authdata; "authentication request.");
xmpp_stanza_t *query; xmpp_disconnect(conn);
xmpp_stanza_t *child; return 0;
char *str;
xmpp_debug(conn->ctx, "auth", "Legacy authentication request");
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_auth1");
if (!iq)
goto err;
query = xmpp_stanza_new(conn->ctx);
if (!query)
goto err_free;
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_AUTH);
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
child = xmpp_stanza_new(conn->ctx);
if (!child)
goto err_free;
xmpp_stanza_set_name(child, "username");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata)
goto err_free;
str = xmpp_jid_node(conn->ctx, conn->jid);
if (!str) {
xmpp_stanza_release(authdata);
goto err_free;
}
xmpp_stanza_set_text(authdata, str);
xmpp_free(conn->ctx, str);
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
child = xmpp_stanza_new(conn->ctx);
if (!child)
goto err_free;
xmpp_stanza_set_name(child, "password");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata)
goto err_free;
xmpp_stanza_set_text(authdata, conn->pass);
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
child = xmpp_stanza_new(conn->ctx);
if (!child)
goto err_free;
xmpp_stanza_set_name(child, "resource");
xmpp_stanza_add_child(query, child);
xmpp_stanza_release(child);
authdata = xmpp_stanza_new(conn->ctx);
if (!authdata)
goto err_free;
str = xmpp_jid_resource(conn->ctx, conn->jid);
if (str) {
xmpp_stanza_set_text(authdata, str);
xmpp_free(conn->ctx, str);
} else {
xmpp_stanza_release(authdata);
xmpp_stanza_release(iq);
xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource");
xmpp_disconnect(conn);
return;
}
xmpp_stanza_add_child(child, authdata);
xmpp_stanza_release(authdata);
handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL);
handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL);
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
return;
err_free:
xmpp_stanza_release(iq);
err:
disconnect_mem_error(conn);
} }
void auth_handle_component_open(xmpp_conn_t * const conn) void auth_handle_component_open(xmpp_conn_t * const conn)

View File

@@ -160,7 +160,6 @@ struct _xmpp_conn_t {
xmpp_stream_error_t *stream_error; xmpp_stream_error_t *stream_error;
sock_t sock; sock_t sock;
xmpp_sock_t *xsock;
int ka_timeout; /* TCP keepalive timeout */ int ka_timeout; /* TCP keepalive timeout */
int ka_interval; /* TCP keepalive interval */ int ka_interval; /* TCP keepalive interval */
@@ -173,7 +172,6 @@ struct _xmpp_conn_t {
int tls_failed; /* set when tls fails, so we don't try again */ int tls_failed; /* set when tls fails, so we don't try again */
int sasl_support; /* if true, field is a bitfield of supported int sasl_support; /* if true, field is a bitfield of supported
mechanisms */ mechanisms */
int auth_legacy_enabled;
int secured; /* set when stream is secured with TLS */ int secured; /* set when stream is secured with TLS */
/* if server returns <bind/> or <session/> we must do them */ /* if server returns <bind/> or <session/> we must do them */

View File

@@ -73,15 +73,6 @@ static int _conn_connect(xmpp_conn_t * const conn,
xmpp_conn_handler callback, xmpp_conn_handler callback,
void * const userdata); void * const userdata);
void xmpp_send_error(xmpp_conn_t * const conn, xmpp_error_type_t const type, char * const text)
{
xmpp_stanza_t *error = xmpp_error_new(conn->ctx, type, text);
xmpp_send(conn, error);
xmpp_stanza_release(error);
}
/** Create a new Strophe connection object. /** Create a new Strophe connection object.
* *
* @param ctx a Strophe context object * @param ctx a Strophe context object
@@ -140,7 +131,6 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t * const ctx)
conn->tls_trust = 0; conn->tls_trust = 0;
conn->tls_failed = 0; conn->tls_failed = 0;
conn->sasl_support = 0; conn->sasl_support = 0;
conn->auth_legacy_enabled = 0;
conn->secured = 0; conn->secured = 0;
conn->bind_required = 0; conn->bind_required = 0;
@@ -689,8 +679,7 @@ void conn_disconnect(xmpp_conn_t * const conn)
tls_free(conn->tls); tls_free(conn->tls);
conn->tls = NULL; conn->tls = NULL;
} }
if (conn->sock >= 0) sock_close(conn->sock);
sock_close(conn->sock);
/* fire off connection handler */ /* fire off connection handler */
conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error, conn->conn_handler(conn, XMPP_CONN_DISCONNECT, conn->error,
@@ -715,7 +704,7 @@ void conn_parser_reset(xmpp_conn_t * const conn)
/** Initiate termination of the connection to the XMPP server. /** Initiate termination of the connection to the XMPP server.
* This function starts the disconnection sequence by sending * This function starts the disconnection sequence by sending
* </stream:stream> to the XMPP server. This function will do nothing * </stream:stream> to the XMPP server. This function will do nothing
* if the connection state is different from CONNECTING or CONNECTED. * if the connection state is CONNECTING or CONNECTED.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
* *
@@ -757,10 +746,10 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
char *bigbuf; char *bigbuf;
va_start(ap, fmt); va_start(ap, fmt);
len = xmpp_vsnprintf(buf, sizeof(buf), fmt, ap); len = xmpp_vsnprintf(buf, 1024, fmt, ap);
va_end(ap); va_end(ap);
if (len >= sizeof(buf)) { if (len >= 1024) {
/* we need more space for this data, so we allocate a big /* we need more space for this data, so we allocate a big
* enough buffer and print to that */ * enough buffer and print to that */
len++; /* account for trailing \0 */ len++; /* account for trailing \0 */
@@ -781,6 +770,7 @@ void xmpp_send_raw_string(xmpp_conn_t * const conn,
xmpp_free(conn->ctx, bigbuf); xmpp_free(conn->ctx, bigbuf);
} else { } else {
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf); xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
xmpp_send_raw(conn, buf, len); xmpp_send_raw(conn, buf, len);
} }
} }
@@ -845,9 +835,10 @@ void xmpp_send(xmpp_conn_t * const conn,
{ {
char *buf; char *buf;
size_t len; size_t len;
int ret;
if (conn->state == XMPP_STATE_CONNECTED) { if (conn->state == XMPP_STATE_CONNECTED) {
if (xmpp_stanza_to_text(stanza, &buf, &len) == 0) { if ((ret = xmpp_stanza_to_text(stanza, &buf, &len)) == 0) {
xmpp_send_raw(conn, buf, len); xmpp_send_raw(conn, buf, len);
xmpp_debug(conn->ctx, "conn", "SENT: %s", buf); xmpp_debug(conn->ctx, "conn", "SENT: %s", buf);
xmpp_free(conn->ctx, buf); xmpp_free(conn->ctx, buf);
@@ -922,8 +913,7 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled | flags = XMPP_CONN_FLAG_DISABLE_TLS * conn->tls_disabled |
XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory | XMPP_CONN_FLAG_MANDATORY_TLS * conn->tls_mandatory |
XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl | XMPP_CONN_FLAG_LEGACY_SSL * conn->tls_legacy_ssl |
XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust | XMPP_CONN_FLAG_TRUST_TLS * conn->tls_trust;
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;;
return flags; return flags;
} }
@@ -941,7 +931,6 @@ long xmpp_conn_get_flags(const xmpp_conn_t * const conn)
* - XMPP_CONN_FLAG_MANDATORY_TLS * - XMPP_CONN_FLAG_MANDATORY_TLS
* - XMPP_CONN_FLAG_LEGACY_SSL * - XMPP_CONN_FLAG_LEGACY_SSL
* - XMPP_CONN_FLAG_TRUST_TLS * - XMPP_CONN_FLAG_TRUST_TLS
* - XMPP_CONN_FLAG_LEGACY_AUTH
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param flags ORed connection flags * @param flags ORed connection flags
@@ -968,7 +957,6 @@ int xmpp_conn_set_flags(xmpp_conn_t * const conn, long flags)
conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0; conn->tls_mandatory = (flags & XMPP_CONN_FLAG_MANDATORY_TLS) ? 1 : 0;
conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0; conn->tls_legacy_ssl = (flags & XMPP_CONN_FLAG_LEGACY_SSL) ? 1 : 0;
conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0; conn->tls_trust = (flags & XMPP_CONN_FLAG_TRUST_TLS) ? 1 : 0;
conn->auth_legacy_enabled = (flags & XMPP_CONN_FLAG_LEGACY_AUTH) ? 1 : 0;
return 0; return 0;
} }
@@ -1214,9 +1202,6 @@ static void _conn_reset(xmpp_conn_t * const conn)
xmpp_free(ctx, tsq->data); xmpp_free(ctx, tsq->data);
xmpp_free(ctx, tsq); xmpp_free(ctx, tsq);
} }
conn->send_queue_head = NULL;
conn->send_queue_tail = NULL;
conn->send_queue_len = 0;
if (conn->stream_error) { if (conn->stream_error) {
xmpp_stanza_release(conn->stream_error->stanza); xmpp_stanza_release(conn->stream_error->stanza);
@@ -1264,8 +1249,7 @@ static int _conn_connect(xmpp_conn_t * const conn,
conn->domain = xmpp_strdup(conn->ctx, domain); conn->domain = xmpp_strdup(conn->ctx, domain);
if (!conn->domain) return XMPP_EMEM; if (!conn->domain) return XMPP_EMEM;
conn->xsock = sock_new(conn->ctx, host, port); conn->sock = sock_connect(host, port);
conn->sock = sock_connect(conn->xsock);
xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d", xmpp_debug(conn->ctx, "xmpp", "sock_connect() to %s:%u returned %d",
host, port, conn->sock); host, port, conn->sock);
if (conn->sock == -1) return XMPP_EINT; if (conn->sock == -1) return XMPP_EINT;

View File

@@ -61,7 +61,7 @@ static char *digest_to_string_alloc(xmpp_ctx_t *ctx, const uint8_t *digest)
return s; return s;
} }
/** Compute SHA1 message digest. /** Compute SHA1 message digest
* Returns an allocated string which represents SHA1 message digest in * Returns an allocated string which represents SHA1 message digest in
* hexadecimal notation. The string must be freed with xmpp_free(). * hexadecimal notation. The string must be freed with xmpp_free().
* *
@@ -81,7 +81,7 @@ char *xmpp_sha1(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return digest_to_string_alloc(ctx, digest); return digest_to_string_alloc(ctx, digest);
} }
/** Compute SHA1 message digest. /** Compute SHA1 message digest
* Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE * Stores digest in user's buffer which must be at least XMPP_SHA1_DIGEST_SIZE
* bytes long. * bytes long.
* *
@@ -97,7 +97,7 @@ void xmpp_sha1_digest(const unsigned char *data, size_t len,
crypto_SHA1((const uint8_t *)data, len, digest); crypto_SHA1((const uint8_t *)data, len, digest);
} }
/** Create new SHA1 object. /** Create new SHA1 object
* SHA1 object is used to compute SHA1 digest of a buffer that is split * SHA1 object is used to compute SHA1 digest of a buffer that is split
* in multiple chunks or provided in stream mode. A single buffer can be * in multiple chunks or provided in stream mode. A single buffer can be
* processed by short functions xmpp_sha1() and xmpp_sha1_digest(). * processed by short functions xmpp_sha1() and xmpp_sha1_digest().
@@ -111,7 +111,7 @@ void xmpp_sha1_digest(const unsigned char *data, size_t len,
* xmpp_sha1_free(sha1); * xmpp_sha1_free(sha1);
* @endcode * @endcode
* *
* @param ctx a Strophe context object * @param ctx a Strophe context onject
* *
* @return new SHA1 object * @return new SHA1 object
* *
@@ -130,7 +130,7 @@ xmpp_sha1_t *xmpp_sha1_new(xmpp_ctx_t *ctx)
return sha1; return sha1;
} }
/** Destroy SHA1 object. /** Destroy SHA1 object
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* *
@@ -141,7 +141,7 @@ void xmpp_sha1_free(xmpp_sha1_t *sha1)
xmpp_free(sha1->xmpp_ctx, sha1); xmpp_free(sha1->xmpp_ctx, sha1);
} }
/** Update SHA1 context with the next portion of data. /** Update SHA1 context with the next portion of data
* Can be called repeatedly. * Can be called repeatedly.
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
@@ -155,7 +155,7 @@ void xmpp_sha1_update(xmpp_sha1_t *sha1, const unsigned char *data, size_t len)
crypto_SHA1_Update(&sha1->ctx, data, len); crypto_SHA1_Update(&sha1->ctx, data, len);
} }
/** Finish SHA1 computation. /** Finish SHA1 computation
* Don't call xmpp_sha1_update() after this function. Retrieve resulting * Don't call xmpp_sha1_update() after this function. Retrieve resulting
* message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest(). * message digest with xmpp_sha1_to_string() or xmpp_sha1_to_digest().
* *
@@ -168,7 +168,7 @@ void xmpp_sha1_final(xmpp_sha1_t *sha1)
crypto_SHA1_Final(&sha1->ctx, sha1->digest); crypto_SHA1_Final(&sha1->ctx, sha1->digest);
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string
* Stores the string to a user's buffer and returns the buffer. Call this * Stores the string to a user's buffer and returns the buffer. Call this
* function after xmpp_sha1_final(). * function after xmpp_sha1_final().
* *
@@ -185,7 +185,7 @@ char *xmpp_sha1_to_string(xmpp_sha1_t *sha1, char *s, size_t slen)
return digest_to_string(sha1->digest, s, slen); return digest_to_string(sha1->digest, s, slen);
} }
/** Return message digest rendered as a string. /** Return message digest rendered as a string
* Returns an allocated string. Free the string using the Strophe context * Returns an allocated string. Free the string using the Strophe context
* which is passed to xmpp_sha1_new(). Call this function after * which is passed to xmpp_sha1_new(). Call this function after
* xmpp_sha1_final(). * xmpp_sha1_final().
@@ -201,7 +201,7 @@ char *xmpp_sha1_to_string_alloc(xmpp_sha1_t *sha1)
return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest); return digest_to_string_alloc(sha1->xmpp_ctx, sha1->digest);
} }
/** Stores message digest to a user's buffer. /** Stores message digest to a user's buffer
* *
* @param sha1 a SHA1 object * @param sha1 a SHA1 object
* @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes * @param digest output buffer of XMPP_SHA1_DIGEST_SIZE bytes
@@ -419,7 +419,7 @@ _base64_error:
*outlen = 0; *outlen = 0;
} }
/** Base64 encoding routine. /** Base64 encoding routine
* Returns an allocated string which must be freed with xmpp_free(). * Returns an allocated string which must be freed with xmpp_free().
* *
* @param ctx a Strophe context * @param ctx a Strophe context
@@ -435,7 +435,7 @@ char *xmpp_base64_encode(xmpp_ctx_t *ctx, const unsigned char *data, size_t len)
return base64_encode(ctx, data, len); return base64_encode(ctx, data, len);
} }
/** Base64 decoding routine. /** Base64 decoding routine
* Returns an allocated string which must be freed with xmpp_free(). User * Returns an allocated string which must be freed with xmpp_free(). User
* calls this function when the result must be a string. When decoded buffer * calls this function when the result must be a string. When decoded buffer
* contains '\0' NULL is returned. * contains '\0' NULL is returned.
@@ -471,7 +471,7 @@ char *xmpp_base64_decode_str(xmpp_ctx_t *ctx, const char *base64, size_t len)
return (char *)buf; return (char *)buf;
} }
/** Base64 decoding routine. /** Base64 decoding routine
* Returns an allocated buffer which must be freed with xmpp_free(). * Returns an allocated buffer which must be freed with xmpp_free().
* *
* @param ctx a Strophe context * @param ctx a Strophe context

View File

@@ -47,7 +47,6 @@
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#include "resolver.h"
#include "util.h" #include "util.h"
/* Workaround for visual studio without va_copy support. */ /* Workaround for visual studio without va_copy support. */
@@ -64,7 +63,6 @@
void xmpp_initialize(void) void xmpp_initialize(void)
{ {
sock_initialize(); sock_initialize();
resolver_initialize();
tls_initialize(); tls_initialize();
} }
@@ -75,7 +73,6 @@
void xmpp_shutdown(void) void xmpp_shutdown(void)
{ {
tls_shutdown(); tls_shutdown();
resolver_shutdown();
sock_shutdown(); sock_shutdown();
} }

View File

@@ -51,18 +51,6 @@
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
static int _connect_next(xmpp_conn_t *conn)
{
sock_close(conn->sock);
conn->sock = sock_connect(conn->xsock);
if (conn->sock < 0)
return -1;
conn->timeout_stamp = time_stamp();
return 0;
}
/** Run the event loop once. /** Run the event loop once.
* This function will run send any data that has been queued by * This function will run send any data that has been queued by
* xmpp_send and related functions and run through the Strophe even * xmpp_send and related functions and run through the Strophe even
@@ -192,11 +180,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
conn->connect_timeout) conn->connect_timeout)
FD_SET(conn->sock, &wfds); FD_SET(conn->sock, &wfds);
else { else {
ret = _connect_next(conn);
if (ret == 0) {
FD_SET(conn->sock, &wfds);
break;
}
conn->error = ETIMEDOUT; conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out."); xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn_disconnect(conn); conn_disconnect(conn);
@@ -255,11 +238,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
/* check for error */ /* check for error */
ret = sock_connect_error(conn->sock); ret = sock_connect_error(conn->sock);
if (ret != 0) {
ret = _connect_next(conn);
if (ret == 0)
break;
}
if (ret != 0) { if (ret != 0) {
/* connection failed */ /* connection failed */
xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret); xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret);
@@ -284,8 +262,10 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
if (ret > 0) { if (ret > 0) {
ret = parser_feed(conn->parser, buf, ret); ret = parser_feed(conn->parser, buf, ret);
if (!ret) { if (!ret) {
xmpp_debug(ctx, "xmpp", "parse error [%s]", buf); /* parse error, we need to shut down */
xmpp_send_error(conn, XMPP_SE_INVALID_XML, "parse error"); /* FIXME */
xmpp_debug(ctx, "xmpp", "parse error, disconnecting");
conn_disconnect(conn);
} }
} else { } else {
if (conn->tls) { if (conn->tls) {

View File

@@ -163,8 +163,6 @@ int hash_add(hash_t *table, const char * const key, void *data)
entry->next = table->entries[table_index]; entry->next = table->entries[table_index];
table->entries[table_index] = entry; table->entries[table_index] = entry;
table->num_keys++; table->num_keys++;
} else {
if (table->free) table->free(ctx, entry->value);
} }
entry->value = data; entry->value = data;
@@ -243,7 +241,7 @@ void hash_iter_release(hash_iterator_t *iter)
iter->ref--; iter->ref--;
if (iter->ref == 0) { // ref is unsigned!!! if (iter->ref <= 0) {
hash_release(iter->table); hash_release(iter->table);
xmpp_free(ctx, iter); xmpp_free(ctx, iter);
} }

View File

@@ -137,7 +137,7 @@ static void _start_element(void *userdata,
if (parser->depth == 0) { if (parser->depth == 0) {
/* notify the owner */ /* notify the owner */
if (parser->startcb) if (parser->startcb)
parser->startcb(name, (char **)attrs, parser->startcb((char *)name, (char **)attrs,
parser->userdata); parser->userdata);
} else { } else {
/* build stanzas at depth 1 */ /* build stanzas at depth 1 */

View File

@@ -249,8 +249,6 @@ void parser_free(parser_t *parser)
{ {
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza)
xmpp_stanza_release(parser->stanza);
xmpp_free(parser->ctx, parser); xmpp_free(parser->ctx, parser);
} }
@@ -259,16 +257,18 @@ int parser_reset(parser_t *parser)
{ {
if (parser->xmlctx) if (parser->xmlctx)
xmlFreeParserCtxt(parser->xmlctx); xmlFreeParserCtxt(parser->xmlctx);
if (parser->stanza) if (parser->stanza)
xmpp_stanza_release(parser->stanza); xmpp_stanza_release(parser->stanza);
parser->stanza = NULL;
parser->depth = 0;
parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers, parser->xmlctx = xmlCreatePushParserCtxt(&parser->handlers,
parser, NULL, 0, NULL); parser, NULL, 0, NULL);
if (!parser->xmlctx) return 0;
return parser->xmlctx ? 1 : 0; parser->depth = 0;
parser->stanza = NULL;
return 1;
} }
/* feed a chunk of data to the parser */ /* feed a chunk of data to the parser */

View File

@@ -127,11 +127,9 @@ static void Hash_DRBG_Instantiate(Hash_DRBG_CTX *ctx,
assert(entropy_input_len <= ENTROPY_MAX); assert(entropy_input_len <= ENTROPY_MAX);
assert(nonce_len <= NONCE_MAX); assert(nonce_len <= NONCE_MAX);
assert(nonce != NULL || nonce_len == 0);
memcpy(seed_material, entropy_input, entropy_input_len); memcpy(seed_material, entropy_input, entropy_input_len);
if (nonce != NULL) memcpy(seed_material + entropy_input_len, nonce, nonce_len);
memcpy(seed_material + entropy_input_len, nonce, nonce_len);
Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen); Hash_df(seed_material, entropy_input_len + nonce_len, seed, seedlen);
seed0[0] = 0; seed0[0] = 0;

View File

@@ -36,7 +36,7 @@ xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx);
*/ */
void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand); void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand);
/** Generate random integer. /** Generate random integer
* Analogue of rand(3). * Analogue of rand(3).
* *
* @ingroup Random * @ingroup Random

View File

@@ -1,4 +1,4 @@
/* resolver.c /* resolver.h
* strophe XMPP client library -- DNS resolver * strophe XMPP client library -- DNS resolver
* *
* Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com> * Copyright (C) 2015 Dmitry Podgorny <pasis.ua@gmail.com>
@@ -13,15 +13,11 @@
* DNS resolver. * DNS resolver.
*/ */
#if !defined(_WIN32) && !defined(HAVE_CARES) #ifndef _WIN32
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/nameser.h> #include <arpa/nameser.h>
#include <resolv.h> /* res_query */ #include <resolv.h> /* res_query */
#endif /* _WIN32 && HAVE_CARES */ #endif /* _WIN32 */
#ifdef HAVE_CARES
#include <ares.h>
#endif /* HAVE_CARES */
#include <string.h> /* strncpy */ #include <string.h> /* strncpy */
@@ -35,189 +31,6 @@
#define MESSAGE_T_SRV 33 #define MESSAGE_T_SRV 33
#define MESSAGE_C_IN 1 #define MESSAGE_C_IN 1
/*******************************************************************************
* Forward declarations.
******************************************************************************/
#ifdef HAVE_CARES
static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
const unsigned char *buf,
size_t len,
resolver_srv_rr_t **srv_rr_list);
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
#endif /* HAVE_CARES */
#ifndef HAVE_CARES
static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
const unsigned char *buf,
size_t len,
resolver_srv_rr_t **srv_rr_list);
#endif /* !HAVE_CARES */
#ifdef _WIN32
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len);
#endif /* _WIN32 */
/*******************************************************************************
* Implementation.
******************************************************************************/
void resolver_initialize(void)
{
#ifdef HAVE_CARES
ares_library_init(ARES_LIB_INIT_ALL);
#endif
}
void resolver_shutdown(void)
{
#ifdef HAVE_CARES
ares_library_cleanup();
#endif
}
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t *rr_head;
resolver_srv_rr_t *rr_current;
resolver_srv_rr_t *rr_next;
resolver_srv_rr_t *rr_prev;
int swap;
rr_head = *srv_rr_list;
if ((rr_head == NULL) || (rr_head->next == NULL)) {
/* Empty or single record list */
return;
}
do {
rr_prev = NULL;
rr_current = rr_head;
rr_next = rr_head->next;
swap = 0;
while (rr_next != NULL) {
/*
* RFC2052: A client MUST attempt to contact the target host
* with the lowest-numbered priority it can reach.
* RFC2052: When selecting a target host among the
* those that have the same priority, the chance of trying
* this one first SHOULD be proportional to its weight.
*/
if ((rr_current->priority > rr_next->priority) ||
(rr_current->priority == rr_next->priority &&
rr_current->weight < rr_next->weight))
{
/* Swap node */
swap = 1;
if (rr_prev != NULL) {
rr_prev->next = rr_next;
} else {
/* Swap head node */
rr_head = rr_next;
}
rr_current->next = rr_next->next;
rr_next->next = rr_current;
rr_prev = rr_next;
rr_next = rr_current->next;
} else {
/* Next node */
rr_prev = rr_current;
rr_current = rr_next;
rr_next = rr_next->next;
}
}
} while (swap != 0);
*srv_rr_list = rr_head;
}
int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
size_t len, resolver_srv_rr_t **srv_rr_list)
{
int set;
#ifdef HAVE_CARES
set = resolver_ares_srv_lookup_buf(ctx, buf, len, srv_rr_list);
#else
set = resolver_raw_srv_lookup_buf(ctx, buf, len, srv_rr_list);
#endif
resolver_srv_list_sort(srv_rr_list);
return set;
}
int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list)
{
#define RESOLVER_BUF_MAX 65536
unsigned char *buf;
char fulldomain[2048];
int len;
int set = XMPP_DOMAIN_NOT_FOUND;
(void)buf;
(void)len;
xmpp_snprintf(fulldomain, sizeof(fulldomain),
"_%s._%s.%s", service, proto, domain);
*srv_rr_list = NULL;
#ifdef HAVE_CARES
set = resolver_ares_srv_lookup(ctx, fulldomain, srv_rr_list);
#else /* HAVE_CARES */
#ifdef _WIN32
set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
if (set == XMPP_DOMAIN_FOUND)
return set;
#endif /* _WIN32 */
buf = xmpp_alloc(ctx, RESOLVER_BUF_MAX);
if (buf == NULL)
return XMPP_DOMAIN_NOT_FOUND;
#ifdef _WIN32
len = resolver_win32_srv_query(fulldomain, buf, RESOLVER_BUF_MAX);
#else /* _WIN32 */
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf,
RESOLVER_BUF_MAX);
#endif /* _WIN32 */
if (len > 0)
set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
xmpp_free(ctx, buf);
#endif /* HAVE_CARES */
return set;
}
void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
{
resolver_srv_rr_t *rr;
while (srv_rr_list != NULL) {
rr = srv_rr_list->next;
xmpp_free(ctx, srv_rr_list);
srv_rr_list = rr;
}
}
#ifndef HAVE_CARES
/*******************************************************************************
* Resolver raw implementation.
*
* This code is common for both unix and win32.
******************************************************************************/
struct message_header { struct message_header {
uint16_t id; uint16_t id;
uint8_t octet2; uint8_t octet2;
@@ -228,6 +41,13 @@ struct message_header {
uint16_t arcount; uint16_t arcount;
}; };
#ifdef _WIN32
static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list);
static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len);
#endif /* _WIN32 */
/* the same as ntohs(), but receives pointer to the value */ /* the same as ntohs(), but receives pointer to the value */
static uint16_t xmpp_ntohs_ptr(const void *ptr) static uint16_t xmpp_ntohs_ptr(const void *ptr)
{ {
@@ -260,7 +80,7 @@ static size_t message_name_append_safe(char *name, size_t name_len,
copy_len = name_max > name_len ? name_max - name_len : 0; copy_len = name_max > name_len ? name_max - name_len : 0;
copy_len = xmpp_min(tail_len, copy_len); copy_len = xmpp_min(tail_len, copy_len);
if (copy_len > 0) if (copy_len > 0)
memcpy(&name[name_len], tail, copy_len); strncpy(&name[name_len], tail, copy_len);
return name_len + tail_len; return name_len + tail_len;
} }
@@ -340,6 +160,63 @@ static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX); return message_name_get(buf, buf_len, buf_offset, NULL, SIZE_MAX);
} }
static void resolver_srv_list_sort(resolver_srv_rr_t **srv_rr_list)
{
resolver_srv_rr_t * rr_head;
resolver_srv_rr_t * rr_current;
resolver_srv_rr_t * rr_next;
resolver_srv_rr_t * rr_prev;
int swap;
rr_head = *srv_rr_list;
if ((rr_head == NULL) || (rr_head->next == NULL)) {
/* Empty or single record list */
return;
}
do {
rr_prev = NULL;
rr_current = rr_head;
rr_next = rr_head->next;
swap = 0;
while (rr_next != NULL) {
/*
* RFC2052: A client MUST attempt to contact the target host
* with the lowest-numbered priority it can reach.
* RFC2052: When selecting a target host among the
* those that have the same priority, the chance of trying
* this one first SHOULD be proportional to its weight.
*/
if ((rr_current->priority > rr_next->priority) ||
(rr_current->priority == rr_next->priority &&
rr_current->weight < rr_next->weight))
{
/* Swap node */
swap = 1;
if (rr_prev != NULL) {
rr_prev->next = rr_next;
} else {
/* Swap head node */
rr_head = rr_next;
}
rr_current->next = rr_next->next;
rr_next->next = rr_current;
rr_prev = rr_next;
rr_next = rr_current->next;
} else {
/* Next node */
rr_prev = rr_current;
rr_current = rr_next;
rr_next = rr_next->next;
}
}
} while (swap != 0);
*srv_rr_list = rr_head;
}
#define BUF_OVERFLOW_CHECK(ptr, len) do { \ #define BUF_OVERFLOW_CHECK(ptr, len) do { \
if ((ptr) >= (len)) { \ if ((ptr) >= (len)) { \
if (*srv_rr_list != NULL) \ if (*srv_rr_list != NULL) \
@@ -349,10 +226,8 @@ static unsigned message_name_len(const unsigned char *buf, size_t buf_len,
} \ } \
} while (0) } while (0)
static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx, int resolver_srv_lookup_buf(xmpp_ctx_t *ctx, const unsigned char *buf,
const unsigned char *buf, size_t len, resolver_srv_rr_t **srv_rr_list)
size_t len,
resolver_srv_rr_t **srv_rr_list)
{ {
unsigned i; unsigned i;
unsigned j; unsigned j;
@@ -417,110 +292,52 @@ static int resolver_raw_srv_lookup_buf(xmpp_ctx_t *ctx,
} }
j += rdlength; j += rdlength;
} }
resolver_srv_list_sort(srv_rr_list);
return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND; return *srv_rr_list != NULL ? XMPP_DOMAIN_FOUND : XMPP_DOMAIN_NOT_FOUND;
} }
#endif /* !HAVE_CARES */ int resolver_srv_lookup(xmpp_ctx_t *ctx, const char *service, const char *proto,
const char *domain, resolver_srv_rr_t **srv_rr_list)
#ifdef HAVE_CARES
/*******************************************************************************
* Resolver implementation using c-ares library.
******************************************************************************/
struct resolver_ares_ctx {
xmpp_ctx_t *ctx;
int result;
resolver_srv_rr_t *srv_rr_list;
};
static int resolver_ares_srv_lookup_buf(xmpp_ctx_t *ctx,
const unsigned char *buf,
size_t len,
resolver_srv_rr_t **srv_rr_list)
{ {
struct ares_srv_reply *srv; char fulldomain[2048];
struct ares_srv_reply *item; unsigned char buf[65535];
resolver_srv_rr_t *rr; int len;
int rc; int set = XMPP_DOMAIN_NOT_FOUND;
xmpp_snprintf(fulldomain, sizeof(fulldomain),
"_%s._%s.%s", service, proto, domain);
*srv_rr_list = NULL; *srv_rr_list = NULL;
rc = ares_parse_srv_reply(buf, len, &srv); #ifdef _WIN32
if (rc != ARES_SUCCESS) set = resolver_win32_srv_lookup(ctx, fulldomain, srv_rr_list);
return XMPP_DOMAIN_NOT_FOUND; if (set == XMPP_DOMAIN_FOUND)
return set;
len = resolver_win32_srv_query(fulldomain, buf, sizeof(buf));
#else /* _WIN32 */
len = res_query(fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV, buf, sizeof(buf));
#endif /* _WIN32 */
item = srv; if (len > 0)
while (item != NULL) { set = resolver_srv_lookup_buf(ctx, buf, (size_t)len, srv_rr_list);
rr = xmpp_alloc(ctx, sizeof(*rr));
if (rr == NULL)
break;
rr->next = *srv_rr_list;
rr->priority = item->priority;
rr->weight = item->weight;
rr->port = item->port;
strncpy(rr->target, item->host, sizeof(rr->target) - 1);
rr->target[sizeof(rr->target) - 1] = '\0';
*srv_rr_list = rr;
item = item->next;
}
ares_free_data(srv);
return *srv_rr_list == NULL ? XMPP_DOMAIN_NOT_FOUND : XMPP_DOMAIN_FOUND; return set;
} }
static void ares_srv_lookup_callback(void *arg, int status, int timeouts, void resolver_srv_free(xmpp_ctx_t *ctx, resolver_srv_rr_t *srv_rr_list)
unsigned char *buf, int len)
{ {
struct resolver_ares_ctx *actx = arg; resolver_srv_rr_t *rr;
if (status != ARES_SUCCESS) while (srv_rr_list != NULL) {
actx->result = XMPP_DOMAIN_NOT_FOUND; rr = srv_rr_list->next;
else xmpp_free(ctx, srv_rr_list);
actx->result = resolver_ares_srv_lookup_buf(actx->ctx, buf, len, srv_rr_list = rr;
&actx->srv_rr_list);
}
static int resolver_ares_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t **srv_rr_list)
{
struct resolver_ares_ctx actx;
ares_channel chan;
struct timeval tv;
struct timeval *tvp;
fd_set rfds;
fd_set wfds;
int nfds;
int rc;
actx.ctx = ctx;
actx.result = XMPP_DOMAIN_NOT_FOUND;
actx.srv_rr_list = NULL;
rc = ares_init(&chan);
if (rc == ARES_SUCCESS) {
ares_query(chan, fulldomain, MESSAGE_C_IN, MESSAGE_T_SRV,
ares_srv_lookup_callback, &actx);
while (1) {
FD_ZERO(&rfds);
FD_ZERO(&wfds);
nfds = ares_fds(chan, &rfds, &wfds);
if (nfds == 0)
break;
tvp = ares_timeout(chan, NULL, &tv);
select(nfds, &rfds, &wfds, NULL, tvp);
ares_process(chan, &rfds, &wfds);
}
ares_destroy(chan);
} }
*srv_rr_list = actx.srv_rr_list;
return actx.result;
} }
#endif /* HAVE_CARES */
#ifdef _WIN32 #ifdef _WIN32
/******************************************************************************* /*******************************************************************************
* Next part was copied from sock.c and contains old win32 code. * Next part was copied from sock.c and contains old win32 code.
* *
@@ -653,21 +470,21 @@ static int resolver_win32_srv_lookup(xmpp_ctx_t *ctx, const char *fulldomain,
resolver_srv_rr_t *rr; resolver_srv_rr_t *rr;
HINSTANCE hdnsapi = NULL; HINSTANCE hdnsapi = NULL;
DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, DNS_RECORDA**, PVOID*); DNS_STATUS (WINAPI * pDnsQuery_A)(PCSTR, WORD, DWORD, PIP4_ARRAY, PDNS_RECORD*, PVOID*);
void (WINAPI * pDnsRecordListFree)(DNS_RECORDA*, DNS_FREE_TYPE); void (WINAPI * pDnsRecordListFree)(PDNS_RECORD, DNS_FREE_TYPE);
if (hdnsapi = LoadLibrary("dnsapi.dll")) { if (hdnsapi = LoadLibrary("dnsapi.dll")) {
pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A"); pDnsQuery_A = (void *)GetProcAddress(hdnsapi, "DnsQuery_A");
pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree"); pDnsRecordListFree = (void *)GetProcAddress(hdnsapi, "DnsRecordListFree");
if (pDnsQuery_A && pDnsRecordListFree) { if (pDnsQuery_A && pDnsRecordListFree) {
DNS_RECORDA *dnsrecords = NULL; PDNS_RECORD dnsrecords = NULL;
DNS_STATUS error; DNS_STATUS error;
error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL); error = pDnsQuery_A(fulldomain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, NULL);
if (error == 0) { if (error == 0) {
DNS_RECORDA *current = dnsrecords; PDNS_RECORD current = dnsrecords;
while (current) { while (current) {
if (current->wType == DNS_TYPE_SRV) { if (current->wType == DNS_TYPE_SRV) {
@@ -700,7 +517,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
unsigned char *buf, size_t len) unsigned char *buf, size_t len)
{ {
int set = 0; int set = 0;
int insize = 0; int insize;
/* if dnsapi didn't work/isn't there, try querying the dns server manually */ /* if dnsapi didn't work/isn't there, try querying the dns server manually */
if (!set) if (!set)
@@ -733,7 +550,7 @@ static int resolver_win32_srv_query(const char *fulldomain,
char buffer[65535]; char buffer[65535];
len = 65535; len = 65535;
fi = (FIXED_INFO *)buffer; fi = buffer;
if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS) if ((error = pGetNetworkParams(fi, &len)) == ERROR_SUCCESS)
{ {

View File

@@ -33,9 +33,6 @@ typedef struct resolver_srv_rr_struc {
struct resolver_srv_rr_struc *next; struct resolver_srv_rr_struc *next;
} resolver_srv_rr_t; } resolver_srv_rr_t;
void resolver_initialize(void);
void resolver_shutdown(void);
/** Perform lookup for RFC1035 message format. /** Perform lookup for RFC1035 message format.
* This function allocates all elements. * This function allocates all elements.
* *

View File

@@ -264,8 +264,7 @@ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge,
xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce)); xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce));
hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce)); hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce));
hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); hash_add(table, "nc", xmpp_strdup(ctx, "00000001"));
if (hash_get(table, "qop") == NULL) hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
hash_add(table, "qop", xmpp_strdup(ctx, "auth"));
value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); value = xmpp_alloc(ctx, 5 + strlen(domain) + 1);
memcpy(value, "xmpp/", 5); memcpy(value, "xmpp/", 5);
memcpy(value+5, domain, strlen(domain)); memcpy(value+5, domain, strlen(domain));

View File

@@ -197,9 +197,8 @@ void crypto_SHA1_Update(SHA1_CTX* context, const uint8_t* data,
size_t i, j; size_t i, j;
j = (context->count[0] >> 3) & 63; j = (context->count[0] >> 3) & 63;
if ((context->count[0] += (uint32_t)len << 3) < ((uint32_t)len << 3)) if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1]++; context->count[1] += (len >> 29);
context->count[1] += (uint32_t)(len >> 29);
if ((j + len) > 63) { if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j)); memcpy(&context->buffer[j], data, (i = 64-j));
SHA1_Transform(context->state, context->buffer); SHA1_Transform(context->state, context->buffer);

View File

@@ -33,17 +33,9 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#include "common.h"
#include "sock.h" #include "sock.h"
#include "snprintf.h" #include "snprintf.h"
struct _xmpp_sock_t {
xmpp_ctx_t *ctx;
struct addrinfo *ainfo_list;
struct addrinfo *current;
sock_t sock;
};
void sock_initialize(void) void sock_initialize(void)
{ {
#ifdef _WIN32 #ifdef _WIN32
@@ -77,23 +69,13 @@ static int _in_progress(int error)
#endif #endif
} }
xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port) sock_t sock_connect(const char * const host, const unsigned short port)
{ {
xmpp_sock_t *xsock; sock_t sock;
char service[6]; char service[6];
struct addrinfo hints; struct addrinfo *res, *ainfo, hints;
int err; int err;
xsock = xmpp_alloc(ctx, sizeof *xsock);
if (xsock == NULL) {
xmpp_error(ctx, "sock", "Memory allocation error.");
return NULL;
}
xsock->ctx = ctx;
xsock->ainfo_list = NULL;
xsock->current = NULL;
xsock->sock = -1;
xmpp_snprintf(service, 6, "%u", port); xmpp_snprintf(service, 6, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo)); memset(&hints, 0, sizeof(struct addrinfo));
@@ -104,33 +86,11 @@ xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port)
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(host, service, &hints, &xsock->ainfo_list); err = getaddrinfo(host, service, &hints, &res);
if (err != 0) { if (err != 0)
xmpp_free(ctx, xsock); return -1;
xsock = NULL;
}
return xsock;
}
void sock_free(xmpp_sock_t *xsock) for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
{
if (xsock->ainfo_list != NULL)
freeaddrinfo(xsock->ainfo_list);
xmpp_free(xsock->ctx, xsock);
}
sock_t sock_connect(xmpp_sock_t *xsock)
{
struct addrinfo *ainfo;
sock_t sock = -1;
int err;
if (xsock->current == NULL)
ainfo = xsock->ainfo_list;
else
ainfo = xsock->current->ai_next;
for (; ainfo != NULL; ainfo = ainfo->ai_next) {
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock < 0) if (sock < 0)
continue; continue;
@@ -143,13 +103,9 @@ sock_t sock_connect(xmpp_sock_t *xsock)
} }
sock_close(sock); sock_close(sock);
} }
freeaddrinfo(res);
sock = ainfo == NULL ? -1 : sock;
xsock->sock = sock;
xsock->current = ainfo;
if (ainfo == NULL) {
freeaddrinfo(xsock->ainfo_list);
xsock->ainfo_list = NULL;
}
return sock; return sock;
} }
@@ -202,33 +158,38 @@ int sock_close(const sock_t sock)
#endif #endif
} }
static int _sock_set_blocking_mode(sock_t sock, int blocking) int sock_set_blocking(const sock_t sock)
{ {
#ifdef _WIN32 #ifdef _WIN32
u_long nonblock = blocking ? 0 : 1; u_long block = 0;
return ioctlsocket(sock, FIONBIO, &block);
#else
int rc;
rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) {
rc = fcntl(sock, F_SETFL, rc & (~O_NONBLOCK));
}
return rc;
#endif
}
int sock_set_nonblocking(const sock_t sock)
{
#ifdef _WIN32
u_long nonblock = 1;
return ioctlsocket(sock, FIONBIO, &nonblock); return ioctlsocket(sock, FIONBIO, &nonblock);
#else #else
int rc; int rc;
rc = fcntl(sock, F_GETFL, NULL); rc = fcntl(sock, F_GETFL, NULL);
if (rc >= 0) { if (rc >= 0) {
rc = blocking ? rc & (~O_NONBLOCK) : rc | O_NONBLOCK; rc = fcntl(sock, F_SETFL, rc | O_NONBLOCK);
rc = fcntl(sock, F_SETFL, rc);
} }
return rc; return rc;
#endif #endif
} }
int sock_set_blocking(const sock_t sock)
{
return _sock_set_blocking_mode(sock, 1);
}
int sock_set_nonblocking(const 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(const sock_t sock, void * const buff, const size_t len)
{ {
return recv(sock, buff, len, 0); return recv(sock, buff, len, 0);

View File

@@ -25,16 +25,12 @@ typedef int sock_t;
typedef SOCKET sock_t; typedef SOCKET sock_t;
#endif #endif
typedef struct _xmpp_sock_t xmpp_sock_t;
void sock_initialize(void); void sock_initialize(void);
void sock_shutdown(void); void sock_shutdown(void);
int sock_error(void); int sock_error(void);
xmpp_sock_t *sock_new(xmpp_ctx_t *ctx, const char *host, unsigned short port); sock_t sock_connect(const char * const host, const unsigned short port);
void sock_free(xmpp_sock_t *xsock);
sock_t sock_connect(xmpp_sock_t *xsock);
int sock_close(const sock_t sock); int sock_close(const sock_t sock);
int sock_set_blocking(const sock_t sock); int sock_set_blocking(const sock_t sock);

View File

@@ -1,7 +1,7 @@
/* stanza.c /* stanza.c
** strophe XMPP client library -- XMPP stanza object and utilities ** strophe XMPP client library -- XMPP stanza object and utilities
** **
** Copyright (C) 2005-2009 Collecta, Inc. ** Copyright (C) 2005-2009 Collecta, Inc.
** **
** This software is provided AS-IS with no warranty, either express ** This software is provided AS-IS with no warranty, either express
** or implied. ** or implied.
@@ -40,15 +40,15 @@ xmpp_stanza_t *xmpp_stanza_new(xmpp_ctx_t *ctx)
stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t)); stanza = xmpp_alloc(ctx, sizeof(xmpp_stanza_t));
if (stanza != NULL) { if (stanza != NULL) {
stanza->ref = 1; stanza->ref = 1;
stanza->ctx = ctx; stanza->ctx = ctx;
stanza->type = XMPP_STANZA_UNKNOWN; stanza->type = XMPP_STANZA_UNKNOWN;
stanza->prev = NULL; stanza->prev = NULL;
stanza->next = NULL; stanza->next = NULL;
stanza->children = NULL; stanza->children = NULL;
stanza->parent = NULL; stanza->parent = NULL;
stanza->data = NULL; stanza->data = NULL;
stanza->attributes = NULL; stanza->attributes = NULL;
} }
return stanza; return stanza;
@@ -121,27 +121,27 @@ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza)
copy->type = stanza->type; copy->type = stanza->type;
if (stanza->data) { if (stanza->data) {
copy->data = xmpp_strdup(stanza->ctx, stanza->data); copy->data = xmpp_strdup(stanza->ctx, stanza->data);
if (!copy->data) goto copy_error; if (!copy->data) goto copy_error;
} }
if (stanza->attributes) { if (stanza->attributes) {
if (_stanza_copy_attributes(copy, stanza) == -1) if (_stanza_copy_attributes(copy, stanza) == -1)
goto copy_error; goto copy_error;
} }
tail = copy->children; tail = copy->children;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
copychild = xmpp_stanza_copy(child); copychild = xmpp_stanza_copy(child);
if (!copychild) goto copy_error; if (!copychild) goto copy_error;
copychild->parent = copy; copychild->parent = copy;
if (tail) { if (tail) {
copychild->prev = tail; copychild->prev = tail;
tail->next = copychild; tail->next = copychild;
} else } else
copy->children = copychild; copy->children = copychild;
tail = copychild; tail = copychild;
} }
return copy; return copy;
@@ -153,7 +153,7 @@ copy_error:
} }
/** Release a stanza object and all of its children. /** Release a stanza object and all of its children.
* This function releases a stanza object and potentially all of its * This function releases a stanza object and potentially all of its
* children, which may cause the object(s) to be freed. * children, which may cause the object(s) to be freed.
* *
* @param stanza a Strophe stanza object * @param stanza a Strophe stanza object
@@ -169,20 +169,20 @@ int xmpp_stanza_release(xmpp_stanza_t * const stanza)
/* release stanza */ /* release stanza */
if (stanza->ref > 1) if (stanza->ref > 1)
stanza->ref--; stanza->ref--;
else { else {
/* release all children */ /* release all children */
child = stanza->children; child = stanza->children;
while (child) { while (child) {
tchild = child; tchild = child;
child = child->next; child = child->next;
xmpp_stanza_release(tchild); xmpp_stanza_release(tchild);
} }
if (stanza->attributes) hash_release(stanza->attributes); if (stanza->attributes) hash_release(stanza->attributes);
if (stanza->data) xmpp_free(stanza->ctx, stanza->data); if (stanza->data) xmpp_free(stanza->ctx, stanza->data);
xmpp_free(stanza->ctx, stanza); xmpp_free(stanza->ctx, stanza);
released = 1; released = 1;
} }
return released; return released;
@@ -274,17 +274,17 @@ static char *_escape_xml(xmpp_ctx_t * const ctx, char *text)
/* small helper function */ /* small helper function */
static void _render_update(int *written, const int length, static void _render_update(int *written, const int length,
const int lastwrite, const int lastwrite,
size_t *left, char **ptr) size_t *left, char **ptr)
{ {
*written += lastwrite; *written += lastwrite;
if (*written >= length) { if (*written >= length) {
*left = 0; *left = 0;
*ptr = NULL; *ptr = NULL;
} else { } else {
*left -= lastwrite; *left -= lastwrite;
*ptr = &(*ptr)[lastwrite]; *ptr = &(*ptr)[lastwrite];
} }
} }
@@ -294,7 +294,7 @@ static void _render_update(int *written, const int length,
* and return values > buflen indicate buffer was not large enough * and return values > buflen indicate buffer was not large enough
*/ */
static int _render_stanza_recursive(xmpp_stanza_t *stanza, static int _render_stanza_recursive(xmpp_stanza_t *stanza,
char * const buf, size_t const buflen) char * const buf, size_t const buflen)
{ {
char *ptr = buf; char *ptr = buf;
size_t left = buflen; size_t left = buflen;
@@ -309,86 +309,80 @@ static int _render_stanza_recursive(xmpp_stanza_t *stanza,
if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP;
if (stanza->type == XMPP_STANZA_TEXT) { if (stanza->type == XMPP_STANZA_TEXT) {
if (!stanza->data) return XMPP_EINVOP; if (!stanza->data) return XMPP_EINVOP;
tmp = _escape_xml(stanza->ctx, stanza->data); tmp = _escape_xml(stanza->ctx, stanza->data);
if (tmp == NULL) return XMPP_EMEM; if (tmp == NULL) return XMPP_EMEM;
ret = xmpp_snprintf(ptr, left, "%s", tmp); ret = xmpp_snprintf(ptr, left, "%s", tmp);
xmpp_free(stanza->ctx, tmp); xmpp_free(stanza->ctx, tmp);
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
} else { /* stanza->type == XMPP_STANZA_TAG */ } else { /* stanza->type == XMPP_STANZA_TAG */
if (!stanza->data) return XMPP_EINVOP; if (!stanza->data) return XMPP_EINVOP;
/* write beginning of tag and attributes */ /* write beginning of tag and attributes */
ret = xmpp_snprintf(ptr, left, "<%s", stanza->data); ret = xmpp_snprintf(ptr, left, "<%s", stanza->data);
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) { if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) {
iter = hash_iter_new(stanza->attributes); iter = hash_iter_new(stanza->attributes);
while ((key = hash_iter_next(iter))) { while ((key = hash_iter_next(iter))) {
if (!strcmp(key, "xmlns")) { if (!strcmp(key, "xmlns")) {
/* don't output namespace if parent stanza is the same */ /* don't output namespace if parent stanza is the same */
if (stanza->parent && if (stanza->parent &&
stanza->parent->attributes && stanza->parent->attributes &&
hash_get(stanza->parent->attributes, key) && hash_get(stanza->parent->attributes, key) &&
!strcmp((char*)hash_get(stanza->attributes, key), !strcmp((char*)hash_get(stanza->attributes, key),
(char*)hash_get(stanza->parent->attributes, key))) (char*)hash_get(stanza->parent->attributes, key)))
continue; continue;
/* or if this is the stream namespace */ /* or if this is the stream namespace */
if (!stanza->parent && if (!stanza->parent &&
!strcmp((char*)hash_get(stanza->attributes, key), !strcmp((char*)hash_get(stanza->attributes, key),
XMPP_NS_CLIENT)) XMPP_NS_CLIENT))
continue; continue;
} }
tmp = _escape_xml(stanza->ctx, tmp = _escape_xml(stanza->ctx,
(char *)hash_get(stanza->attributes, key)); (char *)hash_get(stanza->attributes, key));
if (tmp == NULL) { if (tmp == NULL) return XMPP_EMEM;
hash_iter_release(iter); ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp);
return XMPP_EMEM; xmpp_free(stanza->ctx, tmp);
} if (ret < 0) return XMPP_EMEM;
ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp); _render_update(&written, buflen, ret, &left, &ptr);
xmpp_free(stanza->ctx, tmp); }
if (ret < 0) { hash_iter_release(iter);
hash_iter_release(iter); }
return XMPP_EMEM;
}
_render_update(&written, buflen, ret, &left, &ptr);
}
hash_iter_release(iter);
}
if (!stanza->children) { if (!stanza->children) {
/* write end if singleton tag */ /* write end if singleton tag */
ret = xmpp_snprintf(ptr, left, "/>"); ret = xmpp_snprintf(ptr, left, "/>");
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
} else { } else {
/* this stanza has child stanzas */ /* this stanza has child stanzas */
/* write end of start tag */ /* write end of start tag */
ret = xmpp_snprintf(ptr, left, ">"); ret = xmpp_snprintf(ptr, left, ">");
if (ret < 0) return XMPP_EMEM; if (ret < 0) return XMPP_EMEM;
_render_update(&written, buflen, ret, &left, &ptr); _render_update(&written, buflen, ret, &left, &ptr);
/* iterate and recurse over child stanzas */
child = stanza->children;
while (child) {
ret = _render_stanza_recursive(child, ptr, left);
if (ret < 0) return ret;
/* iterate and recurse over child stanzas */ _render_update(&written, buflen, ret, &left, &ptr);
child = stanza->children;
while (child) {
ret = _render_stanza_recursive(child, ptr, left);
if (ret < 0) return ret;
_render_update(&written, buflen, ret, &left, &ptr); child = child->next;
}
child = child->next; /* write end tag */
} ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data);
if (ret < 0) return XMPP_EMEM;
/* write end tag */
ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data); _render_update(&written, buflen, ret, &left, &ptr);
if (ret < 0) return XMPP_EMEM; }
_render_update(&written, buflen, ret, &left, &ptr);
}
} }
return written; return written;
@@ -421,37 +415,27 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
length = 1024; length = 1024;
buffer = xmpp_alloc(stanza->ctx, length); buffer = xmpp_alloc(stanza->ctx, length);
if (!buffer) { if (!buffer) {
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return XMPP_EMEM; return XMPP_EMEM;
} }
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if (ret < 0) { if (ret < 0) return ret;
xmpp_free(stanza->ctx, buffer);
*buf = NULL;
*buflen = 0;
return ret;
}
if ((size_t)ret > length - 1) { if ((size_t)ret > length - 1) {
tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1); tmp = xmpp_realloc(stanza->ctx, buffer, ret + 1);
if (!tmp) { if (!tmp) {
xmpp_free(stanza->ctx, buffer); xmpp_free(stanza->ctx, buffer);
*buf = NULL; *buf = NULL;
*buflen = 0; *buflen = 0;
return XMPP_EMEM; return XMPP_EMEM;
} }
length = ret + 1; length = ret + 1;
buffer = tmp; buffer = tmp;
ret = _render_stanza_recursive(stanza, buffer, length); ret = _render_stanza_recursive(stanza, buffer, length);
if ((size_t)ret > length - 1) { if ((size_t)ret > length - 1) return XMPP_EMEM;
xmpp_free(stanza->ctx, buffer);
*buf = NULL;
*buflen = 0;
return XMPP_EMEM;
}
} }
buffer[length - 1] = 0; buffer[length - 1] = 0;
@@ -473,7 +457,7 @@ int xmpp_stanza_to_text(xmpp_stanza_t *stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_name(xmpp_stanza_t *stanza, int xmpp_stanza_set_name(xmpp_stanza_t *stanza,
const char * const name) const char * const name)
{ {
if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TEXT) return XMPP_EINVOP;
@@ -512,7 +496,7 @@ const char *xmpp_stanza_get_name(xmpp_stanza_t * const stanza)
int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza) int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
{ {
if (stanza->attributes == NULL) { if (stanza->attributes == NULL) {
return 0; return 0;
} }
return hash_num_keys(stanza->attributes); return hash_num_keys(stanza->attributes);
@@ -533,30 +517,30 @@ int xmpp_stanza_get_attribute_count(xmpp_stanza_t * const stanza)
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza, int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
const char **attr, int attrlen) const char **attr, int attrlen)
{ {
hash_iterator_t *iter; hash_iterator_t *iter;
const char *key; const char *key;
int num = 0; int num = 0;
if (stanza->attributes == NULL) { if (stanza->attributes == NULL) {
return 0; return 0;
} }
iter = hash_iter_new(stanza->attributes); iter = hash_iter_new(stanza->attributes);
while ((key = hash_iter_next(iter)) != NULL && attrlen) { while ((key = hash_iter_next(iter)) != NULL && attrlen) {
attr[num++] = key; attr[num++] = key;
attrlen--; attrlen--;
if (attrlen == 0) { if (attrlen == 0) {
hash_iter_release(iter); hash_iter_release(iter);
return num; return num;
} }
attr[num++] = hash_get(stanza->attributes, key); attr[num++] = hash_get(stanza->attributes, key);
attrlen--; attrlen--;
if (attrlen == 0) { if (attrlen == 0) {
hash_iter_release(iter); hash_iter_release(iter);
return num; return num;
} }
} }
hash_iter_release(iter); hash_iter_release(iter);
@@ -574,8 +558,8 @@ int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza, int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
const char * const key, const char * const key,
const char * const value) const char * const value)
{ {
char *val; char *val;
int rc; int rc;
@@ -583,12 +567,13 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP;
if (!stanza->attributes) { if (!stanza->attributes) {
stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free); stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free);
if (!stanza->attributes) return XMPP_EMEM; if (!stanza->attributes) return XMPP_EMEM;
} }
val = xmpp_strdup(stanza->ctx, value); val = xmpp_strdup(stanza->ctx, value);
if (!val) { if (!val) {
hash_release(stanza->attributes);
return XMPP_EMEM; return XMPP_EMEM;
} }
@@ -613,7 +598,7 @@ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza, int xmpp_stanza_set_ns(xmpp_stanza_t * const stanza,
const char * const ns) const char * const ns)
{ {
return xmpp_stanza_set_attribute(stanza, "xmlns", ns); return xmpp_stanza_set_attribute(stanza, "xmlns", ns);
} }
@@ -639,12 +624,12 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
child->parent = stanza; child->parent = stanza;
if (!stanza->children) if (!stanza->children)
stanza->children = child; stanza->children = child;
else { else {
s = stanza->children; s = stanza->children;
while (s->next) s = s->next; while (s->next) s = s->next;
s->next = child; s->next = child;
child->prev = s; child->prev = s;
} }
return XMPP_EOK; return XMPP_EOK;
@@ -664,7 +649,7 @@ int xmpp_stanza_add_child(xmpp_stanza_t *stanza, xmpp_stanza_t *child)
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_text(xmpp_stanza_t *stanza, int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
const char * const text) const char * const text)
{ {
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
@@ -691,8 +676,8 @@ int xmpp_stanza_set_text(xmpp_stanza_t *stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza, int xmpp_stanza_set_text_with_size(xmpp_stanza_t *stanza,
const char * const text, const char * const text,
const size_t size) const size_t size)
{ {
if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TAG) return XMPP_EINVOP;
@@ -795,14 +780,14 @@ const char *xmpp_stanza_get_from(xmpp_stanza_t * const stanza)
* @ingroup Stanza * @ingroup Stanza
*/ */
xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
const char * const name) const char * const name)
{ {
xmpp_stanza_t *child; xmpp_stanza_t *child;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
if (child->type == XMPP_STANZA_TAG && if (child->type == XMPP_STANZA_TAG &&
(strcmp(name, xmpp_stanza_get_name(child)) == 0)) (strcmp(name, xmpp_stanza_get_name(child)) == 0))
break; break;
} }
return child; return child;
@@ -821,15 +806,14 @@ xmpp_stanza_t *xmpp_stanza_get_child_by_name(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza, xmpp_stanza_t *xmpp_stanza_get_child_by_ns(xmpp_stanza_t * const stanza,
const char * const ns) const char * const ns)
{ {
xmpp_stanza_t *child; xmpp_stanza_t *child;
const char *child_ns;
for (child = stanza->children; child; child = child->next) { for (child = stanza->children; child; child = child->next) {
child_ns = xmpp_stanza_get_ns(child); if (xmpp_stanza_get_ns(child) &&
if (child_ns && strcmp(ns, child_ns) == 0) strcmp(ns, xmpp_stanza_get_ns(child)) == 0)
break; break;
} }
return child; return child;
@@ -882,16 +866,16 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
char *text; char *text;
if (stanza->type == XMPP_STANZA_TEXT) { if (stanza->type == XMPP_STANZA_TEXT) {
if (stanza->data) if (stanza->data)
return xmpp_strdup(stanza->ctx, stanza->data); return xmpp_strdup(stanza->ctx, stanza->data);
else else
return NULL; return NULL;
} }
len = 0; len = 0;
for (child = stanza->children; child; child = child->next) for (child = stanza->children; child; child = child->next)
if (child->type == XMPP_STANZA_TEXT) if (child->type == XMPP_STANZA_TEXT)
len += strlen(child->data); len += strlen(child->data);
if (len == 0) return NULL; if (len == 0) return NULL;
@@ -900,11 +884,11 @@ char *xmpp_stanza_get_text(xmpp_stanza_t * const stanza)
len = 0; len = 0;
for (child = stanza->children; child; child = child->next) for (child = stanza->children; child; child = child->next)
if (child->type == XMPP_STANZA_TEXT) { if (child->type == XMPP_STANZA_TEXT) {
clen = strlen(child->data); clen = strlen(child->data);
memcpy(&text[len], child->data, clen); memcpy(&text[len], child->data, clen);
len += clen; len += clen;
} }
text[len] = 0; text[len] = 0;
@@ -927,7 +911,7 @@ 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_text_ptr(xmpp_stanza_t * const stanza)
{ {
if (stanza->type == XMPP_STANZA_TEXT) if (stanza->type == XMPP_STANZA_TEXT)
return stanza->data; return stanza->data;
return NULL; return NULL;
} }
@@ -944,7 +928,7 @@ const char *xmpp_stanza_get_text_ptr(xmpp_stanza_t * const stanza)
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_id(xmpp_stanza_t * const stanza, int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
const char * const id) const char * const id)
{ {
return xmpp_stanza_set_attribute(stanza, "id", id); return xmpp_stanza_set_attribute(stanza, "id", id);
} }
@@ -961,7 +945,7 @@ int xmpp_stanza_set_id(xmpp_stanza_t * const stanza,
* @ingroup Stanza * @ingroup Stanza
*/ */
int xmpp_stanza_set_type(xmpp_stanza_t * const stanza, int xmpp_stanza_set_type(xmpp_stanza_t * const stanza,
const char * const type) const char * const type)
{ {
return xmpp_stanza_set_attribute(stanza, "type", type); return xmpp_stanza_set_attribute(stanza, "type", type);
} }
@@ -1017,10 +1001,10 @@ const char *xmpp_stanza_get_attribute(xmpp_stanza_t * const stanza,
const char * const name) const char * const name)
{ {
if (stanza->type != XMPP_STANZA_TAG) if (stanza->type != XMPP_STANZA_TAG)
return NULL; return NULL;
if (!stanza->attributes) if (!stanza->attributes)
return NULL; return NULL;
return hash_get(stanza->attributes, name); return hash_get(stanza->attributes, name);
} }
@@ -1234,122 +1218,3 @@ xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx)
{ {
return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL); return _stanza_new_with_attrs(ctx, "presence", NULL, NULL, NULL);
} }
/** Create an <stream:error/> stanza object with given type and error text.
* The error text is optional and may be NULL.
*
* @param ctx a Strophe context object
* @param type enum of xmpp_error_type_t
* @param text content of a 'text'
*
* @return a new Strophe stanza object
*
* @todo Handle errors in this function
*
* @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 *error = _stanza_new_with_attrs(ctx, "stream:error", NULL, NULL, NULL);
xmpp_stanza_t *error_type = xmpp_stanza_new(ctx);
switch(type) {
case XMPP_SE_BAD_FORMAT:
xmpp_stanza_set_name(error_type, "bad-format");
break;
case XMPP_SE_BAD_NS_PREFIX:
xmpp_stanza_set_name(error_type, "bad-namespace-prefix");
break;
case XMPP_SE_CONFLICT:
xmpp_stanza_set_name(error_type, "conflict");
break;
case XMPP_SE_CONN_TIMEOUT:
xmpp_stanza_set_name(error_type, "connection-timeout");
break;
case XMPP_SE_HOST_GONE:
xmpp_stanza_set_name(error_type, "host-gone");
break;
case XMPP_SE_HOST_UNKNOWN:
xmpp_stanza_set_name(error_type, "host-unknown");
break;
case XMPP_SE_IMPROPER_ADDR:
xmpp_stanza_set_name(error_type, "improper-addressing");
break;
case XMPP_SE_INTERNAL_SERVER_ERROR:
xmpp_stanza_set_name(error_type, "internal-server-error");
break;
case XMPP_SE_INVALID_FROM:
xmpp_stanza_set_name(error_type, "invalid-from");
break;
case XMPP_SE_INVALID_ID:
xmpp_stanza_set_name(error_type, "invalid-id");
break;
case XMPP_SE_INVALID_NS:
xmpp_stanza_set_name(error_type, "invalid-namespace");
break;
case XMPP_SE_INVALID_XML:
xmpp_stanza_set_name(error_type, "invalid-xml");
break;
case XMPP_SE_NOT_AUTHORIZED:
xmpp_stanza_set_name(error_type, "not-authorized");
break;
case XMPP_SE_POLICY_VIOLATION:
xmpp_stanza_set_name(error_type, "policy-violation");
break;
case XMPP_SE_REMOTE_CONN_FAILED:
xmpp_stanza_set_name(error_type, "remote-connection-failed");
break;
case XMPP_SE_RESOURCE_CONSTRAINT:
xmpp_stanza_set_name(error_type, "resource-constraint");
break;
case XMPP_SE_RESTRICTED_XML:
xmpp_stanza_set_name(error_type, "restricted-xml");
break;
case XMPP_SE_SEE_OTHER_HOST:
xmpp_stanza_set_name(error_type, "see-other-host");
break;
case XMPP_SE_SYSTEM_SHUTDOWN:
xmpp_stanza_set_name(error_type, "system-shutdown");
break;
case XMPP_SE_UNDEFINED_CONDITION:
xmpp_stanza_set_name(error_type, "undefined-condition");
break;
case XMPP_SE_UNSUPPORTED_ENCODING:
xmpp_stanza_set_name(error_type, "unsupported-encoding");
break;
case XMPP_SE_UNSUPPORTED_STANZA_TYPE:
xmpp_stanza_set_name(error_type, "unsupported-stanza-type");
break;
case XMPP_SE_UNSUPPORTED_VERSION:
xmpp_stanza_set_name(error_type, "unsupported-version");
break;
case XMPP_SE_XML_NOT_WELL_FORMED:
xmpp_stanza_set_name(error_type, "xml-not-well-formed");
break;
default:
xmpp_stanza_set_name(error_type, "internal-server-error");
break;
}
xmpp_stanza_set_ns(error_type, XMPP_NS_STREAMS_IETF);
xmpp_stanza_add_child(error, error_type);
xmpp_stanza_release(error_type);
if (text) {
xmpp_stanza_t *error_text = xmpp_stanza_new(ctx);
xmpp_stanza_t *content = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(error_text, "text");
xmpp_stanza_set_ns(error_text, XMPP_NS_STREAMS_IETF);
xmpp_stanza_set_text(content, text);
xmpp_stanza_add_child(error_text, content);
xmpp_stanza_release(content);
xmpp_stanza_add_child(error, error_text);
xmpp_stanza_release(error_text);
}
return error;
}

View File

@@ -31,22 +31,6 @@
#include "tls.h" #include "tls.h"
#include "sock.h" #include "sock.h"
/*
* Redefine OPENSSL_VERSION_NUMBER for LibreSSL.
* LibreSSL and OpenSSL use different and incompatible version schemes. Solve
* this issue in the way how nginx project did.
*/
#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
#undef OPENSSL_VERSION_NUMBER
#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
#define OPENSSL_VERSION_NUMBER 0x1010000fL
#elif (LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
#define OPENSSL_VERSION_NUMBER 0x1000200fL
#else
#define OPENSSL_VERSION_NUMBER 0x1000107fL
#endif
#endif
struct _tls { struct _tls {
xmpp_ctx_t *ctx; xmpp_ctx_t *ctx;
sock_t sock; sock_t sock;
@@ -64,7 +48,6 @@ enum {
static void _tls_sock_wait(tls_t *tls, int error); static void _tls_sock_wait(tls_t *tls, int error);
static void _tls_set_error(tls_t *tls, int error); static void _tls_set_error(tls_t *tls, int error);
static void _tls_log_error(xmpp_ctx_t *ctx); static void _tls_log_error(xmpp_ctx_t *ctx);
static void _tls_dump_cert_info(tls_t *tls);
void tls_initialize(void) void tls_initialize(void)
{ {
@@ -205,7 +188,6 @@ int tls_start(tls_t *tls)
x509_res = SSL_get_verify_result(tls->ssl); x509_res = SSL_get_verify_result(tls->ssl);
xmpp_debug(tls->ctx, "tls", "Certificate verification %s", xmpp_debug(tls->ctx, "tls", "Certificate verification %s",
x509_res == X509_V_OK ? "passed" : "FAILED"); x509_res == X509_V_OK ? "passed" : "FAILED");
_tls_dump_cert_info(tls);
_tls_set_error(tls, error); _tls_set_error(tls, error);
return ret <= 0 ? 0 : 1; return ret <= 0 ? 0 : 1;
@@ -217,11 +199,6 @@ int tls_stop(tls_t *tls)
int error; int error;
int ret; int ret;
/* According to OpenSSL.org, we must not call SSL_shutdown(3)
if a previous fatal error has occurred on a connection. */
if (tls->lasterror == SSL_ERROR_SYSCALL || tls->lasterror == SSL_ERROR_SSL)
return 1;
while (1) { while (1) {
++retries; ++retries;
ret = SSL_shutdown(tls->ssl); ret = SSL_shutdown(tls->ssl);
@@ -232,14 +209,6 @@ int tls_stop(tls_t *tls)
} }
_tls_sock_wait(tls, error); _tls_sock_wait(tls, error);
} }
if (error == SSL_ERROR_SYSCALL && errno == 0) {
/*
* Handle special case when peer closes connection instead of
* proper shutdown.
*/
error = 0;
ret = 1;
}
_tls_set_error(tls, error); _tls_set_error(tls, error);
return ret <= 0 ? 0 : 1; return ret <= 0 ? 0 : 1;
@@ -291,8 +260,6 @@ static void _tls_sock_wait(tls_t *tls, int error)
int nfds; int nfds;
int ret; int ret;
if (error == SSL_ERROR_NONE) return;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_ZERO(&wfds); FD_ZERO(&wfds);
if (error == SSL_ERROR_WANT_READ) if (error == SSL_ERROR_WANT_READ)
@@ -311,7 +278,6 @@ static void _tls_sock_wait(tls_t *tls, int error)
static void _tls_set_error(tls_t *tls, int error) static void _tls_set_error(tls_t *tls, int error)
{ {
if (error != 0 && !tls_is_recoverable(error)) { if (error != 0 && !tls_is_recoverable(error)) {
xmpp_debug(tls->ctx, "tls", "error=%d errno=%d", error, errno);
_tls_log_error(tls->ctx); _tls_log_error(tls->ctx);
} }
tls->lasterror = error; tls->lasterror = error;
@@ -330,26 +296,3 @@ static void _tls_log_error(xmpp_ctx_t *ctx)
} }
} while (e != 0); } while (e != 0);
} }
static void _tls_dump_cert_info(tls_t *tls)
{
X509 *cert;
char *name;
cert = SSL_get_peer_certificate(tls->ssl);
if (cert == NULL)
xmpp_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else {
name = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (name != NULL) {
xmpp_debug(tls->ctx, "tls", "Subject=%s", name);
OPENSSL_free(name);
}
name = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
if (name != NULL) {
xmpp_debug(tls->ctx, "tls", "Issuer=%s", name);
OPENSSL_free(name);
}
X509_free(cert);
}
}

View File

@@ -255,18 +255,10 @@ int tls_start(tls_t *tls)
NULL, 0, &(tls->hctxt), &sbdout, NULL, 0, &(tls->hctxt), &sbdout,
&ctxtattr, NULL); &ctxtattr, NULL);
unsigned char *p = sbin[0].pvBuffer;
int len = 0;
while (ret == SEC_I_CONTINUE_NEEDED while (ret == SEC_I_CONTINUE_NEEDED
|| ret == SEC_I_INCOMPLETE_CREDENTIALS || ret == SEC_I_INCOMPLETE_CREDENTIALS) {
|| ret == SEC_E_INCOMPLETE_MESSAGE) { unsigned char *p = sbin[0].pvBuffer;
int inbytes = 0; int len = 0, inbytes = 0;
if (ret != SEC_E_INCOMPLETE_MESSAGE) {
len = 0;
p = sbin[0].pvBuffer;
}
if (sbdout.pBuffers[0].cbBuffer) { if (sbdout.pBuffers[0].cbBuffer) {
unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer; unsigned char *writebuff = sbdout.pBuffers[0].pvBuffer;

View File

@@ -169,10 +169,6 @@ typedef struct _xmpp_stanza_t xmpp_stanza_t;
* Trust server's certificate even if it is invalid. * Trust server's certificate even if it is invalid.
*/ */
#define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3) #define XMPP_CONN_FLAG_TRUST_TLS (1UL << 3)
/** @def XMPP_CONN_FLAG_LEGACY_AUTH
* Enable legacy authentication support.
*/
#define XMPP_CONN_FLAG_LEGACY_AUTH (1UL << 4)
/* connect callback */ /* connect callback */
typedef enum { typedef enum {
@@ -221,7 +217,6 @@ typedef void (*xmpp_conn_handler)(xmpp_conn_t * const conn,
xmpp_stream_error_t * const stream_error, xmpp_stream_error_t * const stream_error,
void * const userdata); void * const 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_new(xmpp_ctx_t * const ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn); xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t * const conn);
int xmpp_conn_release(xmpp_conn_t * const conn); int xmpp_conn_release(xmpp_conn_t * const conn);
@@ -386,8 +381,6 @@ int xmpp_message_set_body(xmpp_stanza_t *msg, const char * const text);
xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type, xmpp_stanza_t *xmpp_iq_new(xmpp_ctx_t *ctx, const char * const type,
const char * const id); const char * const id);
xmpp_stanza_t *xmpp_presence_new(xmpp_ctx_t *ctx); 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);
/* jid */ /* jid */

View File

@@ -16,19 +16,18 @@
#include "strophe.h" #include "strophe.h"
#include "common.h" #include "common.h"
#include "hash.h" #include "hash.h"
#include "test.h"
#define TABLESIZE 100 #define TABLESIZE 100
#define TESTSIZE 500 #define TESTSIZE 500
/* static test data */ /* static test data */
const int nkeys = 5;
const char *keys[] = { const char *keys[] = {
"foo", "bar", "baz", "quux", "xyzzy" "foo", "bar", "baz", "quux", "xyzzy"
}; };
const char *values[] = { const char *values[] = {
"wuzzle", "mug", "canonical", "rosebud", "lottery" "wuzzle", "mug", "canonical", "rosebud", "lottery"
}; };
const int nkeys = ARRAY_SIZE(keys);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -59,7 +58,7 @@ int main(int argc, char **argv)
} }
/* allocate a hash table */ /* allocate a hash table */
table = hash_new(ctx, TABLESIZE, xmpp_free); table = hash_new(ctx, TABLESIZE, NULL);
if (table == NULL) { if (table == NULL) {
/* table allocation failed! */ /* table allocation failed! */
return 1; return 1;
@@ -67,7 +66,7 @@ int main(int argc, char **argv)
/* test insertion */ /* test insertion */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[i], xmpp_strdup(ctx, values[i])); err = hash_add(table, keys[i], (void*)values[i]);
if (err) return err; if (err) return err;
} }
@@ -79,7 +78,7 @@ int main(int argc, char **argv)
/* test replacing old values */ /* test replacing old values */
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
err = hash_add(table, keys[0], xmpp_strdup(ctx, values[i])); err = hash_add(table, keys[0], (void*)values[i]);
if (err) return err; if (err) return err;
if (hash_num_keys(table) != nkeys) return 1; if (hash_num_keys(table) != nkeys) return 1;
result = hash_get(table, keys[0]); result = hash_get(table, keys[0]);
@@ -87,7 +86,7 @@ int main(int argc, char **argv)
if (strcmp(result, values[i]) != 0) return 1; if (strcmp(result, values[i]) != 0) return 1;
} }
/* restore value for the 1st key */ /* restore value for the 1st key */
hash_add(table, keys[0], xmpp_strdup(ctx, values[0])); hash_add(table, keys[0], (void*)values[0]);
/* test cloning */ /* test cloning */
clone = hash_clone(table); clone = hash_clone(table);

View File

@@ -20,16 +20,6 @@
#include "test.h" /* ARRAY_SIZE */ #include "test.h" /* ARRAY_SIZE */
/* strtok_s() has appeared in visual studio 2005.
Use own implementation for older versions. */
#ifdef _MSC_VER
# if (_MSC_VER >= 1400)
# define strtok_r strtok_s
# else
# define strtok_r xmpp_strtok_r
# endif
#endif /* _MSC_VER */
static int test_strtok_r(void) static int test_strtok_r(void)
{ {
const char *test = "-abc-=-def--"; const char *test = "-abc-=-def--";