summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2021-10-02 20:23:38 +0300
committerdefanor <defanor@uberspace.net>2021-10-02 20:23:38 +0300
commit024e998f8b73047eb2ae56ea92cb2cbc0bbedc17 (patch)
tree0bb0f816d810d2dc89766669d609f7893f3e7963 /src
parent163742a2d85eabfa844b08e9958a9ae348de5435 (diff)
Make libgsasl optional
Only EXTERNAL and PLAIN mechanisms are supported without it for now.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/rexmpp.c92
-rw-r--r--src/rexmpp.h7
-rw-r--r--src/rexmpp_sasl.c252
-rw-r--r--src/rexmpp_sasl.h110
5 files changed, 397 insertions, 70 deletions
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 <gcrypt.h>
#include <libxml/tree.h>
#include <libxml/xmlsave.h>
-#include <gsasl.h>
#include <unbound.h>
#ifdef HAVE_GPGME
#include <gpgme.h>
@@ -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 <gsasl.h>
#include <libxml/tree.h>
#ifdef HAVE_GPGME
#include <gpgme.h>
@@ -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 <defanor@uberspace.net>
+ @date 2021
+ @copyright MIT license.
+
+*/
+
+#include <syslog.h>
+
+#include "config.h"
+#include "rexmpp.h"
+#include "rexmpp_sasl.h"
+#include "rexmpp_base64.h"
+
+#ifdef HAVE_GSASL
+#include <gsasl.h>
+
+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 <memory.h>
+
+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 <defanor@uberspace.net>
+ @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 <gsasl.h>
+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