1 Commits

Author SHA1 Message Date
Dmitry Podgorny
070a64d9d5 WIP Unify error codes returned to the connection handler
Error argument in the connection handler is not always set and in some
cases provides meaningless values. For example, every TLS module returns
its specific error codes.

Current solution unifies error codes and allows to distinguish between
different types of disconnection.

Fixes #123.
2020-09-16 02:28:37 +03:00
11 changed files with 108 additions and 143 deletions

View File

@@ -6,20 +6,18 @@ stages:
- style - style
- test - test
before_script: before_script:
- ./travis/before_script.sh - ./bootstrap.sh
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"
- CONFIGURE_OPT="--enable-cares" - CONFIGURE_OPT="--enable-cares"
- CONFIGURE_OPT="PKG_CONFIG_PATH=${HOME}/libressl/lib/pkgconfig" LIBRESSL=yes LIBRESSL_COMMIT="v3.1.4" script: ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
- CONFIGURE_OPT="PKG_CONFIG_PATH=${HOME}/libressl/lib/pkgconfig" LIBRESSL=yes LIBRESSL_COMMIT="v2.1.7"
script: ./bootstrap.sh && ./configure ${CONFIGURE_OPT} CFLAGS="-Werror" && make && make check
jobs: jobs:
include: include:
- stage: style - stage: style
name: "Check code style" name: "Check code style"
script: ./bootstrap.sh && ./configure && make format && git diff --exit-code script: ./configure && make format && git diff --exit-code
env: env:
- CONFIGURE_OPT="" - CONFIGURE_OPT=""
matrix: matrix:

View File

@@ -1,6 +1,3 @@
0.10.1
- Fixed compilation error when LibreSSL is used
0.10.0 0.10.0
- Coding style has been unified - Coding style has been unified
- SCRAM-SHA-256 and SCRAM-SHA-512 support - SCRAM-SHA-256 and SCRAM-SHA-512 support

View File

