2 Commits

Author SHA1 Message Date
Steffen Jaeckel
460e34552b Add option to enforce usage of SCRAM-*-PLUS variants
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-01-31 23:52:51 +01:00
Steffen Jaeckel
fac1900c3f Disable weak authentication methods per default
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
2024-01-31 23:50:13 +01:00
26 changed files with 383 additions and 791 deletions

View File

@@ -51,10 +51,8 @@ jobs:
matrix: matrix:
xssl_versions: xssl_versions:
- { version: "master", continue: true, libressl: true } - { version: "master", continue: true, libressl: true }
- { version: "OPENBSD_7_5", continue: true, libressl: true }
- { version: "v3.9.2", continue: true, libressl: true }
- { version: "OPENBSD_7_4", continue: true, libressl: true } - { version: "OPENBSD_7_4", continue: true, libressl: true }
- { version: "v3.8.4", continue: true, libressl: true } - { version: "v3.8.1", continue: true, libressl: true }
- { version: "OPENBSD_7_3", continue: true, libressl: true } - { version: "OPENBSD_7_3", continue: true, libressl: true }
- { version: "OPENBSD_7_2", continue: true, libressl: true } - { version: "OPENBSD_7_2", continue: true, libressl: true }
- { version: "OPENBSD_7_1", continue: true, libressl: true } - { version: "OPENBSD_7_1", continue: true, libressl: true }
@@ -68,13 +66,12 @@ jobs:
- { version: "v3.1.5", continue: true, libressl: true } - { version: "v3.1.5", continue: true, libressl: true }
- { version: "v2.1.10", continue: true, libressl: true } - { version: "v2.1.10", continue: true, libressl: true }
- { version: "openssl-3.0", continue: true, libressl: false } - { version: "openssl-3.0", continue: true, libressl: false }
- { version: "openssl-3.0.13", continue: false, libressl: false } - { version: "openssl-3.0.10", continue: false, libressl: false }
- { version: "openssl-3.1", continue: true, libressl: false } - { version: "openssl-3.1", continue: true, libressl: false }
- { version: "openssl-3.1.5", continue: false, libressl: false } - { version: "openssl-3.1.2", continue: false, libressl: false }
- { version: "openssl-3.2", continue: true, libressl: false } valgrind:
- { version: "openssl-3.2.1", continue: false, libressl: false } - { configure: '' , make: 'check' }
- { version: "openssl-3.3", continue: true, libressl: false } - { configure: '--enable-valgrind' , make: 'check-valgrind' }
- { version: "openssl-3.3.0", continue: false, libressl: false }
name: xSSL tests name: xSSL tests
continue-on-error: ${{ matrix.xssl_versions.continue }} continue-on-error: ${{ matrix.xssl_versions.continue }}
steps: steps:
@@ -92,19 +89,11 @@ jobs:
- name: Build the library - name: Build the library
run: | run: |
./bootstrap.sh ./bootstrap.sh
PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" ./configure CFLAGS="-Werror -g3" --prefix="${HOME}/xssl" ./configure ${{ matrix.valgrind.configure }} PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
make -j$(nproc) make -j$(nproc)
- name: Run tests - name: Run tests
run: | run: |
LD_LIBRARY_PATH="${HOME}/xssl/lib" make -j$(nproc) check make -j$(nproc) ${{ matrix.valgrind.make }}
- name: Build the library with Valgrind enabled
run: |
./bootstrap.sh
PKG_CONFIG_PATH="${HOME}/xssl/lib/pkgconfig" ./configure --enable-valgrind CFLAGS="-Werror -g3" --prefix="${HOME}/xssl"
make -j$(nproc)
- name: Run tests with Valgrind enabled
run: |
LD_LIBRARY_PATH="${HOME}/xssl/lib" make -j$(nproc) check-valgrind
- name: Error logs - name: Error logs
if: ${{ failure() }} if: ${{ failure() }}
run: | run: |

View File

@@ -1,19 +1,3 @@
0.13.1
- Fix SCRAM-*-PLUS SASL mechanisms with OpenSSL and TLS < v1.3 (40f2452)
- Only signal "stream negotiation success" once (1cf09b1)
- Fix `sock_connect()` not looping over all DNS records returned if no `sockopt_cb` is set (5edc480)
- Replace usage of EBADFD, it's not in POSIX (#235)
0.13.0
- Fix connected/connecting signaling to user (#227)
- Fix wording of licensing terms (#225)
- Prepare for future changes in OpenSSL (#226)
- Improve Stream Management (#227) (#230)
- Add SCRAM-PLUS Variants (#228)
- Introduce XEP-0138 stream compression (#231)
- Deprecated the following API (#227):
- xmpp_conn_disable_tls() - replaced by a flag set by xmpp_conn_set_flags()
0.12.3 0.12.3
- Improve TCP-connection establishment (#221) - Improve TCP-connection establishment (#221)
- Handle case where the server doesn't provide the `bind` feature (#224) - Handle case where the server doesn't provide the `bind` feature (#224)
@@ -37,7 +21,7 @@
- Fix some build steps when builddir != srcdir (#208) - Fix some build steps when builddir != srcdir (#208)
- Allow the user to disable build of examples (#209) - Allow the user to disable build of examples (#209)
- CI builds against OpenSSL 3 (#206) - CI builds against OpenSSL 3 (#206)
- Change the call signature of the following API (#208): - Change the call signature of the following API:
- xmpp_conn_set_client_cert() - the PKCS#12 file has now to be passed via the `cert` - xmpp_conn_set_client_cert() - the PKCS#12 file has now to be passed via the `cert`
parameter. Originally it was via `key`. Currently both styles are supported, parameter. Originally it was via `key`. Currently both styles are supported,
but in a future release only passing via `cert` will be accepted. but in a future release only passing via `cert` will be accepted.

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = Strophe
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.13 PROJECT_NUMBER = 0.12
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

View File

@@ -88,7 +88,7 @@ or if you have everything configured properly:
Then open `docs/html/index.html`. Then open `docs/html/index.html`.
An online version of the documentation of the latest release is available on https://strophe.im/libstrophe/ An online version of the documentation of the latest release is available on http://strophe.im/libstrophe/
Releases Releases
-------- --------

View File

@@ -1,6 +1,6 @@
m4_define([v_maj], [0]) m4_define([v_maj], [0])
m4_define([v_min], [13]) m4_define([v_min], [12])
m4_define([v_patch], [1]) m4_define([v_patch], [3])
m4_define([project_version], [v_maj.v_min.v_patch]) m4_define([project_version], [v_maj.v_min.v_patch])
m4_define([lt_cur], m4_eval(v_maj + v_min)) m4_define([lt_cur], m4_eval(v_maj + v_min))

View File

@@ -115,8 +115,8 @@ int main(int argc, char **argv)
*/ */
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]); xmpp_conn_set_jid(conn, argv[1]);
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]); xmpp_conn_set_pass(conn, argv[2]);
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);

View File

@@ -116,9 +116,9 @@ int main(int argc, char **argv)
/* setup authentication information */ /* setup authentication information */
if (jid) if (jid)
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid); xmpp_conn_set_jid(conn, jid);
if (password) if (password)
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password); xmpp_conn_set_pass(conn, password);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -293,24 +293,20 @@ create_connection:
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* ask for a password if key is protected */ /* ask for a password if key is protected */
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK, xmpp_conn_set_password_callback(conn, password_callback, NULL);
password_callback);
/* try at max 3 times in case the user enters the password wrong */ /* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3); xmpp_conn_set_password_retries(conn, 3);
/* setup authentication information */ /* setup authentication information */
if (key) { if (key)
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert); xmpp_conn_set_client_cert(conn, cert, key);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
}
if (jid) if (jid)
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid); xmpp_conn_set_jid(conn, jid);
if (password) if (password)
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password); xmpp_conn_set_pass(conn, password);
/* enable TCP keepalive, using canned callback function */ /* enable TCP keepalive, using canned callback function */
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK, xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
xmpp_sockopt_cb_keepalive);
/* set Stream-Mangement state if available */ /* set Stream-Mangement state if available */
if (sm_state) { if (sm_state) {

View File

@@ -331,31 +331,27 @@ int main(int argc, char **argv)
xmpp_conn_set_flags(conn, flags); xmpp_conn_set_flags(conn, flags);
/* configure TCP keepalive (optional) */ /* configure TCP keepalive (optional) */
if (tcp_keepalive) if (tcp_keepalive)
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK, xmpp_conn_set_sockopt_callback(conn, sockopt_cb);
sockopt_cb);
/* ask for a password if key is protected */ /* ask for a password if key is protected */
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK, xmpp_conn_set_password_callback(conn, password_callback, NULL);
password_callback);
/* try at max 3 times in case the user enters the password wrong */ /* try at max 3 times in case the user enters the password wrong */
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, 3); xmpp_conn_set_password_retries(conn, 3);
/* setup authentication information */ /* setup authentication information */
if (key) { if (key) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert); xmpp_conn_set_client_cert(conn, cert, key);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
} }
if (jid) if (jid)
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid); xmpp_conn_set_jid(conn, jid);
if (password) if (password)
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, password); xmpp_conn_set_pass(conn, password);
if (certfail) if (certfail)
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER, xmpp_conn_set_certfail_handler(conn, certfail_handler);
certfail_handler);
if (capath) if (capath)
xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, capath); xmpp_conn_set_capath(conn, capath);
if (cafile) if (cafile)
xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, cafile); xmpp_conn_set_cafile(conn, cafile);
/* initiate connection */ /* initiate connection */
if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) { if (xmpp_connect_client(conn, host, port, conn_handler, ctx) == XMPP_EOK) {

View File

@@ -80,8 +80,8 @@ int main(int argc, char **argv)
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid); xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass); xmpp_conn_set_pass(conn, pass);
/* initiate connection */ /* initiate connection */
xmpp_connect_component(conn, host, port, conn_handler, ctx); xmpp_connect_component(conn, host, port, conn_handler, ctx);

