26 #include <gsasl-mech.h>
123 ret = gsasl_encode(sd, buf->
data, buf->
len, &out, &len);
124 if (ret != GSASL_OK) {
125 _sx_debug(
ZONE,
"gsasl_encode failed (%d): %s", ret, gsasl_strerror (ret));
151 ret = gsasl_decode(sd, buf->
data, buf->
len, &out, &len);
152 if (ret != GSASL_OK) {
153 _sx_debug(
ZONE,
"gsasl_decode failed (%d): %s", ret, gsasl_strerror (ret));
171 char *method, *authzid;
172 const char *realm = NULL;
175 const char *mechname = gsasl_mechanism_name (sd);
178 method = (
char *) malloc(
sizeof(
char) * (strlen(mechname) + 6));
179 sprintf(method,
"SASL/%s", mechname);
182 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
183 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
184 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
186 if(0 && ctx && ctx->
cb) {
188 _sx_debug(
ZONE,
"stream authzid: %s verification failed, not advancing to auth state", creds.
authzid);
192 }
else if (NULL != gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)) {
193 creds.
authzid = strdup(gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME));
202 authzid = (
char *) malloc(
sizeof(
char) * (strlen(creds.
authnid) + strlen(realm) + 2));
203 sprintf(authzid,
"%s@%s", creds.
authnid, realm);
211 if(authzid) free(authzid);
223 if(NULL == gsasl_property_fast(sd, GSASL_AUTHID)) {
224 _sx_debug(
ZONE,
"not auth'd, not advancing to auth'd state yet");
236 char *mechs, *mech, *c;
242 _sx_debug(
ZONE,
"already auth'd, not offering sasl mechanisms");
247 _sx_debug(
ZONE,
"application didn't ask us to offer sasl, so we won't");
253 _sx_debug(
ZONE,
"ssl not established yet but the app requires it, not offering mechanisms");
260 ret = gsasl_server_mechlist(ctx->
gsasl_ctx, &mechs);
261 if(ret != GSASL_OK) {
262 _sx_debug(
ZONE,
"gsasl_server_mechlist failed (%d): %s, not offering sasl for this conn", ret, gsasl_strerror (ret));
268 while(mech != NULL) {
269 c = strchr(mech,
' ');
309 char *buf = NULL, *out = NULL, *
realm = NULL, **ext_id;
315 size_t buflen, outlen;
318 _sx_debug(
ZONE,
"auth request from client (mechanism=%s)", mech);
320 if(!gsasl_server_support_p(ctx->
gsasl_ctx, mech)) {
321 _sx_debug(
ZONE,
"client requested mechanism (%s) that we didn't offer", mech);
327 ret = gsasl_server_start(ctx->
gsasl_ctx, mech, &sd);
328 if(ret != GSASL_OK) {
329 _sx_debug(
ZONE,
"gsasl_server_start failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
338 gsasl_session_hook_set(sd, (
void *) ctx);
339 gsasl_property_set(sd, GSASL_SERVICE, ctx->
appname);
340 gsasl_property_set(sd, GSASL_REALM,
realm);
344 gethostname(hostname, 256);
345 hostname[255] =
'\0';
346 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
351 for(i = 0; i < s->env->nplugins; i++)
352 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
353 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
354 if (ext_id != NULL) {
358 if (ext_id[i] != NULL) {
359 ctx->
ext_id[i] = strdup(ext_id[i]);
369 s->plugin_data[p->
index] = (
void *) sd;
371 if(strcmp(mech,
"ANONYMOUS") == 0) {
380 buflen = strlen(buf);
381 }
else if (strstr(in,
"<") != NULL && strncmp(in,
"=", strstr(in,
"<") - in ) == 0) {
386 buflen = strlen(buf);
389 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
390 if (ret != GSASL_OK) {
391 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
393 if(buf != NULL) free(buf);
398 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
399 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
400 _sx_debug(
ZONE,
"gsasl_step failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
402 if(out != NULL) free(out);
403 if(buf != NULL) free(buf);
410 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
411 if (ret != GSASL_OK) {
412 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
418 _sx_debug(
ZONE,
"response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
420 if(buf != NULL) free(buf);
423 _sx_debug(
ZONE,
"response from client (decoded: %.*s)", buflen, buf);
424 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
427 if(buf != NULL) free(buf);
430 if(ret == GSASL_OK) {
434 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
435 if (ret == GSASL_OK) {
445 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
447 if(buf != NULL) free(buf);
450 if(out != NULL) free(out);
456 if(ret == GSASL_NEEDS_MORE) {
457 _sx_debug(
ZONE,
"sasl handshake in progress (challenge: %.*s)", outlen, out);
460 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
461 if (ret == GSASL_OK) {
466 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
468 if(buf != NULL) free(buf);
471 if(out != NULL) free(out);
476 if(out != NULL) free(out);
479 _sx_debug(
ZONE,
"sasl handshake failed; (%d): %s", ret, gsasl_strerror(ret));
487 char *buf = NULL, *out = NULL;
488 size_t buflen, outlen;
494 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
496 if (ret == GSASL_OK) {
500 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
501 if(buf != NULL) free(buf); buf = NULL;
504 if(ret == GSASL_OK || ret == GSASL_NEEDS_MORE) {
505 _sx_debug(
ZONE,
"sasl handshake in progress (response: %.*s)", outlen, out);
508 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
510 if (ret == GSASL_OK) {
514 if(out != NULL) free(out);
515 if(buf != NULL) free(buf);
520 if(out != NULL) free(out);
521 if(buf != NULL) free(buf);
524 _sx_debug(
ZONE,
"sasl handshake aborted; (%d): %s", ret, gsasl_strerror(ret));
536 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
552 _sx_debug(
ZONE,
"they tried to do sasl, but we never offered it, ignoring");
559 _sx_debug(
ZONE,
"they tried to do sasl, but they have to do starttls first, ignoring");
568 if((attr =
nad_find_attr(nad, 0, -1,
"mechanism", NULL)) < 0) {
607 _sx_debug(
ZONE,
"got sasl client packets, but they never started sasl, ignoring");
629 if(s->
ns != NULL) ns = strdup(s->
ns);
638 _sx_debug(
ZONE,
"restarting stream with sasl layer established");
644 if(ns != NULL) free(ns);
645 if(to != NULL) free(to);
646 if(from != NULL) free(from);
647 if(version != NULL) free(version);
691 char *value, *node, *host;
694 _sx_debug(
ZONE,
"in _sx_sasl_gsasl_callback, property: %d", prop);
698 assert((ctx->
cb != NULL));
699 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
700 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
701 if(!creds.
authnid)
return GSASL_NO_AUTHID;
702 if(!creds.
realm)
return GSASL_NO_AUTHZID;
704 gsasl_property_set(sd, GSASL_PASSWORD, value);
706 return GSASL_NEEDS_MORE;
709 gsasl_property_set(sd, GSASL_SERVICE,
"xmpp");
717 gethostname(hostname, 256);
718 hostname[255] =
'\0';
720 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
724 case GSASL_VALIDATE_SIMPLE:
726 assert((ctx->
cb != NULL));
727 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
728 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
729 creds.
pass = gsasl_property_fast(sd, GSASL_PASSWORD);
730 if(!creds.
authnid)
return GSASL_NO_AUTHID;
731 if(!creds.
realm)
return GSASL_NO_AUTHZID;
732 if(!creds.
pass)
return GSASL_NO_PASSWORD;
736 return GSASL_AUTHENTICATION_ERROR;
738 case GSASL_VALIDATE_GSSAPI:
740 creds.
authnid = gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME);
741 if(!creds.
authnid)
return GSASL_NO_AUTHID;
742 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
743 if(!creds.
authzid)
return GSASL_NO_AUTHZID;
744 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
747 case GSASL_VALIDATE_ANONYMOUS:
749 creds.
authnid = gsasl_property_fast(sd, GSASL_ANONYMOUS_TOKEN);
750 if(!creds.
authnid)
return GSASL_NO_ANONYMOUS_TOKEN;
752 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
755 case GSASL_VALIDATE_EXTERNAL:
757 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
762 if (ctx->
ext_id[i] == NULL)
766 value = strstr(ctx->
ext_id[i],
"@");
771 _sx_debug(
ZONE,
"sasl ctx->ext_id doesn't have '@' in it. Assuming s2s");
782 len = value - ctx->
ext_id[i];
783 node = (
char *) malloc(
sizeof(
char) * (len + 1));
784 strncpy(node, ctx->
ext_id[i], len);
787 len = strlen(value) - 1 + 1;
788 host = (
char *) malloc(
sizeof(
char) * (len));
789 strcpy(host, value + 1);
790 gsasl_property_set(sd, GSASL_AUTHID, node);
791 gsasl_property_set(sd, GSASL_REALM, host);
796 return GSASL_AUTHENTICATION_ERROR;
802 return GSASL_NO_CALLBACK;
812 if(ctx->
ext_id[i] != NULL)
817 if (ctx != NULL) free(ctx);
830 appname = va_arg(args,
const char *);
831 if(appname == NULL) {
837 cbarg = va_arg(args,
void *);
841 ctx->
appname = strdup(appname);
848 if(ret != GSASL_OK) {
849 _sx_debug(
ZONE,
"couldn't initialize libgsasl (%d): %s", ret, gsasl_strerror (ret));
877 char *buf = NULL, *out = NULL;
880 size_t buflen, outlen;
885 assert((appname != NULL));
886 assert((mech != NULL));
887 assert((user != NULL));
888 assert((pass != NULL));
891 _sx_debug(
ZONE,
"need client in stream state for sasl auth");
896 ret = gsasl_client_start(ctx->
gsasl_ctx, mech, &sd);
897 if(ret != GSASL_OK) {
898 _sx_debug(
ZONE,
"gsasl_client_start failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
905 gethostname(hostname, 256);
906 hostname[255] =
'\0';
909 gsasl_session_hook_set(sd, (
void *) ctx);
910 gsasl_property_set(sd, GSASL_AUTHID, user);
911 gsasl_property_set(sd, GSASL_PASSWORD, pass);
912 gsasl_property_set(sd, GSASL_SERVICE, appname);
913 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
916 ret = gsasl_step(sd, NULL, 0, &out, &outlen);
917 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
918 _sx_debug(
ZONE,
"gsasl_step failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
929 _sx_debug(
ZONE,
"sending auth request to server, mech '%s': %.*s", mech, outlen, out);
932 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
933 if(ret != GSASL_OK) {
934 _sx_debug(
ZONE,
"gsasl_base64_to failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
938 if (out != NULL) free(out);
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
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 nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
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)
char * ext_id[SX_CONN_EXTERNAL_ID_MAX_COUNT]
void(* free)(sx_t s, sx_plugin_t p)
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
void(* features)(sx_t s, sx_plugin_t p, nad_t 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
static void _sx_sasl_stream(sx_t s, sx_plugin_t p)
make the stream authenticated second time round
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
void _sx_reset(sx_t s)
utility; reset stream state
#define sx_sasl_cb_GET_REALM
int(* rio)(sx_t s, sx_plugin_t p, sx_buf_t buf)
static int _sx_sasl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf)
int(* sx_sasl_callback_t)(int cb, void *arg, void **res, sx_t s, void *cbarg)
the callback function
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
void(* stream)(sx_t s, sx_plugin_t p)
void(* unload)(sx_plugin_t p)
static nad_t _sx_sasl_challenge(sx_t s, const char *data, int dlen)
utility: generate a challenge nad
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
int(* wio)(sx_t s, sx_plugin_t p, sx_buf_t buf)
#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)
#define sx_sasl_cb_GEN_AUTHZID
int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
get a matching attr on this elem, both name and optional val
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
int(* process)(sx_t s, sx_plugin_t p, nad_t nad)
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 context
#define sx_sasl_cb_GET_PASS
#define _sasl_err_INVALID_MECHANISM