@@ -38,7 +38,25 @@ void conn_handler(xmpp_conn_t *const conn,
secured ? "secured" : "NOT secured"); secured ? "secured" : "NOT secured");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else { } else {
fprintf(stderr, "DEBUG: disconnected\n"); switch (error) {
case XMPP_EOK:
fprintf(stderr, "DEBUG: disconnected successfully.\n");
break;
case XMPP_EINVOP:
/*
* This may happen when the requested functionality is not
* supported or some data is not provided when it is required (e.g.
* resource part).
*/
fprintf(stderr, "DEBUG: disconnected, invalid operation.\n");
break;
case XMPP_ECERT:
/*
* In this case, application can reconnect with
* XMPP_CONN_FLAG_TRUST_TLS if user permits.
*/
fprintf(stderr, "DEBUG: disconnected, invalid TLS certificate.\n");
}
xmpp_stop(ctx); xmpp_stop(ctx);
} }
} }
@@ -49,7 +67,6 @@ int main(int argc, char **argv)
xmpp_conn_t *conn; xmpp_conn_t *conn;
xmpp_log_t *log; xmpp_log_t *log;
char *jid, *pass, *host = NULL; char *jid, *pass, *host = NULL;
const char *cafile = NULL;
long flags = 0; long flags = 0;
int tcp_keepalive = 0; int tcp_keepalive = 0;
int i; int i;
@@ -68,15 +85,12 @@ int main(int argc, char **argv)
flags |= XMPP_CONN_FLAG_LEGACY_AUTH; flags |= XMPP_CONN_FLAG_LEGACY_AUTH;
else if (strcmp(argv[i], "--tcp-keepalive") == 0) else if (strcmp(argv[i], "--tcp-keepalive") == 0)
tcp_keepalive = 1; tcp_keepalive = 1;
else if (strncmp(argv[i], "--cafile=", strlen("--cafile=")) == 0)
cafile = argv[i] + strlen("--cafile=");
else else
break; break;
} }
if ((argc - i) < 2 || (argc - i) > 3) { if ((argc - i) < 2 || (argc - i) > 3) {
fprintf(stderr, "Usage: basic [options] <jid> <pass> [<host>]\n\n" fprintf(stderr, "Usage: basic [options] <jid> <pass> [<host>]\n\n"
"Options:\n" "Options:\n"
" --cafile=<PATH> CAfile for cert verification.\n"
" --disable-tls Disable TLS.\n" " --disable-tls Disable TLS.\n"
" --mandatory-tls Deny plaintext connection.\n" " --mandatory-tls Deny plaintext connection.\n"
" --trust-tls Trust TLS certificate.\n" " --trust-tls Trust TLS certificate.\n"
@@ -115,10 +129,6 @@ int main(int argc, char **argv)
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL); xmpp_conn_set_keepalive(conn, KA_TIMEOUT, KA_INTERVAL);
/* add external CAfile if needed */
if (cafile)
xmpp_conn_tls_cafile(conn, cafile);
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_jid(conn, jid); xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_pass(conn, pass); xmpp_conn_set_pass(conn, pass);

View File

@@ -346,9 +346,10 @@ static int _handle_sasl_result(xmpp_conn_t *const conn,
} else { } else {
/* got unexpected reply */ /* got unexpected reply */
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Got unexpected reply to SASL %s authentication.", "Got unexpected reply to SASL %s"
"authentication.",
(char *)userdata); (char *)userdata);
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} }
return 0; return 0;
@@ -643,7 +644,7 @@ static void _auth(xmpp_conn_t *const conn)
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"TLS is not supported, but set as " "TLS is not supported, but set as "
"mandatory for this connection"); "mandatory for this connection");
conn_disconnect(conn); disconnect_with_error(conn, XMPP_EINVOP);
return; return;
} }
@@ -666,11 +667,7 @@ static void _auth(xmpp_conn_t *const conn)
} else if (anonjid) { } else if (anonjid) {
xmpp_error(conn->ctx, "auth", xmpp_error(conn->ctx, "auth",
"No node in JID, and SASL ANONYMOUS unsupported."); "No node in JID, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINVOP);
} else if (conn->pass == NULL) {
xmpp_error(conn->ctx, "auth",
"Password hasn't been set, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAM) { } else if (conn->sasl_support & SASL_MASK_SCRAM) {
scram_ctx = xmpp_alloc(conn->ctx, sizeof(*scram_ctx)); scram_ctx = xmpp_alloc(conn->ctx, sizeof(*scram_ctx));
if (conn->sasl_support & SASL_MASK_SCRAMSHA512) if (conn->sasl_support & SASL_MASK_SCRAMSHA512)
@@ -783,7 +780,7 @@ static void _auth(xmpp_conn_t *const conn)
_auth_legacy(conn); _auth_legacy(conn);
} else { } else {
xmpp_error(conn->ctx, "auth", "Cannot authenticate with known methods"); xmpp_error(conn->ctx, "auth", "Cannot authenticate with known methods");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EAUTH);
} }
} }
@@ -933,7 +930,7 @@ static int _handle_features_sasl(xmpp_conn_t *const conn,
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Stream features does not allow " "Stream features does not allow "
"resource bind."); "resource bind.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} }
return 0; return 0;
@@ -947,7 +944,7 @@ static int _handle_missing_features_sasl(xmpp_conn_t *const conn,
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Did not receive stream features " "Did not receive stream features "
"after SASL authentication."); "after SASL authentication.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_ETIMEDOUT);
return 0; return 0;
} }
@@ -967,7 +964,7 @@ static int _handle_bind(xmpp_conn_t *const conn,
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (type && strcmp(type, "error") == 0) { if (type && strcmp(type, "error") == 0) {
xmpp_error(conn->ctx, "xmpp", "Binding failed."); xmpp_error(conn->ctx, "xmpp", "Binding failed.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} else if (type && strcmp(type, "result") == 0) { } else if (type && strcmp(type, "result") == 0) {
xmpp_stanza_t *binding = xmpp_stanza_get_child_by_name(stanza, "bind"); xmpp_stanza_t *binding = xmpp_stanza_get_child_by_name(stanza, "bind");
xmpp_debug(conn->ctx, "xmpp", "Bind successful."); xmpp_debug(conn->ctx, "xmpp", "Bind successful.");
@@ -1019,7 +1016,7 @@ static int _handle_bind(xmpp_conn_t *const conn,
} }
} else { } else {
xmpp_error(conn->ctx, "xmpp", "Server sent malformed bind reply."); xmpp_error(conn->ctx, "xmpp", "Server sent malformed bind reply.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} }
return 0; return 0;
@@ -1030,7 +1027,7 @@ static int _handle_missing_bind(xmpp_conn_t *const conn, void *const userdata)
UNUSED(userdata); UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp", "Server did not reply to bind request."); xmpp_error(conn->ctx, "xmpp", "Server did not reply to bind request.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_ETIMEDOUT);
return 0; return 0;
} }
@@ -1049,7 +1046,7 @@ static int _handle_session(xmpp_conn_t *const conn,
type = xmpp_stanza_get_type(stanza); type = xmpp_stanza_get_type(stanza);
if (type && strcmp(type, "error") == 0) { if (type && strcmp(type, "error") == 0) {
xmpp_error(conn->ctx, "xmpp", "Session establishment failed."); xmpp_error(conn->ctx, "xmpp", "Session establishment failed.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} else if (type && strcmp(type, "result") == 0) { } else if (type && strcmp(type, "result") == 0) {
xmpp_debug(conn->ctx, "xmpp", "Session establishment successful."); xmpp_debug(conn->ctx, "xmpp", "Session establishment successful.");
@@ -1059,7 +1056,7 @@ static int _handle_session(xmpp_conn_t *const conn,
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata); conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
} else { } else {
xmpp_error(conn->ctx, "xmpp", "Server sent malformed session reply."); xmpp_error(conn->ctx, "xmpp", "Server sent malformed session reply.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} }
return 0; return 0;
@@ -1071,7 +1068,7 @@ static int _handle_missing_session(xmpp_conn_t *const conn,
UNUSED(userdata); UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp", "Server did not reply to session request."); xmpp_error(conn->ctx, "xmpp", "Server did not reply to session request.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_ETIMEDOUT);
return 0; return 0;
} }
@@ -1082,7 +1079,7 @@ static int _handle_missing_legacy(xmpp_conn_t *const conn, void *const userdata)
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Server did not reply to legacy " "Server did not reply to legacy "
"authentication request."); "authentication request.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_ETIMEDOUT);
return 0; return 0;
} }
@@ -1105,11 +1102,11 @@ static int _handle_legacy(xmpp_conn_t *const conn,
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Server sent us an unexpected response " "Server sent us an unexpected response "
"to legacy authentication request."); "to legacy authentication request.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} else if (strcmp(type, "error") == 0) { } else if (strcmp(type, "error") == 0) {
/* legacy client auth failed, no more fallbacks */ /* legacy client auth failed, no more fallbacks */
xmpp_error(conn->ctx, "xmpp", "Legacy client authentication failed."); xmpp_error(conn->ctx, "xmpp", "Legacy client authentication failed.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EAUTH);
} else if (strcmp(type, "result") == 0) { } else if (strcmp(type, "result") == 0) {
/* auth succeeded */ /* auth succeeded */
xmpp_debug(conn->ctx, "xmpp", "Legacy auth succeeded."); xmpp_debug(conn->ctx, "xmpp", "Legacy auth succeeded.");
@@ -1120,7 +1117,7 @@ static int _handle_legacy(xmpp_conn_t *const conn,
xmpp_error(conn->ctx, "xmpp", xmpp_error(conn->ctx, "xmpp",
"Server sent us a legacy authentication " "Server sent us a legacy authentication "
"response with a bad type."); "response with a bad type.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINT);
} }
return 0; return 0;
@@ -1200,7 +1197,7 @@ static void _auth_legacy(xmpp_conn_t *conn)
xmpp_stanza_release(authdata); xmpp_stanza_release(authdata);
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource"); xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EINVOP);
return; return;
} }
xmpp_stanza_add_child(child, authdata); xmpp_stanza_add_child(child, authdata);
@@ -1234,7 +1231,7 @@ void auth_handle_component_open(xmpp_conn_t *const conn)
rc = _handle_component_auth(conn); rc = _handle_component_auth(conn);
if (rc != 0) { if (rc != 0) {
xmpp_error(conn->ctx, "auth", "Component authentication failed."); xmpp_error(conn->ctx, "auth", "Component authentication failed.");
xmpp_disconnect(conn); disconnect_with_error(conn, rc);
} }
} }
@@ -1301,15 +1298,8 @@ int _handle_component_hs_response(xmpp_conn_t *const conn,
name = xmpp_stanza_get_name(stanza); name = xmpp_stanza_get_name(stanza);
if (strcmp(name, "handshake") != 0) { if (strcmp(name, "handshake") != 0) {
char *msg; xmpp_debug(conn->ctx, "auth", "Handshake failed.");
size_t msg_size; disconnect_with_error(conn, XMPP_EINT);
xmpp_stanza_to_text(stanza, &msg, &msg_size);
if (msg) {
xmpp_debug(conn->ctx, "auth", "Handshake failed: %s", msg);
xmpp_free(conn->ctx, msg);
}
xmpp_disconnect(conn);
return XMPP_EINT;
} else { } else {
conn->authenticated = 1; conn->authenticated = 1;
conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata); conn->conn_handler(conn, XMPP_CONN_CONNECT, 0, NULL, conn->userdata);
@@ -1326,7 +1316,7 @@ int _handle_missing_handshake(xmpp_conn_t *const conn, void *const userdata)
UNUSED(userdata); UNUSED(userdata);
xmpp_error(conn->ctx, "xmpp", "Server did not reply to handshake request."); xmpp_error(conn->ctx, "xmpp", "Server did not reply to handshake request.");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_ETIMEDOUT);
return 0; return 0;
} }