View File

@@ -342,7 +342,7 @@ int main(int argc, char **argv)
/* jid can be a jid or domain for "raw" connection */ /* jid can be a jid or domain for "raw" connection */
domain = xmpp_jid_domain(ctx, jid); domain = xmpp_jid_domain(ctx, jid);
xmpp_conn_set_string(conn, XMPP_SETTING_JID, domain); xmpp_conn_set_jid(conn, domain);
xmpp_free(ctx, domain); xmpp_free(ctx, domain);
/* private data */ /* private data */

View File

@@ -118,8 +118,8 @@ int main(int argc, char **argv)
*/ */
/* setup authentication information */ /* setup authentication information */
xmpp_conn_set_string(conn, XMPP_SETTING_JID, argv[1]); xmpp_conn_set_jid(conn, argv[1]);
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, argv[2]); xmpp_conn_set_pass(conn, argv[2]);
/* initiate connection */ /* initiate connection */
xmpp_connect_client(conn, NULL, 0, conn_handler, ctx); xmpp_connect_client(conn, NULL, 0, conn_handler, ctx);

View File

@@ -269,8 +269,8 @@ int main(int argc, char **argv)
log = xmpp_get_default_logger(XMPP_LEVEL_INFO); log = xmpp_get_default_logger(XMPP_LEVEL_INFO);
ctx = xmpp_ctx_new(NULL, log); ctx = xmpp_ctx_new(NULL, log);
conn = xmpp_conn_new(ctx); conn = xmpp_conn_new(ctx);
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid); xmpp_conn_set_jid(conn, jid);
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass); xmpp_conn_set_pass(conn, pass);
vcard.ctx = ctx; vcard.ctx = ctx;
xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard); xmpp_connect_client(conn, NULL, 0, conn_handler, &vcard);
xmpp_run(ctx); xmpp_run(ctx);

View File

@@ -5,7 +5,7 @@ includedir=@includedir@
Name: libstrophe Name: libstrophe
Description: A simple, lightweight C library for writing XMPP clients Description: A simple, lightweight C library for writing XMPP clients
URL: https://strophe.im/libstrophe/ URL: http://strophe.im/libstrophe/
Version: @VERSION@ Version: @VERSION@
Requires: Requires:
Requires.private: @PC_REQUIRES@ Requires.private: @PC_REQUIRES@

View File

