26 #include <gsasl-mech.h> 129 ret = gsasl_encode(sd, buf->
data, buf->
len, &out, &len);
130 if (ret != GSASL_OK) {
131 _sx_debug(
ZONE,
"gsasl_encode failed (%d): %s", ret, gsasl_strerror (ret));
157 ret = gsasl_decode(sd, buf->
data, buf->
len, &out, &len);
158 if (ret != GSASL_OK) {
159 _sx_debug(
ZONE,
"gsasl_decode failed (%d): %s", ret, gsasl_strerror (ret));
177 char *method, *authzid;
178 const char *realm = NULL;
182 const char *mechname = gsasl_mechanism_name (sd);
185 method = (
char *) malloc(
sizeof(
char) * (strlen(mechname) + 6));
186 sprintf(method,
"SASL/%s", mechname);
189 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
190 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
191 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
193 if(0 && ctx && ctx->
cb) {
195 _sx_debug(
ZONE,
"stream authzid: %s verification failed, not advancing to auth state", creds.
authzid);
199 }
else if (NULL != gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)) {
200 creds.
authzid = strdup(gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME));
209 authzid = (
char *) malloc(
sizeof(
char) * (strlen(creds.
authnid) + strlen(realm) + 2));
210 sprintf(authzid,
"%s@%s", creds.
authnid, realm);
218 if(authzid) free(authzid);
230 if(NULL == gsasl_property_fast(sd, GSASL_AUTHID)) {
231 _sx_debug(
ZONE,
"not auth'd, not advancing to auth'd state yet");
243 char *mechs, *mech, *c;
249 _sx_debug(
ZONE,
"already auth'd, not offering sasl mechanisms");
254 _sx_debug(
ZONE,
"application didn't ask us to offer sasl, so we won't");
260 _sx_debug(
ZONE,
"ssl not established yet but the app requires it, not offering mechanisms");
267 ret = gsasl_server_mechlist(ctx->
gsasl_ctx, &mechs);
268 if(ret != GSASL_OK) {
269 _sx_debug(
ZONE,
"gsasl_server_mechlist failed (%d): %s, not offering sasl for this conn", ret, gsasl_strerror (ret));
275 while(mech != NULL) {
276 c = strchr(mech,
' ');
317 char *buf = NULL, *out = NULL, *
realm = NULL, **
ext_id;
323 size_t buflen, outlen;
329 _sx_debug(
ZONE,
"auth request from client (mechanism=%s)", mech);
331 if(!gsasl_server_support_p(ctx->
gsasl_ctx, mech)) {
332 _sx_debug(
ZONE,
"client requested mechanism (%s) that we didn't offer", mech);
338 ret = gsasl_server_start(ctx->
gsasl_ctx, mech, &sd);
339 if(ret != GSASL_OK) {
340 _sx_debug(
ZONE,
"gsasl_server_start failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
349 sctx = gsasl_session_hook_get(sd);
350 if (sctx != NULL) free(sctx);
356 gsasl_session_hook_set(sd, (
void *) sctx);
357 gsasl_property_set(sd, GSASL_SERVICE, ctx->
appname);
358 gsasl_property_set(sd, GSASL_REALM,
realm);
362 gethostname(hostname, 256);
363 hostname[255] =
'\0';
364 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
369 for(i = 0; i < s->env->nplugins; i++)
370 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
371 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
387 s->plugin_data[p->
index] = (
void *) sd;
389 if(strcmp(mech,
"ANONYMOUS") == 0) {
398 buflen = strlen(buf);
399 }
else if (strstr(in,
"<") != NULL && strncmp(in,
"=", strstr(in,
"<") - in ) == 0) {
404 buflen = strlen(buf);
407 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
408 if (ret != GSASL_OK) {
409 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
411 if(buf != NULL) free(buf);
416 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
417 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
418 _sx_debug(
ZONE,
"gsasl_step failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
420 if(out != NULL) free(out);
421 if(buf != NULL) free(buf);
428 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
429 if (ret != GSASL_OK) {
430 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
436 _sx_debug(
ZONE,
"response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
438 if(buf != NULL) free(buf);
441 _sx_debug(
ZONE,
"response from client (decoded: %.*s)", buflen, buf);
442 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
445 if(buf != NULL) free(buf);
448 if(ret == GSASL_OK) {
452 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
453 if (ret == GSASL_OK) {
463 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
465 if(buf != NULL) free(buf);
468 if(out != NULL) free(out);
474 if(ret == GSASL_NEEDS_MORE) {
475 _sx_debug(
ZONE,
"sasl handshake in progress (challenge: %.*s)", outlen, out);
478 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
479 if (ret == GSASL_OK) {
484 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
486 if(buf != NULL) free(buf);
489 if(out != NULL) free(out);
494 if(out != NULL) free(out);
497 _sx_debug(
ZONE,
"sasl handshake failed; (%d): %s", ret, gsasl_strerror(ret));
505 char *buf = NULL, *out = NULL;
506 size_t buflen, outlen;
512 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
514 if (ret == GSASL_OK) {
518 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
519 if(buf != NULL) free(buf); buf = NULL;
522 if(ret == GSASL_OK || ret == GSASL_NEEDS_MORE) {
523 _sx_debug(
ZONE,
"sasl handshake in progress (response: %.*s)", outlen, out);
526 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
528 if (ret == GSASL_OK) {
532 if(out != NULL) free(out);
533 if(buf != NULL) free(buf);
538 if(out != NULL) free(out);
539 if(buf != NULL) free(buf);
542 _sx_debug(
ZONE,
"sasl handshake aborted; (%d): %s", ret, gsasl_strerror(ret));
554 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
570 _sx_debug(
ZONE,
"they tried to do sasl, but we never offered it, ignoring");
577 _sx_debug(
ZONE,
"they tried to do sasl, but they have to do starttls first, ignoring");
586 if((attr =
nad_find_attr(nad, 0, -1,
"mechanism", NULL)) < 0) {
625 _sx_debug(
ZONE,
"got sasl client packets, but they never started sasl, ignoring");
647 if(s->
ns != NULL) ns = strdup(s->
ns);
656 _sx_debug(
ZONE,
"restarting stream with sasl layer established");
662 if(ns != NULL) free(ns);
663 if(to != NULL) free(to);
664 if(from != NULL) free(from);
665 if(version != NULL) free(version);
704 sctx = gsasl_session_hook_get(sd);
707 gsasl_session_hook_set(sd, (
void *) NULL);
718 char *value, *node, *host;
729 _sx_debug(
ZONE,
"in _sx_sasl_gsasl_callback, property: %d", prop);
736 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
737 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
738 if(!creds.
authnid)
return GSASL_NO_AUTHID;
739 if(!creds.
realm)
return GSASL_NO_AUTHZID;
741 gsasl_property_set(sd, GSASL_PASSWORD, value);
743 return GSASL_NEEDS_MORE;
746 gsasl_property_set(sd, GSASL_SERVICE,
"xmpp");
754 gethostname(hostname, 256);
755 hostname[255] =
'\0';
757 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
761 case GSASL_VALIDATE_SIMPLE:
765 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
766 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
767 creds.
pass = gsasl_property_fast(sd, GSASL_PASSWORD);
768 if(!creds.
authnid)
return GSASL_NO_AUTHID;
769 if(!creds.
realm)
return GSASL_NO_AUTHZID;
770 if(!creds.
pass)
return GSASL_NO_PASSWORD;
774 return GSASL_AUTHENTICATION_ERROR;
776 case GSASL_VALIDATE_GSSAPI:
778 creds.
authnid = gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME);
779 if(!creds.
authnid)
return GSASL_NO_AUTHID;
780 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
781 if(!creds.
authzid)
return GSASL_NO_AUTHZID;
782 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
785 case GSASL_VALIDATE_ANONYMOUS:
787 creds.
authnid = gsasl_property_fast(sd, GSASL_ANONYMOUS_TOKEN);
788 if(!creds.
authnid)
return GSASL_NO_ANONYMOUS_TOKEN;
790 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
793 case GSASL_VALIDATE_EXTERNAL:
797 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
802 if (ctx->
ext_id[i] == NULL)
806 value = strstr(ctx->
ext_id[i],
"@");
811 _sx_debug(
ZONE,
"sasl ctx->ext_id doesn't have '@' in it. Assuming s2s");
822 len = value - ctx->
ext_id[i];
823 node = (
char *) malloc(
sizeof(
char) * (len + 1));
824 strncpy(node, ctx->
ext_id[i], len);
827 len = strlen(value) - 1 + 1;
828 host = (
char *) malloc(
sizeof(
char) * (len));
829 strcpy(host, value + 1);
830 gsasl_property_set(sd, GSASL_AUTHID, node);
831 gsasl_property_set(sd, GSASL_REALM, host);
836 return GSASL_AUTHENTICATION_ERROR;
842 return GSASL_NO_CALLBACK;
853 if(ctx->
ext_id[i] != NULL)
871 appname = va_arg(args,
const char *);
872 if(appname == NULL) {
878 cbarg = va_arg(args,
void *);
882 ctx->
appname = strdup(appname);
889 if(ret != GSASL_OK) {
890 _sx_debug(
ZONE,
"couldn't initialize libgsasl (%d): %s", ret, gsasl_strerror (ret));
919 char *buf = NULL, *out = NULL;
922 size_t buflen, outlen;
927 assert((appname != NULL));
928 assert((mech != NULL));
929 assert((user != NULL));
930 assert((pass != NULL));
933 _sx_debug(
ZONE,
"need client in stream state for sasl auth");
938 ret = gsasl_client_start(ctx->
gsasl_ctx, mech, &sd);
939 if(ret != GSASL_OK) {
940 _sx_debug(
ZONE,
"gsasl_client_start failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
947 gethostname(hostname, 256);
948 hostname[255] =
'\0';
951 sctx = gsasl_session_hook_get(sd);
952 if (sctx != NULL) free(sctx);
960 gsasl_session_hook_set(sd, (
void *) sctx);
961 gsasl_property_set(sd, GSASL_AUTHID, user);
962 gsasl_property_set(sd, GSASL_PASSWORD, pass);
963 gsasl_property_set(sd, GSASL_SERVICE, appname);
964 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
967 ret = gsasl_step(sd, NULL, 0, &out, &outlen);
968 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
969 _sx_debug(
ZONE,
"gsasl_step failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
980 _sx_debug(
ZONE,
"sending auth request to server, mech '%s': %.*s", mech, outlen, out);
983 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
984 if(ret != GSASL_OK) {
985 _sx_debug(
ZONE,
"gsasl_base64_to failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
989 if (out != NULL) free(out);
void(* free)(sx_t s, sx_plugin_t p)
nad_t nad_new(void)
create a new nad
int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
attach new attr to the last elem
#define sx_sasl_cb_CHECK_MECH
#define _sx_event(s, e, data)
#define NAD_CDATA_L(N, E)
#define sx_nad_write(s, nad)
static nad_t _sx_sasl_response(sx_t s, const char *data, int dlen)
utility: generate a response nad
static nad_t _sx_sasl_success(sx_t s, const char *data, int dlen)
utility: generate a success nad
int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args)
args: appname, callback, cb arg
static void _sx_sasl_notify_success(sx_t s, void *arg)
auth done, restart the stream
int nad_find_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val)
get a matching attr on this elem, both name and optional val
static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, Gsasl_session *sd, const char *in, int inlen)
process handshake packets from the server
void(* unload)(sx_plugin_t p)
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
void(* features)(sx_t s, sx_plugin_t p, nad_t nad)
error info for event_ERROR
#define _sasl_err_ABORTED
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
#define _sasl_err_MALFORMED_REQUEST
void sx_server_init(sx_t s, unsigned int flags)
void _sx_chain_io_plugin(sx_t s, sx_plugin_t p)
struct _sx_sasl_sess_st * _sx_sasl_sess_t
our sasl per session context
char * ext_id[SX_CONN_EXTERNAL_ID_MAX_COUNT]
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
void nad_free(nad_t nad)
free that nad
int sx_sasl_auth(sx_plugin_t p, sx_t s, const char *appname, const char *mech, const char *user, const char *pass)
kick off the auth handshake
#define sx_sasl_cb_CHECK_AUTHZID
holds the state for a single stream
#define SX_SSL_MAGIC
magic numbers, so plugins can find each other
static nad_t _sx_sasl_abort(sx_t s)
utility: generate an abort nad
void sx_client_init(sx_t s, unsigned int flags, const char *ns, const char *to, const char *from, const char *version)
#define NAD_ENAME_L(N, E)
#define NAD_NURI_L(N, NS)
static void _sx_sasl_free(sx_t s, sx_plugin_t p)
cleanup
int(* sx_sasl_callback_t)(int cb, void *arg, void **res, sx_t s, void *cbarg)
the callback function
static void _sx_sasl_stream(sx_t s, sx_plugin_t p)
make the stream authenticated second time round
void(* stream)(sx_t s, sx_plugin_t p)
struct _sx_plugin_st * sx_plugin_t
#define SX_SSL_STARTTLS_REQUIRE
struct _sx_buf_st * sx_buf_t
utility: buffer
#define _sasl_err_INCORRECT_ENCODING
static nad_t _sx_sasl_failure(sx_t s, const char *err)
utility: generate a failure nad
our sasl per session context
void _sx_reset(sx_t s)
utility; reset stream state
#define sx_sasl_cb_GET_REALM
static int _sx_sasl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf)
static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, Gsasl_session *sd, const char *mech, const char *in, int inlen)
process handshake packets from the client
static nad_t _sx_sasl_challenge(sx_t s, const char *data, int dlen)
utility: generate a challenge nad
int(* wio)(sx_t s, sx_plugin_t p, sx_buf_t buf)
static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad)
#define _sasl_err_MECH_TOO_WEAK
void _sx_sasl_open(sx_t s, Gsasl_session *sd)
move the stream to the auth state
#define _sasl_err_TEMPORARY_FAILURE
#define _sx_gen_error(e, c, g, s)
helper macro to populate this struct
void _sx_buffer_set(sx_buf_t buf, char *newdata, int newlength, char *newheap)
utility: reset a sx_buf_t's contents.
static void _sx_sasl_unload(sx_plugin_t p)
int(* process)(sx_t s, sx_plugin_t p, nad_t nad)
int(* rio)(sx_t s, sx_plugin_t p, sx_buf_t buf)
#define sx_sasl_cb_GEN_AUTHZID
static int _sx_sasl_gsasl_callback(Gsasl *gsasl_ctx, Gsasl_session *sd, Gsasl_property prop)
static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad)
main nad processor
int _sx_nad_write(sx_t s, nad_t nad, int elem)
send a new nad out
void sx_auth(sx_t s, const char *auth_method, const char *auth_id)
force advance into auth state
#define SX_CONN_EXTERNAL_ID_MAX_COUNT
our sasl application context
static int _sx_sasl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf)
#define sx_sasl_cb_CHECK_PASS
struct _sx_sasl_st * _sx_sasl_t
our sasl application context
#define sx_sasl_cb_GET_PASS
#define _sasl_err_INVALID_MECHANISM