View File

@@ -171,7 +171,6 @@ struct _xmpp_conn_t {
int ka_interval; /* TCP keepalive interval */ int ka_interval; /* TCP keepalive interval */
tls_t *tls; tls_t *tls;
char *tls_cafile;
int tls_support; int tls_support;
int tls_disabled; int tls_disabled;
int tls_mandatory; int tls_mandatory;
@@ -277,6 +276,7 @@ void handler_add(xmpp_conn_t *const conn,
void handler_system_delete_all(xmpp_conn_t *conn); void handler_system_delete_all(xmpp_conn_t *conn);
/* utility functions */ /* utility functions */
void disconnect_with_error(xmpp_conn_t *const conn, int error);
void disconnect_mem_error(xmpp_conn_t *const conn); void disconnect_mem_error(xmpp_conn_t *const conn);
/* auth functions */ /* auth functions */

View File

@@ -137,7 +137,6 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *const ctx)
conn->bound_jid = NULL; conn->bound_jid = NULL;
conn->is_raw = 0; conn->is_raw = 0;
conn->tls_cafile = NULL;
conn->tls_support = 0; conn->tls_support = 0;
conn->tls_disabled = 0; conn->tls_disabled = 0;
conn->tls_mandatory = 0; conn->tls_mandatory = 0;
@@ -339,8 +338,6 @@ int xmpp_conn_release(xmpp_conn_t *const conn)
xmpp_free(ctx, conn->pass); xmpp_free(ctx, conn->pass);
if (conn->lang) if (conn->lang)
xmpp_free(ctx, conn->lang); xmpp_free(ctx, conn->lang);
if (conn->tls_cafile)
xmpp_free(ctx, conn->tls_cafile);
xmpp_free(ctx, conn); xmpp_free(ctx, conn);
released = 1; released = 1;
} }
@@ -423,7 +420,7 @@ void xmpp_conn_set_pass(xmpp_conn_t *const conn, const char *const pass)
{ {
if (conn->pass) if (conn->pass)
xmpp_free(conn->ctx, conn->pass); xmpp_free(conn->ctx, conn->pass);
conn->pass = pass ? xmpp_strdup(conn->ctx, pass) : NULL; conn->pass = xmpp_strdup(conn->ctx, pass);
} }
/** Get the strophe context that the connection is associated with. /** Get the strophe context that the connection is associated with.
@@ -689,28 +686,6 @@ int xmpp_conn_tls_start(xmpp_conn_t *const conn)
return conn_tls_start(conn); return conn_tls_start(conn);
} }
/** Set external CAfile which will be used for TLS cert verification.
*
* @return XMPP_EOK (0) on success a number less than 0 on failure
*
* @ingroup Connections
*/
int xmpp_conn_tls_cafile(xmpp_conn_t *const conn, const char *cafile)
{
FILE *f;
f = fopen(cafile, "r");
if (f == NULL) {
xmpp_debug(conn->ctx, "conn", "CAfile '%s' is not readable. errno=%d",
cafile, errno);
return XMPP_EINVOP;
}
fclose(f);
conn->tls_cafile = xmpp_strdup(conn->ctx, cafile);
return conn->tls_cafile == NULL ? XMPP_EMEM : XMPP_EOK;
}
/** Cleanly disconnect the connection. /** Cleanly disconnect the connection.
* This function is only called by the stream parser when </stream:stream> * This function is only called by the stream parser when </stream:stream>
* is received, and it not intended to be called by code outside of Strophe. * is received, and it not intended to be called by code outside of Strophe.
@@ -940,15 +915,11 @@ int conn_tls_start(xmpp_conn_t *const conn)
} }
if (conn->tls != NULL) { if (conn->tls != NULL) {
if (conn->tls_cafile != NULL) {
(void)tls_set_credentials(conn->tls, conn->tls_cafile);
}
if (tls_start(conn->tls)) { if (tls_start(conn->tls)) {
conn->secured = 1; conn->secured = 1;
} else { } else {
rc = XMPP_EINT; /* TODO: distinguish invalid certificates and other errors */
conn->error = tls_error(conn->tls); rc = XMPP_ECERT;
tls_free(conn->tls); tls_free(conn->tls);
conn->tls = NULL; conn->tls = NULL;
conn->tls_failed = 1; conn->tls_failed = 1;
@@ -956,9 +927,9 @@ int conn_tls_start(xmpp_conn_t *const conn)
} }
if (rc != 0) { if (rc != 0) {
xmpp_debug(conn->ctx, "conn", xmpp_debug(conn->ctx, "conn",
"Couldn't start TLS! " "Couldn't start TLS! error %d tls_error %d", rc,
"error %d tls_error %d", conn->tls == NULL ? 0 : tls_error(conn->tls));
rc, conn->error); conn->error = rc;
} }
return rc; return rc;
} }
@@ -1098,6 +1069,7 @@ static int _disconnect_cleanup(xmpp_conn_t *const conn, void *const userdata)
xmpp_debug(conn->ctx, "xmpp", "disconnection forced by cleanup timeout"); xmpp_debug(conn->ctx, "xmpp", "disconnection forced by cleanup timeout");
conn->error = conn->error ?: XMPP_ETIMEDOUT;
conn_disconnect(conn); conn_disconnect(conn);
return 0; return 0;
@@ -1224,7 +1196,7 @@ static void _handle_stream_start(char *name, char **attrs, void *const userdata)
{ {
xmpp_conn_t *conn = (xmpp_conn_t *)userdata; xmpp_conn_t *conn = (xmpp_conn_t *)userdata;
char *id; char *id;
int failed = 0; int ret = 0;
if (conn->stream_id) if (conn->stream_id)
xmpp_free(conn->ctx, conn->stream_id); xmpp_free(conn->ctx, conn->stream_id);
@@ -1238,20 +1210,21 @@ static void _handle_stream_start(char *name, char **attrs, void *const userdata)
if (id && !conn->stream_id) { if (id && !conn->stream_id) {
xmpp_error(conn->ctx, "conn", "Memory allocation failed."); xmpp_error(conn->ctx, "conn", "Memory allocation failed.");
failed = 1; ret = XMPP_EMEM;
} }
} else { } else {
xmpp_error(conn->ctx, "conn", xmpp_error(conn->ctx, "conn",
"Server did not open valid stream." "Server did not open valid stream."
" name = %s.", " name = %s.",
name); name);
failed = 1; ret = XMPP_EINT;
} }
if (!failed) { if (ret == 0) {
/* call stream open handler */ /* call stream open handler */
conn->open_handler(conn); conn->open_handler(conn);
} else { } else {
conn->error = ret;
conn_disconnect(conn); conn_disconnect(conn);
} }
} }