@@ -799,7 +799,9 @@ static void _auth(xmpp_conn_t *conn)
conn->ctx, "auth", conn->ctx, "auth",
"Password hasn't been set, and SASL ANONYMOUS unsupported."); "Password hasn't been set, and SASL ANONYMOUS unsupported.");
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (conn->sasl_support & SASL_MASK_SCRAM) { } else if ((conn->sasl_support & SASL_MASK_SCRAM_PLUS) ||
((conn->sasl_support & SASL_MASK_SCRAM_WEAK) &&
!conn->only_strong_auth)) {
size_t n; size_t n;
scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx)); scram_ctx = strophe_alloc(conn->ctx, sizeof(*scram_ctx));
memset(scram_ctx, 0, sizeof(*scram_ctx)); memset(scram_ctx, 0, sizeof(*scram_ctx));
@@ -857,7 +859,8 @@ static void _auth(xmpp_conn_t *conn)
/* SASL algorithm was tried, unset flag */ /* SASL algorithm was tried, unset flag */
conn->sasl_support &= ~scram_ctx->alg->mask; conn->sasl_support &= ~scram_ctx->alg->mask;
} else if (conn->sasl_support & SASL_MASK_DIGESTMD5) { } else if ((conn->sasl_support & SASL_MASK_DIGESTMD5) &&
conn->weak_auth_enabled) {
auth = _make_sasl_auth(conn, "DIGEST-MD5"); auth = _make_sasl_auth(conn, "DIGEST-MD5");
if (!auth) { if (!auth) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
@@ -871,7 +874,8 @@ static void _auth(xmpp_conn_t *conn)
/* SASL DIGEST-MD5 was tried, unset flag */ /* SASL DIGEST-MD5 was tried, unset flag */
conn->sasl_support &= ~SASL_MASK_DIGESTMD5; conn->sasl_support &= ~SASL_MASK_DIGESTMD5;
} else if (conn->sasl_support & SASL_MASK_PLAIN) { } else if ((conn->sasl_support & SASL_MASK_PLAIN) &&
conn->weak_auth_enabled) {
auth = _make_sasl_auth(conn, "PLAIN"); auth = _make_sasl_auth(conn, "PLAIN");
if (!auth) { if (!auth) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
@@ -1095,19 +1099,21 @@ static int _handle_features_compress(xmpp_conn_t *conn,
static int static int
_handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t *bind, *session; xmpp_stanza_t *bind, *session, *opt;
xmpp_stanza_t *resume; xmpp_stanza_t *resume;
const char *ns;
char h[11]; char h[11];
UNUSED(userdata); UNUSED(userdata);
/* Remove missing features handler */ /* remove missing features handler */
xmpp_timed_handler_delete(conn, _handle_missing_features_sasl); xmpp_timed_handler_delete(conn, _handle_missing_features_sasl);
/* Check whether resource binding is required */ /* check whether resource binding is required */
bind = xmpp_stanza_get_child_by_name_and_ns(stanza, "bind", XMPP_NS_BIND); bind = xmpp_stanza_get_child_by_name(stanza, "bind");
if (bind) { if (bind) {
conn->bind_required = 1; ns = xmpp_stanza_get_ns(bind);
conn->bind_required = ns != NULL && strcmp(ns, XMPP_NS_BIND) == 0;
bind = xmpp_stanza_copy(bind); bind = xmpp_stanza_copy(bind);
if (!bind) { if (!bind) {
disconnect_mem_error(conn); disconnect_mem_error(conn);
@@ -1117,31 +1123,25 @@ _handle_features_sasl(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
conn->bind_required = 0; conn->bind_required = 0;
} }
/* Check whether session establishment is required. /* check whether session establishment is required */
* session = xmpp_stanza_get_child_by_name(stanza, "session");
* The mechanism is deprecated, but we still support it.
*
* RFC3921 contains Ch. 3 "Session Establishment".
*
* RFC6121 removes this and explains in Ch. 1.4:
* "Interoperability Note: [...] Implementation and deployment experience
* has shown that this additional step is unnecessary. [...]" */
session = xmpp_stanza_get_child_by_name_and_ns(stanza, "session",
XMPP_NS_SESSION);
if (session) { if (session) {
ns = xmpp_stanza_get_ns(session);
opt = xmpp_stanza_get_child_by_name(session, "optional");
if (!opt)
conn->session_required = conn->session_required =
xmpp_stanza_get_child_by_name(session, "optional") == NULL; ns != NULL && strcmp(ns, XMPP_NS_SESSION) == 0;
} }
/* Check stream-management support */
if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) { if (xmpp_stanza_get_child_by_name_and_ns(stanza, "sm", XMPP_NS_SM)) {
/* stream management supported */
conn->sm_state->sm_support = 1; conn->sm_state->sm_support = 1;
} }
/* We are expecting either <bind/> and optionally <session/> since this is a /* we are expecting either <bind/> and <session/> since this is a
XMPP style connection or we <resume/> the previous session */ XMPP style connection or we <resume/> the previous session */
/* Check whether we can <resume/> the previous session */ /* check whether we can <resume/> the previous session */
if (!conn->sm_disable && conn->sm_state->can_resume && if (!conn->sm_disable && conn->sm_state->can_resume &&
conn->sm_state->previd && conn->sm_state->bound_jid) { conn->sm_state->previd && conn->sm_state->bound_jid) {
resume = xmpp_stanza_new(conn->ctx); resume = xmpp_stanza_new(conn->ctx);
@@ -1188,57 +1188,11 @@ static int _handle_missing_features_sasl(xmpp_conn_t *conn, void *userdata)
return 0; return 0;
} }
static void _session_start(xmpp_conn_t *conn)
{
xmpp_stanza_t *session;
xmpp_stanza_t *iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
if (!iq) {
disconnect_mem_error(conn);
return;
}
session = xmpp_stanza_new(conn->ctx);
if (!session) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return;
}
/* setup response handlers */
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT, NULL);
xmpp_stanza_set_name(session, "session");
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
xmpp_stanza_add_child_ex(iq, session, 0);
/* send session establishment request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
}
static void _sm_enable(xmpp_conn_t *conn)
{
xmpp_stanza_t *enable = xmpp_stanza_new(conn->ctx);
if (!enable) {
disconnect_mem_error(conn);
return;
}
xmpp_stanza_set_name(enable, "enable");
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
if (!conn->sm_state->dont_request_resume)
xmpp_stanza_set_attribute(enable, "resume", "true");
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
conn->sm_state->sm_sent_nr = 0;
conn->sm_state->sm_enabled = 1;
}
static int static int
_handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
const char *type; const char *type;
xmpp_stanza_t *binding, *jid_stanza; xmpp_stanza_t *iq, *session, *binding, *jid_stanza, *enable = NULL;
UNUSED(userdata); UNUSED(userdata);
@@ -1261,19 +1215,58 @@ _handle_bind(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
} }
} }
/* send enable directly after the bind request */
if (conn->sm_state->sm_support && !conn->sm_disable) {
enable = xmpp_stanza_new(conn->ctx);
if (!enable) {
disconnect_mem_error(conn);
return 0;
}
xmpp_stanza_set_name(enable, "enable");
xmpp_stanza_set_ns(enable, XMPP_NS_SM);
if (!conn->sm_state->dont_request_resume)
xmpp_stanza_set_attribute(enable, "resume", "true");
handler_add(conn, _handle_sm, XMPP_NS_SM, NULL, NULL, NULL);
send_stanza(conn, enable, XMPP_QUEUE_SM_STROPHE);
conn->sm_state->sm_sent_nr = 0;
conn->sm_state->sm_enabled = 1;
}
/* establish a session if required */ /* establish a session if required */
if (conn->session_required) { if (conn->session_required) {
_session_start(conn); /* setup response handlers */
handler_add_id(conn, _handle_session, "_xmpp_session1", NULL);
handler_add_timed(conn, _handle_missing_session, SESSION_TIMEOUT,
NULL);
/* send session request */
iq = xmpp_iq_new(conn->ctx, "set", "_xmpp_session1");
if (!iq) {
disconnect_mem_error(conn);
return 0;
} }
/* send enable directly after the bind request */
else if (conn->sm_state->sm_support && !conn->sm_disable) { session = xmpp_stanza_new(conn->ctx);
_sm_enable(conn); if (!session) {
xmpp_stanza_release(iq);
disconnect_mem_error(conn);
return 0;
} }
xmpp_stanza_set_name(session, "session");
xmpp_stanza_set_ns(session, XMPP_NS_SESSION);
xmpp_stanza_add_child_ex(iq, session, 0);
/* send session establishment request */
send_stanza(conn, iq, XMPP_QUEUE_STROPHE);
}
/* if there's no xmpp session required and we didn't try to enable /* if there's no xmpp session required and we didn't try to enable
* stream-management, we're done here and the stream-negotiation was * stream-management, we're done here and the stream-negotiation was
* successful * successful
*/ */
else { if (!conn->session_required && !enable) {
_stream_negotiation_success(conn); _stream_negotiation_success(conn);
} }
} else { } else {
@@ -1310,11 +1303,8 @@ _handle_session(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_disconnect(conn); xmpp_disconnect(conn);
} else if (type && strcmp(type, "result") == 0) { } else if (type && strcmp(type, "result") == 0) {
strophe_debug(conn->ctx, "xmpp", "Session establishment successful."); strophe_debug(conn->ctx, "xmpp", "Session establishment successful.");
if (conn->sm_state->sm_support && !conn->sm_disable) {
_sm_enable(conn);
} else {
_stream_negotiation_success(conn); _stream_negotiation_success(conn);
}
} else { } else {
strophe_error(conn->ctx, "xmpp", strophe_error(conn->ctx, "xmpp",
"Server sent malformed session reply."); "Server sent malformed session reply.");

View File

@@ -175,11 +175,9 @@ struct _xmpp_send_queue_t {
#define SASL_MASK_EXTERNAL (1 << 6) #define SASL_MASK_EXTERNAL (1 << 6)
#define SASL_MASK_SCRAMSHA1_PLUS (1 << 7) #define SASL_MASK_SCRAMSHA1_PLUS (1 << 7)
#define SASL_MASK_SCRAMSHA256_PLUS (1 << 8) #define SASL_MASK_SCRAMSHA256_PLUS (1 << 8)
#define SASL_MASK_SCRAMSHA512_PLUS (1 << 9)
#define SASL_MASK_SCRAM_PLUS \ #define SASL_MASK_SCRAM_PLUS \
(SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS | \ (SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS)
SASL_MASK_SCRAMSHA512_PLUS)
#define SASL_MASK_SCRAM_WEAK \ #define SASL_MASK_SCRAM_WEAK \
(SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512) (SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512)
#define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK) #define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK)
@@ -261,6 +259,8 @@ struct _xmpp_conn_t {
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 auth_legacy_enabled;
int weak_auth_enabled;
int only_strong_auth;
int secured; /* set when stream is secured with TLS */ int secured; /* set when stream is secured with TLS */
xmpp_certfail_handler certfail_handler; xmpp_certfail_handler certfail_handler;
xmpp_password_callback password_callback; xmpp_password_callback password_callback;
@@ -280,8 +280,7 @@ struct _xmpp_conn_t {
struct { struct {
struct xmpp_compression *state; struct xmpp_compression *state;
int allowed, dont_reset, level; int allowed, supported, dont_reset;
int supported;
} compression; } compression;
char *lang; char *lang;

View File

@@ -63,7 +63,7 @@ static int _conn_decompress(struct xmpp_compression *comp,
break; break;
default: default:
strophe_error(comp->conn->ctx, "zlib", "inflate error %d", ret); strophe_error(comp->conn->ctx, "zlib", "inflate error %d", ret);
comp->conn->error = ret; comp->conn->error = EBADFD;
conn_disconnect(comp->conn); conn_disconnect(comp->conn);
break; break;
} }
@@ -129,7 +129,7 @@ _compression_write(xmpp_conn_t *conn, const void *buff, size_t len, int flush)
} }
if (ret != Z_OK) { if (ret != Z_OK) {
strophe_error(conn->ctx, "zlib", "deflate error %d", ret); strophe_error(conn->ctx, "zlib", "deflate error %d", ret);
conn->error = ret; conn->error = EBADFD;
conn_disconnect(conn); conn_disconnect(conn);
return ret; return ret;
} }
@@ -227,22 +227,22 @@ int compression_init(xmpp_conn_t *conn)
comp->compression.stream.next_out = comp->compression.buffer; comp->compression.stream.next_out = comp->compression.buffer;
comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE; comp->compression.stream.avail_out = STROPHE_COMPRESSION_BUFFER_SIZE;
int ret = deflateInit(&comp->compression.stream, conn->compression.level); int err = deflateInit(&comp->compression.stream, Z_DEFAULT_COMPRESSION);
if (ret != Z_OK) { if (err != Z_OK) {
strophe_free_and_null(conn->ctx, comp->compression.buffer); strophe_free_and_null(conn->ctx, comp->compression.buffer);
conn->error = ret; conn->error = EBADFD;
conn_disconnect(conn); conn_disconnect(conn);
return ret; return err;
} }
_init_zlib_compression(conn->ctx, &comp->decompression); _init_zlib_compression(conn->ctx, &comp->decompression);
ret = inflateInit(&comp->decompression.stream); err = inflateInit(&comp->decompression.stream);
if (ret != Z_OK) { if (err != Z_OK) {
strophe_free_and_null(conn->ctx, comp->decompression.buffer); strophe_free_and_null(conn->ctx, comp->decompression.buffer);
conn->error = ret; conn->error = EBADFD;
conn_disconnect(conn); conn_disconnect(conn);
return ret; return err;
} }
return 0; return 0;
} }

View File

@@ -167,8 +167,6 @@ xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx)
tls_clear_password_cache(conn); tls_clear_password_cache(conn);
conn->password_retries = 1; conn->password_retries = 1;
conn->compression.level = -1;
conn->parser = conn->parser =
parser_new(conn->ctx, _handle_stream_start, _handle_stream_end, parser_new(conn->ctx, _handle_stream_start, _handle_stream_end,
_handle_stream_stanza, conn); _handle_stream_stanza, conn);
@@ -219,6 +217,32 @@ xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn)
return conn; return conn;
} }
/** Register sockopt callback
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started.
*
* If the connection is already connected, this callback will be called
* immediately.
*
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn The Strophe connection object this callback is being registered
* for
* @param callback a xmpp_sockopt_callback callback function that will receive
* notifications of connection status
*
* @ingroup Connections
*/
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback)
{
conn->sockopt_cb = callback;
if (conn->state != XMPP_STATE_DISCONNECTED)
callback(conn, &conn->sock);
}
/** Release a Strophe connection object. /** Release a Strophe connection object.
* Decrement the reference count by one for a connection, freeing the * Decrement the reference count by one for a connection, freeing the
* connection object if the count reaches 0. * connection object if the count reaches 0.
@@ -342,204 +366,6 @@ int xmpp_conn_release(xmpp_conn_t *conn)
return released; return released;
} }
/** Configure a connection-related int setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_RETRIES
* Set the number of retry attempts to decrypt a private key file. \n
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* - \ref XMPP_SETTING_COMPRESSION_LEVEL
* Set the compression level. \n
* For zlib the valid range is `-1` to `9`.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_int(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
int value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_RETRIES:
if (value <= 0)
conn->password_retries = 1;
else
conn->password_retries = value;
break;
case XMPP_SETTING_COMPRESSION_LEVEL:
conn->compression.level = value;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Int setting %d", setting);
return;
}
}
/** Configure a connection-related string setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_JID
* Set the JID of the user that will be bound to the connection. \n
* This should not be used after a connection is created. \n
* If the supplied JID is missing the node, SASL ANONYMOUS authentication
* will be used.
*
* - \ref XMPP_SETTING_PASS
* Set the password used to authenticate the connection.
*
* - \ref XMPP_SETTING_CAFILE
* Set CAfile.
*
* - \ref XMPP_SETTING_CAPATH
* Set CApath.
*
* - \ref XMPP_SETTING_CLIENT_CERT
* Set the Client Certificate or PKCS#12 encoded file that will be bound to
* the connection. \n
* This should not be used after a connection is created. \n
* In case the PKCS#12 file is encrypted, a callback must be set via
* \ref xmpp_conn_set_functionpointer with the option
* \ref XMPP_SETTING_PASSWORD_CALLBACK so the TLS stack can retrieve the
* password.
*
* - \ref XMPP_SETTING_CLIENT_KEY
* Set the Private Key that will be bound to the connection. \n
* This should not be used after a connection is created. \n
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_functionpointer with the option
* \ref XMPP_SETTING_PASSWORD_CALLBACK so the TLS stack can retrieve the
* password.
*
*
*
* If any value was previously set, it will be discarded.
* The function will make a copy of the value given.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_string(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
const char *value)
{
char **target;
switch (setting) {
case XMPP_SETTING_JID:
target = &conn->jid;
break;
case XMPP_SETTING_PASS:
target = &conn->pass;
break;
case XMPP_SETTING_CAFILE:
target = &conn->tls_cafile;
break;
case XMPP_SETTING_CAPATH:
target = &conn->tls_capath;
break;
case XMPP_SETTING_CLIENT_CERT:
target = &conn->tls_client_cert;
break;
case XMPP_SETTING_CLIENT_KEY:
target = &conn->tls_client_key;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid String setting %d", setting);
return;
}
if (*target)
strophe_free(conn->ctx, *target);
*target = NULL;
if (value) {
*target = strophe_strdup(conn->ctx, value);
}
}
/** Configure a connection-related pointer setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_CALLBACK_USERDATA
* Set the userdata pointer that is pass when the password-retrieval
* callback is called. \ref XMPP_SETTING_PASSWORD_CALLBACK
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_pointer(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
void *value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_CALLBACK_USERDATA:
conn->password_callback_userdata = value;
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Pointer setting %d", setting);
return;
}
}
/** Configure a connection-related functionpointer setting
*
* `setting` can be one of:
* - \ref XMPP_SETTING_PASSWORD_CALLBACK
* Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file. The userdata pointer can be set
* via \ref xmpp_conn_set_pointer with the setting
* \ref XMPP_SETTING_PASSWORD_CALLBACK_USERDATA
*
* - \ref XMPP_SETTING_CERTFAIL_HANDLER
* Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* - \ref XMPP_SETTING_SOCKOPT_CALLBACK
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started. \n
* If the connection is already connected, this callback will be called
* immediately. \n
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn a Strophe connection object
* @param setting The setting that shall be configured
* @param value The value, the settings should get
*
* @ingroup Connections
*/
void xmpp_conn_set_functionpointer_impl(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
xmpp_conn_pfn_t value)
{
switch (setting) {
case XMPP_SETTING_PASSWORD_CALLBACK:
conn->password_callback = (xmpp_password_callback)value;
break;
case XMPP_SETTING_CERTFAIL_HANDLER:
conn->certfail_handler = (xmpp_certfail_handler)value;
break;
case XMPP_SETTING_SOCKOPT_CALLBACK:
conn->sockopt_cb = (xmpp_sockopt_callback)value;
if (conn->state != XMPP_STATE_DISCONNECTED)
conn->sockopt_cb(conn, &conn->sock);
break;
default:
strophe_warn(conn->ctx, "xmpp", "Invalid Functionpointer setting %d",
setting);
return;
}
}
/** Get the JID which is or will be bound to the connection. /** Get the JID which is or will be bound to the connection.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -571,6 +397,66 @@ const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn)
return conn->bound_jid; return conn->bound_jid;
} }
/** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL
* ANONYMOUS authentication will be used.
*
* @param conn a Strophe connection object
* @param jid a full or bare JID
*
* @ingroup Connections
*/
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
if (conn->jid)
strophe_free(conn->ctx, conn->jid);
conn->jid = strophe_strdup(conn->ctx, jid);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup TLS
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
conn->certfail_handler = hndl;
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param path path to a certificate file
*
* @ingroup TLS
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_cafile)
strophe_free(conn->ctx, conn->tls_cafile);
conn->tls_cafile = strophe_strdup(conn->ctx, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param path path to a folder containing certificates
*
* @ingroup TLS
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
if (conn->tls_capath)
strophe_free(conn->ctx, conn->tls_capath);
conn->tls_capath = strophe_strdup(conn->ctx, path);
}
/** Retrieve the peer certificate /** Retrieve the peer certificate
* *
* The returned Certificate object must be free'd by calling * The returned Certificate object must be free'd by calling
@@ -587,6 +473,41 @@ xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn)
return tls_peer_cert(conn); return tls_peer_cert(conn);
} }
/** Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* @param conn a Strophe connection object
* @param cb The callback function that shall be called
* @param userdata An opaque data pointer that will be passed to the callback
*
* @ingroup TLS
*/
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata)
{
conn->password_callback = cb;
conn->password_callback_userdata = userdata;
}
/** Set the number of retry attempts to decrypt a private key file.
*
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* @param conn a Strophe connection object
* @param retries The number of retries that should be tried
*
* @ingroup TLS
*/
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries)
{
if (retries == 0)
conn->password_retries = 1;
else
conn->password_retries = retries;
}
/** Retrieve the path of the key file that shall be unlocked. /** Retrieve the path of the key file that shall be unlocked.
* *
* This makes usually sense to be called from the * This makes usually sense to be called from the
@@ -603,6 +524,49 @@ const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn)
return conn->tls_client_key; return conn->tls_client_key;
} }
/** Set the Client Certificate and Private Key or PKCS#12 encoded file that
* will be bound to the connection. If any of them was previously set, it
* will be discarded. This should not be used after a connection is created.
* The function will make a copy of the strings passed in.
*
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup TLS
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (conn->tls_client_cert)
strophe_free(conn->ctx, conn->tls_client_cert);
conn->tls_client_cert = NULL;
if (conn->tls_client_key)
strophe_free(conn->ctx, conn->tls_client_key);
conn->tls_client_key = NULL;
if (cert && key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
conn->tls_client_key = strophe_strdup(conn->ctx, key);
} else if (cert && !key) {
conn->tls_client_cert = strophe_strdup(conn->ctx, cert);
} else if (!cert && key) {
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
conn->tls_client_cert = strophe_strdup(conn->ctx, key);
}
}
/** Get the number of xmppAddr entries in the client certificate. /** Get the number of xmppAddr entries in the client certificate.
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
@@ -643,6 +607,22 @@ const char *xmpp_conn_get_pass(const xmpp_conn_t *conn)
return conn->pass; return conn->pass;
} }
/** Set the password used to authenticate the connection.
* If any password was previously set, it will be discarded. The function
* will make a copy of the password string.
*
* @param conn a Strophe connection object
* @param pass the password
*
* @ingroup Connections
*/
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
if (conn->pass)
strophe_free(conn->ctx, conn->pass);
conn->pass = pass ? strophe_strdup(conn->ctx, pass) : NULL;
}
/** Get the strophe context that the connection is associated with. /** Get the strophe context that the connection is associated with.
* @param conn a Strophe connection object * @param conn a Strophe connection object
* *
@@ -1112,7 +1092,6 @@ int conn_tls_start(xmpp_conn_t *conn)
} }
if (conn->tls != NULL) { if (conn->tls != NULL) {
struct conn_interface old_intf = conn->intf;
conn->intf = tls_intf; conn->intf = tls_intf;
conn->intf.conn = conn; conn->intf.conn = conn;
if (tls_start(conn->tls)) { if (tls_start(conn->tls)) {
@@ -1123,7 +1102,6 @@ int conn_tls_start(xmpp_conn_t *conn)
tls_free(conn->tls); tls_free(conn->tls);
conn->tls = NULL; conn->tls = NULL;
conn->tls_failed = 1; conn->tls_failed = 1;
conn->intf = old_intf;
} }
} }
if (rc != 0) { if (rc != 0) {
@@ -1155,6 +1133,8 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable | XMPP_CONN_FLAG_DISABLE_SM * conn->sm_disable |
XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression.allowed | XMPP_CONN_FLAG_ENABLE_COMPRESSION * conn->compression.allowed |
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * conn->compression.dont_reset | XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * conn->compression.dont_reset |
XMPP_CONN_FLAG_WEAK_AUTH * conn->weak_auth_enabled |
XMPP_CONN_FLAG_STRONG_AUTH * conn->only_strong_auth |
XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled; XMPP_CONN_FLAG_LEGACY_AUTH * conn->auth_legacy_enabled;
return flags; return flags;
@@ -1169,14 +1149,14 @@ long xmpp_conn_get_flags(const xmpp_conn_t *conn)
* *
* Supported flags are: * Supported flags are:
* *
* - \ref XMPP_CONN_FLAG_DISABLE_TLS * - XMPP_CONN_FLAG_DISABLE_TLS
* - \ref XMPP_CONN_FLAG_MANDATORY_TLS * - XMPP_CONN_FLAG_MANDATORY_TLS
* - \ref XMPP_CONN_FLAG_LEGACY_SSL * - XMPP_CONN_FLAG_LEGACY_SSL
* - \ref XMPP_CONN_FLAG_TRUST_TLS * - XMPP_CONN_FLAG_TRUST_TLS
* - \ref XMPP_CONN_FLAG_LEGACY_AUTH * - XMPP_CONN_FLAG_LEGACY_AUTH
* - \ref XMPP_CONN_FLAG_DISABLE_SM * - XMPP_CONN_FLAG_DISABLE_SM
* - \ref XMPP_CONN_FLAG_ENABLE_COMPRESSION * - XMPP_CONN_FLAG_ENABLE_COMPRESSION
* - \ref XMPP_CONN_FLAG_COMPRESSION_DONT_RESET * - XMPP_CONN_FLAG_COMPRESSION_DONT_RESET
* *
* @param conn a Strophe connection object * @param conn a Strophe connection object
* @param flags ORed connection flags * @param flags ORed connection flags
@@ -1210,11 +1190,14 @@ int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags)
(flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0; (flags & XMPP_CONN_FLAG_ENABLE_COMPRESSION) ? 1 : 0;
conn->compression.dont_reset = conn->compression.dont_reset =
(flags & XMPP_CONN_FLAG_COMPRESSION_DONT_RESET) ? 1 : 0; (flags & XMPP_CONN_FLAG_COMPRESSION_DONT_RESET) ? 1 : 0;
conn->weak_auth_enabled = (flags & XMPP_CONN_FLAG_WEAK_AUTH) ? 1 : 0;
conn->only_strong_auth = (flags & XMPP_CONN_FLAG_STRONG_AUTH) ? 1 : 0;
flags &= ~(XMPP_CONN_FLAG_DISABLE_TLS | XMPP_CONN_FLAG_MANDATORY_TLS | flags &= ~(XMPP_CONN_FLAG_DISABLE_TLS | XMPP_CONN_FLAG_MANDATORY_TLS |
XMPP_CONN_FLAG_LEGACY_SSL | XMPP_CONN_FLAG_TRUST_TLS | XMPP_CONN_FLAG_LEGACY_SSL | XMPP_CONN_FLAG_TRUST_TLS |
XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM | XMPP_CONN_FLAG_LEGACY_AUTH | XMPP_CONN_FLAG_DISABLE_SM |
XMPP_CONN_FLAG_ENABLE_COMPRESSION | XMPP_CONN_FLAG_ENABLE_COMPRESSION |
XMPP_CONN_FLAG_COMPRESSION_DONT_RESET); XMPP_CONN_FLAG_COMPRESSION_DONT_RESET |
XMPP_CONN_FLAG_WEAK_AUTH | XMPP_CONN_FLAG_STRONG_AUTH);
if (flags) { if (flags) {
strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags); strophe_error(conn->ctx, "conn", "Flags 0x%04lx unknown", flags);
return XMPP_EINVOP; return XMPP_EINVOP;
@@ -1457,7 +1440,6 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
xmpp_queue_element_t which) xmpp_queue_element_t which)
{ {
xmpp_send_queue_t *t; xmpp_send_queue_t *t;
int disconnected = conn->state == XMPP_STATE_DISCONNECTED;
/* Fast return paths */ /* Fast return paths */
/* empty queue */ /* empty queue */
@@ -1466,7 +1448,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
/* one element in queue */ /* one element in queue */
if (conn->send_queue_head == conn->send_queue_tail) { if (conn->send_queue_head == conn->send_queue_tail) {
/* head is already sent out partially */ /* head is already sent out partially */
if (conn->send_queue_head->wip && !disconnected) if (conn->send_queue_head->wip)
return NULL; return NULL;
/* the element is no USER element */ /* the element is no USER element */
if (conn->send_queue_head->owner != XMPP_QUEUE_USER) if (conn->send_queue_head->owner != XMPP_QUEUE_USER)
@@ -1490,7 +1472,7 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
return NULL; return NULL;
/* head is already sent out partially */ /* head is already sent out partially */
if (t == conn->send_queue_head && t->wip && !disconnected) if (t == conn->send_queue_head && t->wip)
t = t->next; t = t->next;
/* search forward to find the first USER element */ /* search forward to find the first USER element */
@@ -1504,11 +1486,8 @@ char *xmpp_conn_send_queue_drop_element(xmpp_conn_t *conn,
/* In case there exists a SM stanza that is linked to the /* In case there exists a SM stanza that is linked to the
* one we're currently dropping, also delete that one. * one we're currently dropping, also delete that one.
*/ */
if (t->next && t->next->userdata == t) { if (t->next && t->next->userdata == t)
strophe_free(conn->ctx, _drop_send_queue_element(conn, t->next)); strophe_free(conn->ctx, _drop_send_queue_element(conn, t->next));
/* reset the flag, so we restart to send `<r>` stanzas */
conn->sm_state->r_sent = 0;
}
/* Finally drop the element */ /* Finally drop the element */
return _drop_send_queue_element(conn, t); return _drop_send_queue_element(conn, t);
} }

View File

@@ -19,7 +19,6 @@
*/ */
#include "common.h" #include "common.h"
#include <limits.h>
/** Allocate memory in a Strophe context. /** Allocate memory in a Strophe context.
* All Strophe functions will use this to allocate memory. * All Strophe functions will use this to allocate memory.
@@ -87,10 +86,6 @@ char *xmpp_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len)
return strophe_strndup(ctx, s, len); return strophe_strndup(ctx, s, len);
} }
/** Write to the log.
*
* @ingroup Deprecated
*/
void xmpp_log(const xmpp_ctx_t *ctx, void xmpp_log(const xmpp_ctx_t *ctx,
xmpp_log_level_t level, xmpp_log_level_t level,
const char *area, const char *area,
@@ -222,10 +217,6 @@ char *xmpp_strtok_r(char *s, const char *delim, char **saveptr)
return strophe_strtok_r(s, delim, saveptr); return strophe_strtok_r(s, delim, saveptr);
} }
/** snprintf(3) implementation.
*
* @ingroup Deprecated
*/
int xmpp_snprintf(char *str, size_t count, const char *fmt, ...) int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
{ {
va_list ap; va_list ap;
@@ -237,184 +228,11 @@ int xmpp_snprintf(char *str, size_t count, const char *fmt, ...)
return ret; return ret;
} }
/** vsnprintf(3) implementation.
*
* @ingroup Deprecated
*/
int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg) int xmpp_vsnprintf(char *str, size_t count, const char *fmt, va_list arg)
{ {
return strophe_vsnprintf(str, count, fmt, arg); return strophe_vsnprintf(str, count, fmt, arg);
} }
/** Set the JID of the user that will be bound to the connection.
* If any JID was previously set, it will be discarded. This should not be
* be used after a connection is created. The function will make a copy of
* the JID string. If the supplied JID is missing the node, SASL
* ANONYMOUS authentication will be used.
*
* @param conn a Strophe connection object
* @param jid a full or bare JID
*
* @ingroup Deprecated
*/
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid)
{
xmpp_conn_set_string(conn, XMPP_SETTING_JID, jid);
}
/** Set the password used to authenticate the connection.
* If any password was previously set, it will be discarded. The function
* will make a copy of the password string.
*
* @param conn a Strophe connection object
* @param pass the password
*
* @ingroup Deprecated
*/
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass)
{
xmpp_conn_set_string(conn, XMPP_SETTING_PASS, pass);
}
/** Set the CAfile
*
* @param conn a Strophe connection object
* @param path path to a certificate file
*
* @ingroup Deprecated
*/
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path)
{
xmpp_conn_set_string(conn, XMPP_SETTING_CAFILE, path);
}
/** Set the CApath
*
* @param conn a Strophe connection object
* @param path path to a folder containing certificates
*
* @ingroup Deprecated
*/
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path)
{
xmpp_conn_set_string(conn, XMPP_SETTING_CAPATH, path);
}
/** Set the Client Certificate and Private Key or PKCS#12 encoded file that
* will be bound to the connection. If any of them was previously set, it
* will be discarded. This should not be used after a connection is created.
* The function will make a copy of the strings passed in.
*
* In case the Private Key is encrypted, a callback must be set via
* \ref xmpp_conn_set_password_callback so the TLS stack can retrieve the
* password.
*
* In case one wants to use a PKCS#12 encoded file, it should be passed via
* the `cert` parameter and `key` should be NULL. Passing a PKCS#12 file in
* `key` is deprecated.
*
* @param conn a Strophe connection object
* @param cert path to a certificate file or a P12 file
* @param key path to a private key file or a P12 file
*
* @ingroup Deprecated
*/
void xmpp_conn_set_client_cert(xmpp_conn_t *const conn,
const char *const cert,
const char *const key)
{
strophe_debug(conn->ctx, "conn", "set client cert %s %s", cert, key);
if (!cert && key) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, key);
strophe_warn(conn->ctx, "xmpp",
"xmpp_conn_set_client_cert: Passing PKCS#12 in 'key' "
"parameter is deprecated. Use 'cert' instead");
} else {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, cert);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, key);
}
}
/** Set the number of retry attempts to decrypt a private key file.
*
* In case the user enters the password manually it can be useful to
* directly retry if the decryption of the key file failed.
*
* @param conn a Strophe connection object
* @param retries The number of retries that should be tried
*
* @ingroup Deprecated
*/
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries)
{
int val;
if (retries > INT_MAX) {
val = INT_MAX;
strophe_warn(conn->ctx, "xmpp", "retries capped from %u to %d", retries,
val);
} else {
val = (int)retries;
}
xmpp_conn_set_int(conn, XMPP_SETTING_PASSWORD_RETRIES, val);
}
/** Set the Callback function which will be called when the TLS stack can't
* decrypt a password protected key file.
*
* @param conn a Strophe connection object
* @param cb The callback function that shall be called
* @param userdata An opaque data pointer that will be passed to the callback
*
* @ingroup Deprecated
*/
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK, cb);
xmpp_conn_set_pointer(conn, XMPP_SETTING_PASSWORD_CALLBACK_USERDATA,
userdata);
}
/** Set the Handler function which will be called when the TLS stack can't
* verify the CA of the server we're trying to connect to.
*
* @param conn a Strophe connection object
* @param hndl certfail Handler function
*
* @ingroup Deprecated
*/
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_CERTFAIL_HANDLER, hndl);
}
/** Register sockopt callback
* Set function to be called when a new socket is created to allow setting
* socket options before connection is started.
*
* If the connection is already connected, this callback will be called
* immediately.
*
* To set options that can only be applied to disconnected sockets, the
* callback must be registered before connecting.
*
* @param conn The Strophe connection object this callback is being registered
* for
* @param callback a xmpp_sockopt_callback callback function that will receive
* notifications of connection status
*
* @ingroup Deprecated
*/
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback)
{
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK,
callback);
}
/** Set TCP keepalive parameters /** Set TCP keepalive parameters
* Turn on TCP keepalive and set timeout and interval. Zero timeout * Turn on TCP keepalive and set timeout and interval. Zero timeout
* disables TCP keepalives. The parameters are applied immediately for * disables TCP keepalives. The parameters are applied immediately for
@@ -435,8 +253,7 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval)
conn->ka_timeout = timeout; conn->ka_timeout = timeout;
conn->ka_interval = interval; conn->ka_interval = interval;
conn->ka_count = 0; conn->ka_count = 0;
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_SOCKOPT_CALLBACK, xmpp_conn_set_sockopt_callback(conn, xmpp_sockopt_cb_keepalive);
xmpp_sockopt_cb_keepalive);
} }
/** Disable TLS for this connection, called by users of the library. /** Disable TLS for this connection, called by users of the library.

View File

@@ -78,23 +78,12 @@ const struct hash_alg scram_sha512 = {
(void (*)(void *, const uint8_t *, size_t))sha512_process, (void (*)(void *, const uint8_t *, size_t))sha512_process,
(void (*)(void *, uint8_t *))sha512_done}; (void (*)(void *, uint8_t *))sha512_done};
const struct hash_alg scram_sha512_plus = {
"SCRAM-SHA-512-PLUS",
SASL_MASK_SCRAMSHA512_PLUS,
SHA512_DIGEST_SIZE,
(void (*)(const uint8_t *, size_t, uint8_t *))sha512_hash,
(void (*)(void *))sha512_init,
(void (*)(void *, const uint8_t *, size_t))sha512_process,
(void (*)(void *, uint8_t *))sha512_done};
/* The order of this list defines the order in which the SCRAM algorithms are /* The order of this list defines the order in which the SCRAM algorithms are
* tried if the server supports them. * tried if the server supports them.
* Their order is derived from * Their order is derived from
* https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage * https://datatracker.ietf.org/doc/html/draft-ietf-kitten-password-storage
*/ */
const struct hash_alg *scram_algs[] = { const struct hash_alg *scram_algs[] = {
/* *1 */
&scram_sha512_plus,
/* *1 */ /* *1 */
&scram_sha256_plus, &scram_sha256_plus,
/* *1 */ /* *1 */

View File

@@ -123,8 +123,7 @@ static void sock_getaddrinfo(xmpp_sock_t *xsock)
rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints, rc = getaddrinfo(xsock->srv_rr_cur->target, service, &hints,
&xsock->ainfo_list); &xsock->ainfo_list);
if (rc != 0) { if (rc != 0) {
strophe_debug(xsock->ctx, "sock", strophe_debug(xsock->ctx, "sock", "getaddrinfo() failed with %d",
"getaddrinfo() failed with %s (%d)", gai_strerror(rc),
rc); rc);
xsock->ainfo_list = NULL; xsock->ainfo_list = NULL;
} }
@@ -208,7 +207,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
{ {
struct addrinfo *ainfo; struct addrinfo *ainfo;
sock_t sock; sock_t sock;
int rc; int rc = 0;
char buf[64]; char buf[64];
do { do {
@@ -229,7 +228,6 @@ sock_t sock_connect(xmpp_sock_t *xsock)
sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
if (sock != INVALID_SOCKET) { if (sock != INVALID_SOCKET) {
rc = 0;
if (xsock->conn->sockopt_cb) { if (xsock->conn->sockopt_cb) {
/* Don't allow user to overwrite sockfd value. */ /* Don't allow user to overwrite sockfd value. */
sock_t sock_copy = sock; sock_t sock_copy = sock;
@@ -237,7 +235,7 @@ sock_t sock_connect(xmpp_sock_t *xsock)
if (rc != 0) { if (rc != 0) {
strophe_debug(xsock->ctx, "sock", strophe_debug(xsock->ctx, "sock",
"User's setsockopt callback" "User's setsockopt callback"
" failed with %d (errno=%d)", "failed with %d (errno=%d)",
rc, errno); rc, errno);
} }
} }

View File

@@ -51,10 +51,8 @@
#if OPENSSL_VERSION_NUMBER < 0x30000000L #if OPENSSL_VERSION_NUMBER < 0x30000000L
#define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e) #define STROPHE_ERR_func_error_string(e) ERR_func_error_string(e)
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get_peer_certificate(s)
#else #else
#define STROPHE_ERR_func_error_string(e) "" #define STROPHE_ERR_func_error_string(e) ""
#define STROPHE_SSL_get1_peer_certificate(s) SSL_get1_peer_certificate(s)
#endif #endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -111,7 +109,6 @@ struct _tls {
X509 *client_cert; X509 *client_cert;
void *channel_binding_data; void *channel_binding_data;
size_t channel_binding_size; size_t channel_binding_size;
FILE *keylogfile;
int lasterror; int lasterror;
}; };
@@ -559,36 +556,6 @@ static int _tls_password_callback(char *buf, int size, int rwflag, void *u)
return tls_caching_password_callback(buf, size, u); return tls_caching_password_callback(buf, size, u);
} }
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
static void _keylog_cb(const SSL *ssl, const char *line)
{
xmpp_conn_t *conn = SSL_get_app_data(ssl);
fwrite(line, strlen(line), 1, conn->tls->keylogfile);
fputc('\n', conn->tls->keylogfile);
fflush(conn->tls->keylogfile);
}
#endif
static void _try_open_keylogfile(tls_t *tls)
{
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
const char *first_line = "# SSL Key logfile generated by libstrophe\n";
const char *SSLKEYLOGFILE = getenv("SSLKEYLOGFILE");
if (!SSLKEYLOGFILE || *SSLKEYLOGFILE == '\0')
return;
tls->keylogfile = fopen(SSLKEYLOGFILE, "abe");
if (!tls->keylogfile) {
strophe_warn(tls->ctx, "tls", "Could not open SSL keylog file %s",
SSLKEYLOGFILE);
return;
}
fwrite(first_line, strlen(first_line), 1, tls->keylogfile);
SSL_CTX_set_keylog_callback(tls->ssl_ctx, _keylog_cb);
#else
UNUSED(tls);
#endif
}
tls_t *tls_new(xmpp_conn_t *conn) tls_t *tls_new(xmpp_conn_t *conn)
{ {
tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls)); tls_t *tls = strophe_alloc(conn->ctx, sizeof(*tls));
@@ -732,8 +699,6 @@ tls_t *tls_new(xmpp_conn_t *conn)
ret = SSL_set_fd(tls->ssl, conn->sock); ret = SSL_set_fd(tls->ssl, conn->sock);
if (ret <= 0) if (ret <= 0)
goto err_free_ssl; goto err_free_ssl;
_try_open_keylogfile(tls);
} }
return tls; return tls;
@@ -752,8 +717,6 @@ err:
void tls_free(tls_t *tls) void tls_free(tls_t *tls)
{ {
if (tls->keylogfile)
fclose(tls->keylogfile);
strophe_free(tls->ctx, tls->channel_binding_data); strophe_free(tls->ctx, tls->channel_binding_data);
SSL_free(tls->ssl); SSL_free(tls->ssl);
X509_free(tls->client_cert); X509_free(tls->client_cert);
@@ -764,7 +727,7 @@ void tls_free(tls_t *tls)
xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn) xmpp_tlscert_t *tls_peer_cert(xmpp_conn_t *conn)
{ {
if (conn && conn->tls && conn->tls->ssl) { if (conn && conn->tls && conn->tls->ssl) {
X509 *cert = STROPHE_SSL_get1_peer_certificate(conn->tls->ssl); X509 *cert = SSL_get_peer_certificate(conn->tls->ssl);
if (cert) { if (cert) {
xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert); xmpp_tlscert_t *tlscert = _x509_to_tlscert(conn->ctx, cert);
X509_free(cert); X509_free(cert);
@@ -787,9 +750,8 @@ int tls_init_channel_binding(tls_t *tls,
{ {
const char *label = NULL; const char *label = NULL;
size_t labellen = 0; size_t labellen = 0;
int ssl_version = SSL_version(tls->ssl);
switch (ssl_version) { switch (SSL_version(tls->ssl)) {
case SSL3_VERSION: case SSL3_VERSION:
*binding_prefix = "tls-unique"; *binding_prefix = "tls-unique";
*binding_prefix_len = strlen("tls-unique"); *binding_prefix_len = strlen("tls-unique");
@@ -812,7 +774,7 @@ int tls_init_channel_binding(tls_t *tls,
break; break;
#endif #endif
default: default:
strophe_error(tls->ctx, "tls", "Unsupported TLS/SSL Version: %s", strophe_error(tls->ctx, "tls", "Unsupported TLS Version: %s",
SSL_get_version(tls->ssl)); SSL_get_version(tls->ssl));
return -1; return -1;
} }
@@ -823,29 +785,12 @@ int tls_init_channel_binding(tls_t *tls,
if (!tls->channel_binding_data) if (!tls->channel_binding_data)
return -1; return -1;
if (ssl_version <= TLS1_2_VERSION) {
size_t len;
if (SSL_session_reused(tls->ssl)) {
len = SSL_get_peer_finished(tls->ssl, tls->channel_binding_data,
tls->channel_binding_size);
} else {
len = SSL_get_finished(tls->ssl, tls->channel_binding_data,
tls->channel_binding_size);
}
if (len != tls->channel_binding_size) {
strophe_error(tls->ctx, "tls",
"Got channel binding data of wrong size %zu", len);
return -1;
}
} else {
if (SSL_export_keying_material(tls->ssl, tls->channel_binding_data, if (SSL_export_keying_material(tls->ssl, tls->channel_binding_data,
tls->channel_binding_size, label, tls->channel_binding_size, label, labellen,
labellen, NULL, 0, 0) != 1) { NULL, 0, 0) != 1) {
strophe_error(tls->ctx, "tls", strophe_error(tls->ctx, "tls", "Could not get channel binding data");
"Could not get channel binding data");
return -1; return -1;
} }
}
return 0; return 0;
} }
@@ -1036,7 +981,7 @@ static void _tls_dump_cert_info(tls_t *tls)
X509 *cert; X509 *cert;
char *name; char *name;
cert = STROPHE_SSL_get1_peer_certificate(tls->ssl); cert = SSL_get_peer_certificate(tls->ssl);
if (cert == NULL) if (cert == NULL)
strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer"); strophe_debug(tls->ctx, "tls", "Certificate was not presented by peer");
else { else {

110
strophe.h
View File

@@ -208,6 +208,14 @@ typedef struct _xmpp_sm_t xmpp_sm_state_t;
* Only enable this flag if you know what you're doing. * Only enable this flag if you know what you're doing.
*/ */
#define XMPP_CONN_FLAG_COMPRESSION_DONT_RESET (1UL << 7) #define XMPP_CONN_FLAG_COMPRESSION_DONT_RESET (1UL << 7)
/** @def XMPP_CONN_FLAG_WEAK_AUTH
* Allow weak authentication methods (DIGEST-MD5 and PLAIN).
*/
#define XMPP_CONN_FLAG_WEAK_AUTH (1UL << 8)
/** @def XMPP_CONN_FLAG_STRONG_AUTH
* Only allow strong authentication methods (Only the SCRAM-*-PLUS variants).
*/
#define XMPP_CONN_FLAG_STRONG_AUTH (1UL << 9)
/* connect callback */ /* connect callback */
typedef enum { typedef enum {
@@ -371,70 +379,37 @@ typedef int (*xmpp_sockopt_callback)(xmpp_conn_t *conn, void *sock);
/* an example callback that sets basic keepalive parameters */ /* an example callback that sets basic keepalive parameters */
int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock); int xmpp_sockopt_cb_keepalive(xmpp_conn_t *conn, void *sock);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx); xmpp_conn_t *xmpp_conn_new(xmpp_ctx_t *ctx);
xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn); xmpp_conn_t *xmpp_conn_clone(xmpp_conn_t *conn);
int xmpp_conn_release(xmpp_conn_t *conn); int xmpp_conn_release(xmpp_conn_t *conn);
/** Connection settings
*/
typedef enum xmpp_conn_setting_t {
/* String values */
XMPP_SETTING_JID = 0x0, /**< JID */
XMPP_SETTING_PASS, /**< Password */
XMPP_SETTING_CAFILE, /**< CAfile */
XMPP_SETTING_CAPATH, /**< CApath */
XMPP_SETTING_CLIENT_CERT, /**< Client Certificate */
XMPP_SETTING_CLIENT_KEY, /**< Key of Client Certificate */
/* Int values */
XMPP_SETTING_PASSWORD_RETRIES = 0x40, /**< Number of retry attempts to
decrypt a private key file. */
XMPP_SETTING_COMPRESSION_LEVEL, /**< Compression level. */
/* Pointer values */
XMPP_SETTING_PASSWORD_CALLBACK_USERDATA = 0x80, /**< Userdata for password
callback function */
/* Functionpointer values */
XMPP_SETTING_PASSWORD_CALLBACK = 0xC0, /**< Callback function to retrieve
password for key file. */
XMPP_SETTING_CERTFAIL_HANDLER, /**< Handler function when certificate chain
can't be verified */
XMPP_SETTING_SOCKOPT_CALLBACK, /**< Callback function when a new socket is
created. */
} xmpp_conn_setting_t;
void xmpp_conn_set_int(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
int value);
void xmpp_conn_set_string(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
const char *value);
void xmpp_conn_set_pointer(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
void *value);
/* Provide a wrapper macro, so users don't have to cast their function pointer
* type manually. */
typedef int (*xmpp_conn_pfn_t)();
#define xmpp_conn_set_functionpointer(c, s, p) \
do { \
xmpp_conn_set_functionpointer_impl(c, s, (xmpp_conn_pfn_t)p); \
} while (0)
void xmpp_conn_set_functionpointer_impl(xmpp_conn_t *conn,
xmpp_conn_setting_t setting,
xmpp_conn_pfn_t pfn);
long xmpp_conn_get_flags(const xmpp_conn_t *conn); long xmpp_conn_get_flags(const xmpp_conn_t *conn);
int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags); int xmpp_conn_set_flags(xmpp_conn_t *conn, long flags);
const char *xmpp_conn_get_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_jid(const xmpp_conn_t *conn);
const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn); const char *xmpp_conn_get_bound_jid(const xmpp_conn_t *conn);
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn); xmpp_tlscert_t *xmpp_conn_get_peer_cert(xmpp_conn_t *const conn);
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn); const char *xmpp_conn_get_keyfile(const xmpp_conn_t *conn);
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn); unsigned int xmpp_conn_cert_xmppaddr_num(xmpp_conn_t *conn);
char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n); char *xmpp_conn_cert_xmppaddr(xmpp_conn_t *conn, unsigned int n);
const char *xmpp_conn_get_pass(const xmpp_conn_t *conn); const char *xmpp_conn_get_pass(const xmpp_conn_t *conn);
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn); xmpp_ctx_t *xmpp_conn_get_context(xmpp_conn_t *conn);
int xmpp_conn_is_secured(xmpp_conn_t *conn); int xmpp_conn_is_secured(xmpp_conn_t *conn);
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
int xmpp_conn_is_connecting(xmpp_conn_t *conn); int xmpp_conn_is_connecting(xmpp_conn_t *conn);
int xmpp_conn_is_connected(xmpp_conn_t *conn); int xmpp_conn_is_connected(xmpp_conn_t *conn);
int xmpp_conn_is_disconnected(xmpp_conn_t *conn); int xmpp_conn_is_disconnected(xmpp_conn_t *conn);
@@ -478,7 +453,6 @@ int xmpp_conn_tls_start(xmpp_conn_t *conn);
void xmpp_disconnect(xmpp_conn_t *conn); void xmpp_disconnect(xmpp_conn_t *conn);
void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza); void xmpp_send(xmpp_conn_t *conn, xmpp_stanza_t *stanza);
void xmpp_send_error(xmpp_conn_t *conn, xmpp_error_type_t type, char *text);
void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...); void xmpp_send_raw_string(xmpp_conn_t *conn, const char *fmt, ...);
void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len); void xmpp_send_raw(xmpp_conn_t *conn, const char *data, size_t len);
@@ -741,19 +715,11 @@ void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len);
*/ */
void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len); void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
/* /**
* Formerly "private but exported" functions made public for now to announce * Formerly "private but exported" functions made public for now to announce
* deprecation */ * deprecation */
#include <stdarg.h> #include <stdarg.h>
#if !defined(XMPP_DEPRECATED)
/**
* XMPP_DEPRECATED(x) macro to show a compiler warning for deprecated API
* functions
*
* @param x The function that can be used as a replacement or 'internal' if
* there is no replacement
*/
#if defined(__GNUC__) #if defined(__GNUC__)
#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405) #if (__GNUC__ * 100 + __GNUC_MINOR__ >= 405)
#define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x))) #define XMPP_DEPRECATED(x) __attribute__((deprecated("replaced by " #x)))
@@ -765,7 +731,6 @@ void xmpp_rand_nonce(xmpp_rand_t *rand, char *output, size_t len);
#else #else
#define XMPP_DEPRECATED(x) #define XMPP_DEPRECATED(x)
#endif #endif
#endif
XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size); XMPP_DEPRECATED(internal) void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size);
XMPP_DEPRECATED(internal) XMPP_DEPRECATED(internal)
@@ -805,31 +770,6 @@ void xmpp_conn_set_keepalive(xmpp_conn_t *conn, int timeout, int interval);
XMPP_DEPRECATED(xmpp_conn_set_flags) XMPP_DEPRECATED(xmpp_conn_set_flags)
void xmpp_conn_disable_tls(xmpp_conn_t *conn); void xmpp_conn_disable_tls(xmpp_conn_t *conn);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_jid(xmpp_conn_t *conn, const char *jid);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_pass(xmpp_conn_t *conn, const char *pass);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_cafile(xmpp_conn_t *const conn, const char *path);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_capath(xmpp_conn_t *const conn, const char *path);
XMPP_DEPRECATED(xmpp_conn_set_string)
void xmpp_conn_set_client_cert(xmpp_conn_t *conn,
const char *cert,
const char *key);
XMPP_DEPRECATED(xmpp_conn_set_int)
void xmpp_conn_set_password_retries(xmpp_conn_t *conn, unsigned int retries);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_password_callback(xmpp_conn_t *conn,
xmpp_password_callback cb,
void *userdata);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_certfail_handler(xmpp_conn_t *const conn,
xmpp_certfail_handler hndl);
XMPP_DEPRECATED(xmpp_conn_set_functionpointer)
void xmpp_conn_set_sockopt_callback(xmpp_conn_t *conn,
xmpp_sockopt_callback callback);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -7,7 +7,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <limits.h>
#undef HAVE_VSNPRINTF #undef HAVE_VSNPRINTF
#undef HAVE_SNPRINTF #undef HAVE_SNPRINTF
@@ -29,14 +28,7 @@ int main(void)
char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d", char *int_fmt[] = {"%-1.5d", "%1.5d", "%123.9d", "%5.5d",
"%10.5d", "% 10.5d", "%+22.33d", "%01.3d", "%10.5d", "% 10.5d", "%+22.33d", "%01.3d",
"%4d", "0x%x", "0x%04x", NULL}; "%4d", "0x%x", "0x%04x", NULL};
int int_nums[] = {-1, 134, 91340, 341, 0203, long int_nums[] = {-1, 134, 91340, 341, 0203, 0x76543210, 0};
0x76543210, INT_MIN, INT_MAX, 0};
char *long_fmt[] = {"%-1.5ld", "%1.5ld", "%123.9ld", "%5.5ld",
"%10.5ld", "% 10.5ld", "%+22.33ld", "%01.3ld",
"%4ld", "0x%lx", "0x%04lx", NULL};
long long_nums[] = {-1L, 134L, 91340L,
341L, 0203L, 0xFEDCBA9876543210L,
LONG_MIN, LONG_MAX, 0L};
int x, y; int x, y;
int fail = 0; int fail = 0;
int num = 0; int num = 0;
@@ -68,19 +60,6 @@ int main(void)
} }
num++; num++;
} }
for (x = 0; long_fmt[x] != NULL; x++)
for (y = 0; long_nums[y] != 0; y++) {
strophe_snprintf(buf1, sizeof(buf1), long_fmt[x], long_nums[y]);
sprintf(buf2, long_fmt[x], long_nums[y]);
if (strcmp(buf1, buf2)) {
printf("xmpp_snprintf doesn't match Format: "
"%s\n\txmpp_snprintf = %s\n\tsprintf = %s\n",
long_fmt[x], buf1, buf2);
fail++;
}
num++;
}
printf("%d tests failed out of %d.\n", fail, num); printf("%d tests failed out of %d.\n", fail, num);
return fail != 0 ? 1 : 0; return fail != 0 ? 1 : 0;
} }

