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;
326 _sx_debug(
ZONE,
"auth request from client (mechanism=%s)", mech);
328 if(!gsasl_server_support_p(ctx->
gsasl_ctx, mech)) {
329 _sx_debug(
ZONE,
"client requested mechanism (%s) that we didn't offer", mech);
335 ret = gsasl_server_start(ctx->
gsasl_ctx, mech, &sd);
336 if(ret != GSASL_OK) {
337 _sx_debug(
ZONE,
"gsasl_server_start failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
347 sctx = gsasl_session_hook_get(sd);
348 if (sctx != NULL) free(sctx);
354 gsasl_session_hook_set(sd, (
void *) sctx);
355 gsasl_property_set(sd, GSASL_SERVICE, ctx->
appname);
356 gsasl_property_set(sd, GSASL_REALM,
realm);
360 gethostname(hostname, 256);
361 hostname[255] =
'\0';
362 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
367 for(i = 0; i < s->env->nplugins; i++)
368 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
369 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
370 if (ext_id != NULL) {
374 if (ext_id[i] != NULL) {
375 ctx->
ext_id[i] = strdup(ext_id[i]);
385 s->plugin_data[p->
index] = (
void *) sd;
387 if(strcmp(mech,
"ANONYMOUS") == 0) {
396 buflen = strlen(buf);
397 }
else if (strstr(in,
"<") != NULL && strncmp(in,
"=", strstr(in,
"<") - in ) == 0) {
402 buflen = strlen(buf);
405 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
406 if (ret != GSASL_OK) {
407 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
409 if(buf != NULL) free(buf);
414 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
415 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
416 _sx_debug(
ZONE,
"gsasl_step failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
418 if(out != NULL) free(out);
419 if(buf != NULL) free(buf);
426 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
427 if (ret != GSASL_OK) {
428 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
434 _sx_debug(
ZONE,
"response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
436 if(buf != NULL) free(buf);
439 _sx_debug(
ZONE,
"response from client (decoded: %.*s)", buflen, buf);
440 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
443 if(buf != NULL) free(buf);
446 if(ret == GSASL_OK) {
450 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
451 if (ret == GSASL_OK) {
461 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
463 if(buf != NULL) free(buf);
466 if(out != NULL) free(out);
472 if(ret == GSASL_NEEDS_MORE) {
473 _sx_debug(
ZONE,
"sasl handshake in progress (challenge: %.*s)", outlen, out);
476 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
477 if (ret == GSASL_OK) {
482 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
484 if(buf != NULL) free(buf);
487 if(out != NULL) free(out);
492 if(out != NULL) free(out);
495 _sx_debug(
ZONE,
"sasl handshake failed; (%d): %s", ret, gsasl_strerror(ret));
503 char *buf = NULL, *out = NULL;
504 size_t buflen, outlen;
510 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
512 if (ret == GSASL_OK) {
516 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
517 if(buf != NULL) free(buf); buf = NULL;
520 if(ret == GSASL_OK || ret == GSASL_NEEDS_MORE) {
521 _sx_debug(
ZONE,
"sasl handshake in progress (response: %.*s)", outlen, out);
524 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
526 if (ret == GSASL_OK) {
530 if(out != NULL) free(out);
531 if(buf != NULL) free(buf);
536 if(out != NULL) free(out);
537 if(buf != NULL) free(buf);
540 _sx_debug(
ZONE,
"sasl handshake aborted; (%d): %s", ret, gsasl_strerror(ret));
552 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
568 _sx_debug(
ZONE,
"they tried to do sasl, but we never offered it, ignoring");
575 _sx_debug(
ZONE,
"they tried to do sasl, but they have to do starttls first, ignoring");
584 if((attr =
nad_find_attr(nad, 0, -1,
"mechanism", NULL)) < 0) {
623 _sx_debug(
ZONE,
"got sasl client packets, but they never started sasl, ignoring");
645 if(s->
ns != NULL) ns = strdup(s->
ns);
654 _sx_debug(
ZONE,
"restarting stream with sasl layer established");
660 if(ns != NULL) free(ns);
661 if(to != NULL) free(to);
662 if(from != NULL) free(from);
663 if(version != NULL) free(version);
702 sctx = gsasl_session_hook_get(sd);
705 gsasl_session_hook_set(sd, (
void *) NULL);
716 char *value, *node, *host;
727 _sx_debug(
ZONE,
"in _sx_sasl_gsasl_callback, property: %d", prop);
732 assert((ctx->
cb != NULL));
733 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
734 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
735 if(!creds.
authnid)
return GSASL_NO_AUTHID;
736 if(!creds.
realm)
return GSASL_NO_AUTHZID;
738 gsasl_property_set(sd, GSASL_PASSWORD, value);
740 return GSASL_NEEDS_MORE;
743 gsasl_property_set(sd, GSASL_SERVICE,
"xmpp");
751 gethostname(hostname, 256);
752 hostname[255] =
'\0';
754 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
758 case GSASL_VALIDATE_SIMPLE:
760 assert((ctx->
cb != NULL));
761 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
762 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
763 creds.
pass = gsasl_property_fast(sd, GSASL_PASSWORD);
764 if(!creds.
authnid)
return GSASL_NO_AUTHID;
765 if(!creds.
realm)
return GSASL_NO_AUTHZID;
766 if(!creds.
pass)
return GSASL_NO_PASSWORD;
770 return GSASL_AUTHENTICATION_ERROR;
772 case GSASL_VALIDATE_GSSAPI:
774 creds.
authnid = gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME);
775 if(!creds.
authnid)
return GSASL_NO_AUTHID;
776 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
777 if(!creds.
authzid)
return GSASL_NO_AUTHZID;
778 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
781 case GSASL_VALIDATE_ANONYMOUS:
783 creds.
authnid = gsasl_property_fast(sd, GSASL_ANONYMOUS_TOKEN);
784 if(!creds.
authnid)
return GSASL_NO_ANONYMOUS_TOKEN;
786 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
789 case GSASL_VALIDATE_EXTERNAL:
791 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
796 if (ctx->
ext_id[i] == NULL)
800 value = strstr(ctx->
ext_id[i],
"@");
805 _sx_debug(
ZONE,
"sasl ctx->ext_id doesn't have '@' in it. Assuming s2s");
816 len = value - ctx->
ext_id[i];
817 node = (
char *) malloc(
sizeof(
char) * (len + 1));
818 strncpy(node, ctx->
ext_id[i], len);
821 len = strlen(value) - 1 + 1;
822 host = (
char *) malloc(
sizeof(
char) * (len));
823 strcpy(host, value + 1);
824 gsasl_property_set(sd, GSASL_AUTHID, node);
825 gsasl_property_set(sd, GSASL_REALM, host);
830 return GSASL_AUTHENTICATION_ERROR;
836 return GSASL_NO_CALLBACK;
846 if(ctx->
ext_id[i] != NULL)
851 if (ctx != NULL) free(ctx);
864 appname = va_arg(args,
const char *);
865 if(appname == NULL) {
871 cbarg = va_arg(args,
void *);
875 ctx->
appname = strdup(appname);
882 if(ret != GSASL_OK) {
883 _sx_debug(
ZONE,
"couldn't initialize libgsasl (%d): %s", ret, gsasl_strerror (ret));
912 char *buf = NULL, *out = NULL;
915 size_t buflen, outlen;
920 assert((appname != NULL));
921 assert((mech != NULL));
922 assert((user != NULL));
923 assert((pass != NULL));
926 _sx_debug(
ZONE,
"need client in stream state for sasl auth");
931 ret = gsasl_client_start(ctx->
gsasl_ctx, mech, &sd);
932 if(ret != GSASL_OK) {
933 _sx_debug(
ZONE,
"gsasl_client_start failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
940 gethostname(hostname, 256);
941 hostname[255] =
'\0';
944 sctx = gsasl_session_hook_get(sd);
945 if (sctx != NULL) free(sctx);
953 gsasl_session_hook_set(sd, (
void *) sctx);
954 gsasl_property_set(sd, GSASL_AUTHID, user);
955 gsasl_property_set(sd, GSASL_PASSWORD, pass);
956 gsasl_property_set(sd, GSASL_SERVICE, appname);
957 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
960 ret = gsasl_step(sd, NULL, 0, &out, &outlen);
961 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
962 _sx_debug(
ZONE,
"gsasl_step failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
973 _sx_debug(
ZONE,
"sending auth request to server, mech '%s': %.*s", mech, outlen, out);
976 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
977 if(ret != GSASL_OK) {
978 _sx_debug(
ZONE,
"gsasl_base64_to failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
982 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
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
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
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