From 024e998f8b73047eb2ae56ea92cb2cbc0bbedc17 Mon Sep 17 00:00:00 2001 From: defanor Date: Sat, 2 Oct 2021 20:23:38 +0300 Subject: Make libgsasl optional Only EXTERNAL and PLAIN mechanisms are supported without it for now. --- src/Makefile.am | 6 +- src/rexmpp.c | 92 ++++++-------------- src/rexmpp.h | 7 +- src/rexmpp_sasl.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rexmpp_sasl.h | 110 ++++++++++++++++++++++++ 5 files changed, 397 insertions(+), 70 deletions(-) create mode 100644 src/rexmpp_sasl.c create mode 100644 src/rexmpp_sasl.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index a6337ff..437acc9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,10 +22,12 @@ librexmpp_la_SOURCES = rexmpp_roster.h rexmpp_roster.c \ rexmpp_pubsub.h rexmpp_pubsub.c \ rexmpp_http_upload.h rexmpp_http_upload.c \ rexmpp_jingle.h rexmpp_jingle.c \ - rexmpp_base64.h rexmpp_base64.c + rexmpp_base64.h rexmpp_base64.c \ + rexmpp_sasl.h rexmpp_sasl.c include_HEADERS = config.h rexmpp_roster.h rexmpp_tcp.h rexmpp_socks.h rexmpp.h \ rexmpp_dns.h rexmpp_tls.h rexmpp_jid.h rexmpp_openpgp.h rexmpp_console.h \ - rexmpp_pubsub.h rexmpp_http_upload.h rexmpp_jingle.h rexmpp_base64.h + rexmpp_pubsub.h rexmpp_http_upload.h rexmpp_jingle.h rexmpp_base64.h \ + rexmpp_sasl.h librexmpp_la_CFLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) \ $(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \ $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \ diff --git a/src/rexmpp.c b/src/rexmpp.c index b754f49..2acdf51 100644 --- a/src/rexmpp.c +++ b/src/rexmpp.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #ifdef HAVE_GPGME #include @@ -40,6 +39,7 @@ #include "rexmpp_http_upload.h" #include "rexmpp_jingle.h" #include "rexmpp_base64.h" +#include "rexmpp_sasl.h" struct rexmpp_iq_cacher { rexmpp_iq_callback_t cb; @@ -497,15 +497,6 @@ xmlNodePtr rexmpp_disco_info (rexmpp_t *s) { return s->disco_info; } -int rexmpp_sasl_cb (Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop) { - (void)sctx; /* The session should already be in rexmpp_t. */ - rexmpp_t *s = gsasl_callback_hook_get(ctx); - if (s == NULL || s->sasl_property_cb == NULL) { - return GSASL_NO_CALLBACK; - } - return s->sasl_property_cb(s, prop); -} - rexmpp_err_t rexmpp_init (rexmpp_t *s, const char *jid, log_function_t log_func) @@ -631,17 +622,13 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, return REXMPP_E_TLS; } - err = gsasl_init(&(s->sasl_ctx)); + err = rexmpp_sasl_ctx_init(s); if (err) { - rexmpp_log(s, LOG_CRIT, "gsasl initialisation error: %s", - gsasl_strerror(err)); rexmpp_tls_deinit(s); rexmpp_dns_ctx_deinit(s); xmlFreeParserCtxt(s->xml_parser); return REXMPP_E_SASL; } - gsasl_callback_hook_set(s->sasl_ctx, s); - gsasl_callback_set(s->sasl_ctx, rexmpp_sasl_cb); #ifdef HAVE_GPGME gpgme_check_version(NULL); @@ -649,7 +636,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s, if (gpg_err_code(err) != GPG_ERR_NO_ERROR) { rexmpp_log(s, LOG_CRIT, "gpgme initialisation error: %s", gpgme_strerror(err)); - gsasl_done(s->sasl_ctx); + rexmpp_sasl_ctx_deinit(s); rexmpp_tls_deinit(s); rexmpp_dns_ctx_deinit(s); xmlFreeParserCtxt(s->xml_parser); @@ -677,8 +664,7 @@ void rexmpp_cleanup (rexmpp_t *s) { rexmpp_tls_cleanup(s); s->tls_state = REXMPP_TLS_INACTIVE; if (s->sasl_state != REXMPP_SASL_INACTIVE) { - gsasl_finish(s->sasl_session); - s->sasl_session = NULL; + rexmpp_sasl_ctx_cleanup(s); s->sasl_state = REXMPP_SASL_INACTIVE; } if (s->tcp_state == REXMPP_TCP_CONNECTING) { @@ -751,7 +737,7 @@ void rexmpp_done (rexmpp_t *s) { #ifdef HAVE_GPGME gpgme_release(s->pgp_ctx); #endif - gsasl_done(s->sasl_ctx); + rexmpp_sasl_ctx_deinit(s); rexmpp_tls_deinit(s); rexmpp_dns_ctx_deinit(s); xmlFreeParserCtxt(s->xml_parser); @@ -977,11 +963,9 @@ rexmpp_err_t rexmpp_send_start (rexmpp_t *s, const void *data, size_t data_len) return REXMPP_E_SEND_BUFFER_NOT_EMPTY; } if (s->sasl_state == REXMPP_SASL_ACTIVE) { - sasl_err = gsasl_encode (s->sasl_session, data, data_len, - &(s->send_buffer), &(s->send_buffer_len)); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "SASL encoding error: %s", - gsasl_strerror(sasl_err)); + sasl_err = rexmpp_sasl_encode (s, data, data_len, + &(s->send_buffer), &(s->send_buffer_len)); + if (sasl_err) { s->sasl_state = REXMPP_SASL_ERROR; return REXMPP_E_SASL; } @@ -1315,11 +1299,9 @@ rexmpp_err_t rexmpp_recv (rexmpp_t *s) { if (chunk_raw_len > 0) { s->last_network_activity = time(NULL); if (s->sasl_state == REXMPP_SASL_ACTIVE) { - sasl_err = gsasl_decode(s->sasl_session, chunk_raw, chunk_raw_len, - &chunk, &chunk_len); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_ERR, "SASL decoding error: %s", - gsasl_strerror(sasl_err)); + sasl_err = rexmpp_sasl_decode(s, chunk_raw, chunk_raw_len, + &chunk, &chunk_len); + if (sasl_err) { s->sasl_state = REXMPP_SASL_ERROR; return REXMPP_E_SASL; } @@ -1848,28 +1830,21 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { free(mech_str); } } - const char *mech = - gsasl_client_suggest_mechanism(s->sasl_ctx, mech_list); + const char *mech = rexmpp_sasl_suggest_mechanism(s, mech_list); + if (mech == NULL) { + rexmpp_log(s, LOG_CRIT, "Failed to decide on a SASL mechanism"); + s->sasl_state = REXMPP_SASL_ERROR; + return REXMPP_E_SASL; + } rexmpp_log(s, LOG_INFO, "Selected SASL mechanism: %s", mech); - int sasl_err; char *sasl_buf; - sasl_err = gsasl_client_start(s->sasl_ctx, mech, &(s->sasl_session)); - if (sasl_err != GSASL_OK) { - rexmpp_log(s, LOG_CRIT, "Failed to initialise SASL session: %s", - gsasl_strerror(sasl_err)); + if (rexmpp_sasl_start(s, mech)) { s->sasl_state = REXMPP_SASL_ERROR; return REXMPP_E_SASL; } - sasl_err = gsasl_step64 (s->sasl_session, "", (char**)&sasl_buf); - if (sasl_err != GSASL_OK) { - if (sasl_err == GSASL_NEEDS_MORE) { - rexmpp_log(s, LOG_DEBUG, "SASL needs more data"); - } else { - rexmpp_log(s, LOG_ERR, "SASL error: %s", - gsasl_strerror(sasl_err)); - s->sasl_state = REXMPP_SASL_ERROR; - return REXMPP_E_SASL; - } + if (rexmpp_sasl_step64(s, "", (char**)&sasl_buf)) { + s->sasl_state = REXMPP_SASL_ERROR; + return REXMPP_E_SASL; } xmlNodePtr auth_cmd = xmlNewNode(NULL, "auth"); xmlNewProp(auth_cmd, "mechanism", mech); @@ -2223,18 +2198,11 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { if (rexmpp_xml_match(elem, "urn:ietf:params:xml:ns:xmpp-sasl", "challenge")) { char *challenge = xmlNodeGetContent(elem); - sasl_err = gsasl_step64 (s->sasl_session, challenge, - (char**)&sasl_buf); + sasl_err = rexmpp_sasl_step64 (s, challenge, (char**)&sasl_buf); free(challenge); - if (sasl_err != GSASL_OK) { - if (sasl_err == GSASL_NEEDS_MORE) { - rexmpp_log(s, LOG_DEBUG, "SASL needs more data"); - } else { - rexmpp_log(s, LOG_ERR, "SASL error: %s", - gsasl_strerror(sasl_err)); - s->sasl_state = REXMPP_SASL_ERROR; - return REXMPP_E_SASL; - } + if (sasl_err) { + s->sasl_state = REXMPP_SASL_ERROR; + return REXMPP_E_SASL; } xmlNodePtr response = xmlNewNode(NULL, "response"); xmlNewNs(response, "urn:ietf:params:xml:ns:xmpp-sasl", NULL); @@ -2244,15 +2212,12 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, xmlNodePtr elem) { } else if (rexmpp_xml_match(elem, "urn:ietf:params:xml:ns:xmpp-sasl", "success")) { char *success = xmlNodeGetContent(elem); - sasl_err = gsasl_step64 (s->sasl_session, success, - (char**)&sasl_buf); + sasl_err = rexmpp_sasl_step64 (s, success, (char**)&sasl_buf); free(success); free(sasl_buf); - if (sasl_err == GSASL_OK) { + if (! sasl_err) { rexmpp_log(s, LOG_DEBUG, "SASL success"); } else { - rexmpp_log(s, LOG_ERR, "SASL error: %s", - gsasl_strerror(sasl_err)); s->sasl_state = REXMPP_SASL_ERROR; return REXMPP_E_SASL; } @@ -2405,8 +2370,7 @@ void rexmpp_sax_end_elem_ns (rexmpp_t *s, strcmp(URI, "http://etherx.jabber.org/streams") == 0) { rexmpp_log(s, LOG_DEBUG, "stream end"); if (s->sasl_state == REXMPP_SASL_ACTIVE) { - gsasl_finish(s->sasl_session); - s->sasl_session = NULL; + rexmpp_sasl_ctx_cleanup(s); s->sasl_state = REXMPP_SASL_INACTIVE; } s->stream_state = REXMPP_STREAM_CLOSED; diff --git a/src/rexmpp.h b/src/rexmpp.h index e4fbc09..22722ce 100644 --- a/src/rexmpp.h +++ b/src/rexmpp.h @@ -13,7 +13,6 @@ #include "config.h" -#include #include #ifdef HAVE_GPGME #include @@ -79,6 +78,7 @@ typedef enum rexmpp_err rexmpp_err_t; #include "rexmpp_tls.h" #include "rexmpp_jid.h" #include "rexmpp_jingle.h" +#include "rexmpp_sasl.h" /** @brief An info/query callback function type. @@ -228,7 +228,7 @@ enum tls_pol { }; typedef void (*log_function_t) (rexmpp_t *s, int priority, const char *format, va_list args); -typedef int (*sasl_property_cb_t) (rexmpp_t *s, Gsasl_property prop); +typedef int (*sasl_property_cb_t) (rexmpp_t *s, rexmpp_sasl_property prop); typedef int (*xml_in_cb_t) (rexmpp_t *s, xmlNodePtr node); typedef int (*xml_out_cb_t) (rexmpp_t *s, xmlNodePtr node); typedef void (*roster_modify_cb_t) (rexmpp_t *s, xmlNodePtr item); @@ -373,8 +373,7 @@ struct rexmpp rexmpp_tls_t tls; /* SASL structures. */ - Gsasl *sasl_ctx; - Gsasl_session *sasl_session; + rexmpp_sasl_ctx_t sasl; /* OpenPGP structures */ #ifdef HAVE_GPGME diff --git a/src/rexmpp_sasl.c b/src/rexmpp_sasl.c new file mode 100644 index 0000000..7dd16ba --- /dev/null +++ b/src/rexmpp_sasl.c @@ -0,0 +1,252 @@ +/** + @file rexmpp_sasl.c + @brief SASL + @author defanor + @date 2021 + @copyright MIT license. + +*/ + +#include + +#include "config.h" +#include "rexmpp.h" +#include "rexmpp_sasl.h" +#include "rexmpp_base64.h" + +#ifdef HAVE_GSASL +#include + +int rexmpp_sasl_cb (Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop) { + (void)sctx; /* The session should already be in rexmpp_t. */ + rexmpp_t *s = gsasl_callback_hook_get(ctx); + if (s == NULL || s->sasl_property_cb == NULL) { + return GSASL_NO_CALLBACK; + } + if (s->sasl_property_cb(s, (rexmpp_sasl_property)prop) == 0) { + return GSASL_OK; + } else { + return GSASL_NO_CALLBACK; + } +} + +int rexmpp_sasl_ctx_init (rexmpp_t *s) { + int err = gsasl_init(&(s->sasl.ctx)); + if (err != GSASL_OK) { + rexmpp_log(s, LOG_CRIT, "gsasl initialisation error: %s", + gsasl_strerror(err)); + return -1; + } + gsasl_callback_hook_set(s->sasl.ctx, s); + gsasl_callback_set(s->sasl.ctx, rexmpp_sasl_cb); + return 0; +} + +void rexmpp_sasl_ctx_deinit (rexmpp_t *s) { + gsasl_done(s->sasl.ctx); +} + +void rexmpp_sasl_ctx_cleanup (rexmpp_t *s) { + gsasl_finish(s->sasl.session); + s->sasl.session = NULL; +} + +int rexmpp_sasl_encode (rexmpp_t *s, const char *in, size_t in_len, char **out, size_t *out_len) { + int sasl_err = gsasl_encode (s->sasl.session, in, in_len, out, out_len); + if (sasl_err != GSASL_OK) { + rexmpp_log(s, LOG_ERR, "SASL encoding error: %s", gsasl_strerror(sasl_err)); + return -1; + } + return 0; +} + +int rexmpp_sasl_decode (rexmpp_t *s, const char *in, size_t in_len, char **out, size_t *out_len) { + int sasl_err = gsasl_decode(s->sasl.session, in, in_len, out, out_len); + if (sasl_err != GSASL_OK) { + rexmpp_log(s, LOG_ERR, "SASL decoding error: %s", gsasl_strerror(sasl_err)); + return -1; + } + return 0; +} + +const char *rexmpp_sasl_suggest_mechanism (rexmpp_t *s, const char *mech_list) { + return gsasl_client_suggest_mechanism(s->sasl.ctx, mech_list); +} + +void rexmpp_sasl_property_set (rexmpp_t *s, rexmpp_sasl_property prop, const char *data) { + gsasl_property_set (s->sasl.session, (Gsasl_property)prop, data); +} + +int rexmpp_sasl_start (rexmpp_t *s, const char *mech) { + int sasl_err = gsasl_client_start(s->sasl.ctx, mech, &(s->sasl.session)); + if (sasl_err != GSASL_OK) { + rexmpp_log(s, LOG_CRIT, "Failed to initialise SASL session: %s", + gsasl_strerror(sasl_err)); + return -1; + } + return 0; +} + +int rexmpp_sasl_step64 (rexmpp_t *s, const char *b64_in, char **b64_out) { + int sasl_err = gsasl_step64 (s->sasl.session, b64_in, b64_out); + if (sasl_err != GSASL_OK) { + if (sasl_err == GSASL_NEEDS_MORE) { + rexmpp_log(s, LOG_DEBUG, "SASL needs more data"); + } else { + rexmpp_log(s, LOG_ERR, "SASL error: %s", gsasl_strerror(sasl_err)); + return -1; + } + } + return 0; +} + +#else + +/* No GSASL. */ +#include + +int rexmpp_sasl_ctx_init (rexmpp_t *s) { + s->sasl.mech = REXMPP_SASL_MECH_UNKNOWN; + s->sasl.authid = NULL; + s->sasl.password = NULL; + return 0; +} + +void rexmpp_sasl_ctx_cleanup (rexmpp_t *s) { + s->sasl.mech = REXMPP_SASL_MECH_UNKNOWN; + if (s->sasl.authid != NULL) { + free(s->sasl.authid); + s->sasl.authid = NULL; + } + if (s->sasl.password != NULL) { + free(s->sasl.password); + s->sasl.password = NULL; + } +} + +void rexmpp_sasl_ctx_deinit (rexmpp_t *s) { + (void)s; +} + +int rexmpp_sasl_encode (rexmpp_t *s, const char *in, size_t in_len, char **out, size_t *out_len) { + (void)s; + *out = malloc(in_len); + memcpy(*out, in, in_len); + *out_len = in_len; + return 0; +} +int rexmpp_sasl_decode (rexmpp_t *s, const char *in, size_t in_len, char **out, size_t *out_len) { + (void)s; + *out = malloc(in_len); + memcpy(*out, in, in_len); + *out_len = in_len; + return 0; +} + +rexmpp_sasl_mechanism rexmpp_sasl_mech_read (const char *mech) { + if (mech == NULL) { + return REXMPP_SASL_MECH_UNKNOWN; + } + if (strcmp(mech, "EXTERNAL") == 0) { + return REXMPP_SASL_MECH_EXTERNAL; + } else if (strcmp(mech, "PLAIN") == 0) { + return REXMPP_SASL_MECH_PLAIN; + } else { + return REXMPP_SASL_MECH_UNKNOWN; + } +} + +const char *rexmpp_sasl_mech_name (rexmpp_sasl_mechanism mech) { + if (mech == REXMPP_SASL_MECH_EXTERNAL) { + return "EXTERNAL"; + } else if (mech == REXMPP_SASL_MECH_PLAIN) { + return "PLAIN"; + } else { + return NULL; + } +} + +const char *rexmpp_sasl_suggest_mechanism (rexmpp_t *s, const char *mech_list) { + (void)s; + char *mech, *save_ptr, *mlist = strdup(mech_list); + mech = strtok_r(mlist, " ", &save_ptr); + rexmpp_sasl_mechanism preferred = REXMPP_SASL_MECH_UNKNOWN; + while (mech != NULL) { + rexmpp_sasl_mechanism m = rexmpp_sasl_mech_read(mech); + if (m == REXMPP_SASL_MECH_EXTERNAL || + (m == REXMPP_SASL_MECH_PLAIN && preferred == REXMPP_SASL_MECH_UNKNOWN)) { + preferred = m; + } + mech = strtok_r(NULL, " ", &save_ptr); + } + free(mlist); + return rexmpp_sasl_mech_name(preferred); +} + +int rexmpp_sasl_start (rexmpp_t *s, const char *mech) { + rexmpp_sasl_mechanism m = rexmpp_sasl_mech_read(mech); + if (m != REXMPP_SASL_MECH_UNKNOWN) { + s->sasl.mech = m; + return 0; + } + return -1; +} + +const char *rexmpp_sasl_get_prop (rexmpp_t *s, rexmpp_sasl_property prop) { + if (prop == REXMPP_SASL_PROP_AUTHID) { + if (s->sasl.authid == NULL) { + s->sasl_property_cb(s, prop); + } + return s->sasl.authid; + } else if (prop == REXMPP_SASL_PROP_PASSWORD) { + if (s->sasl.password == NULL) { + s->sasl_property_cb(s, prop); + } + return s->sasl.password; + } + return NULL; +} + +int rexmpp_sasl_step64 (rexmpp_t *s, const char *b64_in, char **b64_out) { + (void)s; + (void)b64_in; + if (s->sasl.mech == REXMPP_SASL_MECH_PLAIN) { + /* RFC 4616 */ + const char *authid = rexmpp_sasl_get_prop(s, REXMPP_SASL_PROP_AUTHID); + const char *password = rexmpp_sasl_get_prop(s, REXMPP_SASL_PROP_PASSWORD); + if (authid != NULL && password != NULL) { + size_t auth_len = strlen(authid) + strlen(password) + 2; + char *auth = malloc(auth_len); + auth[0] = 0; + memcpy(auth + 1, authid, strlen(authid)); + auth[strlen(authid) + 1] = 0; + memcpy(auth + strlen(authid) + 2, password, strlen(password)); + size_t out_len; + rexmpp_base64_to(auth, auth_len, b64_out, &out_len); + free(auth); + return 0; + } + } else if (s->sasl.mech == REXMPP_SASL_MECH_EXTERNAL) { + *b64_out = strdup(""); + return 0; + } + return -1; +} + +void rexmpp_sasl_property_set (rexmpp_t *s, rexmpp_sasl_property prop, const char *data) { + (void)s; + (void)data; + if (prop == REXMPP_SASL_PROP_AUTHID) { + if (s->sasl.authid != NULL) { + free(s->sasl.authid); + } + s->sasl.authid = strdup(data); + } else if (prop == REXMPP_SASL_PROP_PASSWORD) { + if (s->sasl.password != NULL) { + free(s->sasl.password); + } + s->sasl.password = strdup(data); + } +} + +#endif diff --git a/src/rexmpp_sasl.h b/src/rexmpp_sasl.h new file mode 100644 index 0000000..a8460d4 --- /dev/null +++ b/src/rexmpp_sasl.h @@ -0,0 +1,110 @@ +/** + @file rexmpp_sasl.h + @brief SASL + @author defanor + @date 2021 + @copyright MIT license. + +*/ + + +#ifndef REXMPP_SASL_H +#define REXMPP_SASL_H + +#include "config.h" + +#include "rexmpp.h" + +/** @brief These correspond to Gsasl_property values. */ +typedef enum { + /* Information properties, e.g., username. */ + REXMPP_SASL_PROP_AUTHID = 1, + REXMPP_SASL_PROP_AUTHZID = 2, + REXMPP_SASL_PROP_PASSWORD = 3, + REXMPP_SASL_PROP_ANONYMOUS_TOKEN = 4, + REXMPP_SASL_PROP_SERVICE = 5, + REXMPP_SASL_PROP_HOSTNAME = 6, + REXMPP_SASL_PROP_GSSAPI_DISPLAY_NAME = 7, + REXMPP_SASL_PROP_PASSCODE = 8, + REXMPP_SASL_PROP_SUGGESTED_PIN = 9, + REXMPP_SASL_PROP_PIN = 10, + REXMPP_SASL_PROP_REALM = 11, + REXMPP_SASL_PROP_DIGEST_MD5_HASHED_PASSWORD = 12, + REXMPP_SASL_PROP_QOPS = 13, + REXMPP_SASL_PROP_QOP = 14, + REXMPP_SASL_PROP_SCRAM_ITER = 15, + REXMPP_SASL_PROP_SCRAM_SALT = 16, + REXMPP_SASL_PROP_SCRAM_SALTED_PASSWORD = 17, + REXMPP_SASL_PROP_SCRAM_SERVERKEY = 23, + REXMPP_SASL_PROP_SCRAM_STOREDKEY = 24, + REXMPP_SASL_PROP_CB_TLS_UNIQUE = 18, + REXMPP_SASL_PROP_SAML20_IDP_IDENTIFIER = 19, + REXMPP_SASL_PROP_SAML20_REDIRECT_URL = 20, + REXMPP_SASL_PROP_OPENID20_REDIRECT_URL = 21, + REXMPP_SASL_PROP_OPENID20_OUTCOME_DATA = 22, + /* Client callbacks. */ + REXMPP_SASL_PROP_SAML20_AUTHENTICATE_IN_BROWSER = 250, + REXMPP_SASL_PROP_OPENID20_AUTHENTICATE_IN_BROWSER = 251, + /* Server validation callback properties. */ + REXMPP_SASL_PROP_VALIDATE_SIMPLE = 500, + REXMPP_SASL_PROP_VALIDATE_EXTERNAL = 501, + REXMPP_SASL_PROP_VALIDATE_ANONYMOUS = 502, + REXMPP_SASL_PROP_VALIDATE_GSSAPI = 503, + REXMPP_SASL_PROP_VALIDATE_SECURID = 504, + REXMPP_SASL_PROP_VALIDATE_SAML20 = 505, + REXMPP_SASL_PROP_VALIDATE_OPENID20 = 506 +} rexmpp_sasl_property; + +/** + @brief SASL context. +*/ +#ifdef HAVE_GSASL +#include +struct rexmpp_sasl_ctx { + Gsasl *ctx; + Gsasl_session *session; +}; +#else +typedef enum { + REXMPP_SASL_MECH_EXTERNAL, + REXMPP_SASL_MECH_PLAIN, + REXMPP_SASL_MECH_UNKNOWN +} rexmpp_sasl_mechanism; + +struct rexmpp_sasl_ctx { + rexmpp_sasl_mechanism mech; + char *authid; + char *password; +}; +#endif + +typedef struct rexmpp_sasl_ctx rexmpp_sasl_ctx_t; + +/** + @brief Initializes SASL context. +*/ +int rexmpp_sasl_ctx_init (rexmpp_t *s); + +/** + @brief Cleans up the state that can be discarded between XMPP + connections, to be called from rexmpp_cleanup. +*/ +void rexmpp_sasl_ctx_cleanup (rexmpp_t *s); + +/** + @brief Deinitializes a SASL context. +*/ +void rexmpp_sasl_ctx_deinit (rexmpp_t *s); + + +int rexmpp_sasl_encode (rexmpp_t *s, const char *in, size_t in_len, char **out, size_t *out_len); +int rexmpp_sasl_decode (rexmpp_t *s, const char *in, size_t in_len, char **out, size_t *out_len); + +const char *rexmpp_sasl_suggest_mechanism (rexmpp_t *s, const char *mech_list); + +int rexmpp_sasl_start (rexmpp_t *s, const char *mech); +int rexmpp_sasl_step64 (rexmpp_t *s, const char *b64_in, char **b64_out); + +void rexmpp_sasl_property_set (rexmpp_t *s, rexmpp_sasl_property prop, const char *data); + +#endif -- cgit v1.2.3