View File

@@ -41,15 +41,6 @@
#define _sleep(x) usleep((x)*1000) #define _sleep(x) usleep((x)*1000)
#else #else
#include <winsock2.h> #include <winsock2.h>
#ifndef ETIMEDOUT
#define ETIMEDOUT WSAETIMEDOUT
#endif
#ifndef ECONNRESET
#define ECONNRESET WSAECONNRESET
#endif
#ifndef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
#endif
#define _sleep(x) Sleep(x) #define _sleep(x) Sleep(x)
#endif #endif
@@ -107,25 +98,23 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) {
/* an error occurred */ /* an error occurred */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting."); conn->error = XMPP_EIO;
conn->error = ECONNABORTED;
conn_disconnect(conn);
} }
} }
/* write all data from the send queue to the socket */ /* write all data from the send queue to the socket */
sq = conn->send_queue_head; sq = conn->send_queue_head;
while (sq) { while (!conn->error && sq) {
towrite = sq->len - sq->written; towrite = sq->len - sq->written;
if (conn->tls) { if (conn->tls) {
ret = tls_write(conn->tls, &sq->data[sq->written], towrite); ret = tls_write(conn->tls, &sq->data[sq->written], towrite);
if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls)))
conn->error = tls_error(conn->tls); conn->error = XMPP_EIO;
} else { } else {
ret = sock_write(conn->sock, &sq->data[sq->written], towrite); ret = sock_write(conn->sock, &sq->data[sq->written], towrite);
if (ret < 0 && !sock_is_recoverable(sock_error())) if (ret < 0 && !sock_is_recoverable(sock_error()))
conn->error = sock_error(); conn->error = XMPP_EIO;
} }
if (ret > 0 && ret < towrite) if (ret > 0 && ret < towrite)
sq->written += ret; /* not all data could be sent now */ sq->written += ret; /* not all data could be sent now */
@@ -151,7 +140,6 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
/* FIXME: need to tear down send queues and random other things /* FIXME: need to tear down send queues and random other things
* maybe this should be abstracted */ * maybe this should be abstracted */
xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting."); xmpp_debug(ctx, "xmpp", "Send error occurred, disconnecting.");
conn->error = ECONNABORTED;
conn_disconnect(conn); conn_disconnect(conn);
} }
@@ -190,8 +178,8 @@ 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 {
conn->error = ETIMEDOUT;
xmpp_info(ctx, "xmpp", "Connection attempt timed out."); xmpp_info(ctx, "xmpp", "Connection attempt timed out.");
conn->error = XMPP_ETIMEDOUT;
conn_disconnect(conn); conn_disconnect(conn);
} }
break; break;
@@ -252,6 +240,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
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);
conn->error = XMPP_EIO;
conn_disconnect(conn); conn_disconnect(conn);
break; break;
} }
@@ -285,14 +274,14 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout)
xmpp_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp",
"Unrecoverable TLS error, %d.", "Unrecoverable TLS error, %d.",
tls_error(conn->tls)); tls_error(conn->tls));
conn->error = tls_error(conn->tls); conn->error = XMPP_EIO;
conn_disconnect(conn); conn_disconnect(conn);
} }
} else { } else {
/* return of 0 means socket closed by server */ /* return of 0 means socket closed by server */
xmpp_debug(ctx, "xmpp", xmpp_debug(ctx, "xmpp",
"Socket closed by remote host."); "Socket closed by remote host.");
conn->error = ECONNRESET; conn->error = ret == 0 ? XMPP_ERESET : XMPP_EIO;
conn_disconnect(conn); conn_disconnect(conn);
} }
} }