View File

@@ -175,7 +175,7 @@ static void test_stanza_error(xmpp_ctx_t *ctx)
xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL); xmpp_stanza_reply_error(stanza, "cancel", "service-unavailable", NULL);
assert(error != NULL); assert(error != NULL);
mood = xmpp_stanza_new_from_string(ctx, str_mood); mood = xmpp_stanza_new_from_string(ctx, str_mood);
assert(mood != NULL); assert(stanza != NULL);
assert(xmpp_stanza_get_to(error) != NULL); assert(xmpp_stanza_get_to(error) != NULL);
COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error)); COMPARE("romeo@montague.lit/home", xmpp_stanza_get_to(error));

View File

@@ -16,7 +16,6 @@
#include <string.h> #include <string.h>
#include <sys/param.h> #include <sys/param.h>
#define XMPP_DEPRECATED(x)
#include "strophe.h" #include "strophe.h"
#include "test.h" #include "test.h"
@@ -42,14 +41,12 @@ int main()
} client_cert[] = { } client_cert[] = {
{0, "tests/cert.pem", "tests/key.pem"}, {0, "tests/cert.pem", "tests/key.pem"},
{1, "tests/cert.pem", "tests/key_encrypted.pem"}, {1, "tests/cert.pem", "tests/key_encrypted.pem"},
{0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL},
/* Backward compatibility checks for change introduced in #208
* To be removed, once xmpp_conn_set_client_cert() is gone */
{0, NULL, "tests/cert.emptypass.pfx"}, {0, NULL, "tests/cert.emptypass.pfx"},
{0, NULL, "tests/cert.nopass.pfx"}, {0, NULL, "tests/cert.nopass.pfx"},
{1, NULL, "tests/cert.pfx"}, {1, NULL, "tests/cert.pfx"},
{0, "tests/cert.emptypass.pfx", NULL},
{0, "tests/cert.nopass.pfx", NULL},
{1, "tests/cert.pfx", NULL},
}; };
const char *srcdir; const char *srcdir;
@@ -81,15 +78,9 @@ int main()
keyfile = NULL; keyfile = NULL;
if (client_cert[m].needs_callback) if (client_cert[m].needs_callback)
xmpp_conn_set_functionpointer(conn, XMPP_SETTING_PASSWORD_CALLBACK, xmpp_conn_set_password_callback(conn, password_callback, NULL);
password_callback);
if (certfile) {
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_CERT, certfile);
xmpp_conn_set_string(conn, XMPP_SETTING_CLIENT_KEY, keyfile);
} else {
xmpp_conn_set_client_cert(conn, certfile, keyfile); xmpp_conn_set_client_cert(conn, certfile, keyfile);
}
xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn); xmppaddr_num[0] = '0' + xmpp_conn_cert_xmppaddr_num(conn);