View File

@@ -81,7 +81,6 @@ const char *tls_errors[] = {
TLS_ERROR_FIELD(SSL_ERROR_ZERO_RETURN), TLS_ERROR_FIELD(SSL_ERROR_ZERO_RETURN),
TLS_ERROR_FIELD(SSL_ERROR_WANT_CONNECT), TLS_ERROR_FIELD(SSL_ERROR_WANT_CONNECT),
TLS_ERROR_FIELD(SSL_ERROR_WANT_ACCEPT), TLS_ERROR_FIELD(SSL_ERROR_WANT_ACCEPT),
#ifndef LIBRESSL_VERSION_NUMBER
#if OPENSSL_VERSION_NUMBER >= 0x10100000L #if OPENSSL_VERSION_NUMBER >= 0x10100000L
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC), TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC),
TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC_JOB), TLS_ERROR_FIELD(SSL_ERROR_WANT_ASYNC_JOB),
@@ -89,7 +88,6 @@ const char *tls_errors[] = {
#if OPENSSL_VERSION_NUMBER >= 0x10101000L #if OPENSSL_VERSION_NUMBER >= 0x10101000L
TLS_ERROR_FIELD(SSL_ERROR_WANT_CLIENT_HELLO_CB), TLS_ERROR_FIELD(SSL_ERROR_WANT_CLIENT_HELLO_CB),
#endif #endif
#endif /* !LIBRESSL_VERSION_NUMBER */
}; };
const char *cert_errors[] = { const char *cert_errors[] = {
TLS_ERROR_FIELD(X509_V_OK), TLS_ERROR_FIELD(X509_V_OK),
@@ -150,34 +148,30 @@ const char *cert_errors[] = {
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX), TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX),
TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX), TLS_ERROR_FIELD(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX),
TLS_ERROR_FIELD(X509_V_ERR_CRL_PATH_VALIDATION_ERROR), TLS_ERROR_FIELD(X509_V_ERR_CRL_PATH_VALIDATION_ERROR),
#ifndef LIBRESSL_VERSION_NUMBER
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_VERSION), TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_VERSION),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_ALGORITHM), TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_ALGORITHM),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_CURVE), TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_CURVE),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM), TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED), TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED),
TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256), TLS_ERROR_FIELD(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256),
#endif /* !LIBRESSL_VERSION_NUMBER */
TLS_ERROR_FIELD(X509_V_ERR_HOSTNAME_MISMATCH), TLS_ERROR_FIELD(X509_V_ERR_HOSTNAME_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_EMAIL_MISMATCH), TLS_ERROR_FIELD(X509_V_ERR_EMAIL_MISMATCH),
TLS_ERROR_FIELD(X509_V_ERR_IP_ADDRESS_MISMATCH), TLS_ERROR_FIELD(X509_V_ERR_IP_ADDRESS_MISMATCH),
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ #endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000L #if OPENSSL_VERSION_NUMBER >= 0x10100000L
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CALL),
TLS_ERROR_FIELD(X509_V_ERR_STORE_LOOKUP),
#ifndef LIBRESSL_VERSION_NUMBER
TLS_ERROR_FIELD(X509_V_ERR_PATH_LOOP), TLS_ERROR_FIELD(X509_V_ERR_PATH_LOOP),
TLS_ERROR_FIELD(X509_V_ERR_DANE_NO_MATCH), TLS_ERROR_FIELD(X509_V_ERR_DANE_NO_MATCH),
TLS_ERROR_FIELD(X509_V_ERR_EE_KEY_TOO_SMALL), TLS_ERROR_FIELD(X509_V_ERR_EE_KEY_TOO_SMALL),
TLS_ERROR_FIELD(X509_V_ERR_CA_KEY_TOO_SMALL), TLS_ERROR_FIELD(X509_V_ERR_CA_KEY_TOO_SMALL),
TLS_ERROR_FIELD(X509_V_ERR_CA_MD_TOO_WEAK), TLS_ERROR_FIELD(X509_V_ERR_CA_MD_TOO_WEAK),
TLS_ERROR_FIELD(X509_V_ERR_INVALID_CALL),
TLS_ERROR_FIELD(X509_V_ERR_STORE_LOOKUP),
TLS_ERROR_FIELD(X509_V_ERR_NO_VALID_SCTS), TLS_ERROR_FIELD(X509_V_ERR_NO_VALID_SCTS),
TLS_ERROR_FIELD(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION), TLS_ERROR_FIELD(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_NEEDED), TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_NEEDED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_FAILED), TLS_ERROR_FIELD(X509_V_ERR_OCSP_VERIFY_FAILED),
TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN), TLS_ERROR_FIELD(X509_V_ERR_OCSP_CERT_UNKNOWN),
#endif /* !LIBRESSL_VERSION_NUMBER */ #endif
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
}; };
#undef TLS_ERROR_FIELD #undef TLS_ERROR_FIELD
@@ -318,14 +312,9 @@ void tls_free(tls_t *tls)
int tls_set_credentials(tls_t *tls, const char *cafilename) int tls_set_credentials(tls_t *tls, const char *cafilename)
{ {
int ret; UNUSED(tls);
UNUSED(cafilename);
ret = SSL_CTX_load_verify_locations(tls->ssl_ctx, cafilename, NULL); return -1;
if (ret != 1) {
xmpp_error(tls->ctx, "tls", "Failed to process CAfile: %s", cafilename);
_tls_log_error(tls->ctx);
}
return ret;
} }
int tls_start(tls_t *tls) int tls_start(tls_t *tls)

View File

@@ -128,6 +128,20 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
return (uint64_t)(t2 - t1); return (uint64_t)(t2 - t1);
} }
/** Disconnect the stream with the error.
* This is a convenience function used internally by various parts of
* the Strophe library for terminating the connection because of an error.
*
* @param conn a Strophe connection object
* @param error an error code
*/
void disconnect_with_error(xmpp_conn_t *const conn, int error)
{
xmpp_error(conn->ctx, "xmpp", "Disconnecting with error %d", error);
conn->error = conn->error ?: error;
xmpp_disconnect(conn);
}
/** Disconnect the stream with a memory error. /** Disconnect the stream with a memory error.
* This is a convenience function used internally by various parts of * This is a convenience function used internally by various parts of
* the Strophe library for terminating the connection because of a * the Strophe library for terminating the connection because of a
@@ -138,5 +152,5 @@ uint64_t time_elapsed(uint64_t t1, uint64_t t2)
void disconnect_mem_error(xmpp_conn_t *const conn) void disconnect_mem_error(xmpp_conn_t *const conn)
{ {
xmpp_error(conn->ctx, "xmpp", "Memory allocation error"); xmpp_error(conn->ctx, "xmpp", "Memory allocation error");
xmpp_disconnect(conn); disconnect_with_error(conn, XMPP_EMEM);
} }

View File

@@ -103,6 +103,26 @@ extern "C" {
* Internal failure error code. * Internal failure error code.
*/ */
#define XMPP_EINT -3 #define XMPP_EINT -3
/** @def XMPP_ECERT
* Certificate verification failed during TLS establishment.
*/
#define XMPP_ECERT -4
/** @def XMPP_ETIMEDOUT
* Operation timed out error code.
*/
#define XMPP_ETIMEDOUT -5
/** @def XMPP_EIO
* I/O error code.
*/
#define XMPP_EIO -6
/** @def XMPP_ERESET
* Error code for situation when connection closed by remote side.
*/
#define XMPP_ERESET -7
/** @def XMPP_EAUTH
* Authentication failed error code.
*/
#define XMPP_EAUTH -8
/* initialization and shutdown */ /* initialization and shutdown */
void xmpp_initialize(void); void xmpp_initialize(void);
@@ -271,7 +291,6 @@ int xmpp_conn_open_stream(xmpp_conn_t *const conn,
char **attributes, char **attributes,
size_t attributes_len); size_t attributes_len);
int xmpp_conn_tls_start(xmpp_conn_t *const conn); int xmpp_conn_tls_start(xmpp_conn_t *const conn);
int xmpp_conn_tls_cafile(xmpp_conn_t *const conn, const char *cafile);
void xmpp_disconnect(xmpp_conn_t *const conn); void xmpp_disconnect(xmpp_conn_t *const conn);

View File

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