26 #include <gsasl-mech.h> 133 ret = gsasl_encode(sd, buf->
data, buf->
len, &out, &len);
134 if (ret != GSASL_OK) {
135 _sx_debug(
ZONE,
"gsasl_encode failed (%d): %s", ret, gsasl_strerror (ret));
161 ret = gsasl_decode(sd, buf->
data, buf->
len, &out, &len);
162 if (ret != GSASL_OK) {
163 _sx_debug(
ZONE,
"gsasl_decode failed (%d): %s", ret, gsasl_strerror (ret));
181 char *method, *authzid;
182 const char *realm = NULL;
186 const char *mechname = gsasl_mechanism_name (sd);
189 method = (
char *) malloc(
sizeof(
char) * (strlen(mechname) + 6));
190 sprintf(method,
"SASL/%s", mechname);
193 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
194 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
195 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
197 if(0 && ctx && ctx->
cb) {
199 _sx_debug(
ZONE,
"stream authzid: %s verification failed, not advancing to auth state", creds.
authzid);
203 }
else if (NULL != gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)) {
204 creds.
authzid = strdup(gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME));
213 authzid = (
char *) malloc(
sizeof(
char) * (strlen(creds.
authnid) + strlen(realm) + 2));
214 sprintf(authzid,
"%s@%s", creds.
authnid, realm);
222 if(authzid) free(authzid);
234 if(NULL == gsasl_property_fast(sd, GSASL_AUTHID)) {
235 _sx_debug(
ZONE,
"not auth'd, not advancing to auth'd state yet");
247 char *mechs, *mech, *c;
253 _sx_debug(
ZONE,
"already auth'd, not offering sasl mechanisms");
258 _sx_debug(
ZONE,
"application didn't ask us to offer sasl, so we won't");
264 _sx_debug(
ZONE,
"ssl not established yet but the app requires it, not offering mechanisms");
271 ret = gsasl_server_mechlist(ctx->
gsasl_ctx, &mechs);
272 if(ret != GSASL_OK) {
273 _sx_debug(
ZONE,
"gsasl_server_mechlist failed (%d): %s, not offering sasl for this conn", ret, gsasl_strerror (ret));
279 while(mech != NULL) {
280 c = strchr(mech,
' ');
321 char *buf = NULL, *out = NULL, *
realm = NULL, **
ext_id;
327 size_t buflen, outlen;
333 _sx_debug(
ZONE,
"auth request from client (mechanism=%s)", mech);
336 _sx_debug(
ZONE,
"client requested mechanism (%s) that we didn't offer", mech);
342 ret = gsasl_server_start(ctx->
gsasl_ctx, mech, &sd);
343 if(ret != GSASL_OK) {
344 _sx_debug(
ZONE,
"gsasl_server_start failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
353 sctx = gsasl_session_hook_get(sd);
354 if (sctx != NULL) free(sctx);
360 gsasl_session_hook_set(sd, (
void *) sctx);
361 gsasl_property_set(sd, GSASL_SERVICE, ctx->
appname);
362 gsasl_property_set(sd, GSASL_REALM,
realm);
366 gethostname(hostname, 256);
367 hostname[255] =
'\0';
368 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
373 for(i = 0; i < s->env->nplugins; i++)
374 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
375 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
391 s->plugin_data[p->
index] = (
void *) sd;
393 if(strcmp(mech,
"ANONYMOUS") == 0) {
402 buflen = strlen(buf);
403 }
else if (strstr(in,
"<") != NULL && strncmp(in,
"=", strstr(in,
"<") - in ) == 0) {
408 buflen = strlen(buf);
411 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
412 if (ret != GSASL_OK) {
413 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
415 if(buf != NULL) free(buf);
420 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
425 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
426 if (ret != GSASL_OK) {
427 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
433 _sx_debug(
ZONE,
"response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
435 if(buf != NULL) free(buf);
438 _sx_debug(
ZONE,
"response from client (decoded: %.*s)", buflen, buf);
439 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
442 if(buf != NULL) free(buf);
445 if(ret == GSASL_OK) {
449 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
450 if (ret == GSASL_OK) {
460 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
462 if(buf != NULL) free(buf);
465 if(out != NULL) free(out);
471 if(ret == GSASL_NEEDS_MORE) {
472 _sx_debug(
ZONE,
"sasl handshake in progress (challenge: %.*s)", outlen, out);
475 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
476 if (ret == GSASL_OK) {
481 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
483 if(buf != NULL) free(buf);
486 if(out != NULL) free(out);
491 if(out != NULL) free(out);
494 _sx_debug(
ZONE,
"sasl handshake failed; (%d): %s", ret, gsasl_strerror(ret));
497 case GSASL_AUTHENTICATION_ERROR:
498 case GSASL_NO_ANONYMOUS_TOKEN:
499 case GSASL_NO_AUTHID:
500 case GSASL_NO_AUTHZID:
501 case GSASL_NO_PASSWORD:
502 case GSASL_NO_PASSCODE:
504 case GSASL_NO_SERVICE:
505 case GSASL_NO_HOSTNAME:
508 case GSASL_UNKNOWN_MECHANISM:
509 case GSASL_MECHANISM_PARSE_ERROR:
512 case GSASL_BASE64_ERROR:
523 char *buf = NULL, *out = NULL;
524 size_t buflen, outlen;
530 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
532 if (ret == GSASL_OK) {
536 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
537 if(buf != NULL) free(buf);
541 if(ret == GSASL_OK || ret == GSASL_NEEDS_MORE) {
542 _sx_debug(
ZONE,
"sasl handshake in progress (response: %.*s)", outlen, out);
545 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
547 if (ret == GSASL_OK) {
551 if(out != NULL) free(out);
552 if(buf != NULL) free(buf);
557 if(out != NULL) free(out);
558 if(buf != NULL) free(buf);
561 _sx_debug(
ZONE,
"sasl handshake aborted; (%d): %s", ret, gsasl_strerror(ret));
573 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
589 _sx_debug(
ZONE,
"they tried to do sasl, but we never offered it, ignoring");
596 _sx_debug(
ZONE,
"they tried to do sasl, but they have to do starttls first, ignoring");
605 if((attr =
nad_find_attr(nad, 0, -1,
"mechanism", NULL)) < 0) {
644 _sx_debug(
ZONE,
"got sasl client packets, but they never started sasl, ignoring");
666 if(s->
ns != NULL) ns = strdup(s->
ns);
675 _sx_debug(
ZONE,
"restarting stream with sasl layer established");
681 if(ns != NULL) free(ns);
682 if(to != NULL) free(to);
683 if(from != NULL) free(from);
684 if(version != NULL) free(version);
723 sctx = gsasl_session_hook_get(sd);
726 gsasl_session_hook_set(sd, (
void *) NULL);
737 char *value, *node, *host;
748 _sx_debug(
ZONE,
"in _sx_sasl_gsasl_callback, property: %d", prop);
755 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
756 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
757 if(!creds.
authnid)
return GSASL_NO_AUTHID;
758 if(!creds.
realm)
return GSASL_NO_AUTHZID;
760 gsasl_property_set(sd, GSASL_PASSWORD, value);
762 return GSASL_NEEDS_MORE;
765 gsasl_property_set(sd, GSASL_SERVICE,
"xmpp");
773 gethostname(hostname, 256);
774 hostname[255] =
'\0';
776 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
780 case GSASL_VALIDATE_SIMPLE:
784 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
785 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
786 creds.
pass = gsasl_property_fast(sd, GSASL_PASSWORD);
787 if(!creds.
authnid)
return GSASL_NO_AUTHID;
788 if(!creds.
realm)
return GSASL_NO_AUTHZID;
789 if(!creds.
pass)
return GSASL_NO_PASSWORD;
793 return GSASL_AUTHENTICATION_ERROR;
795 case GSASL_VALIDATE_GSSAPI:
797 creds.
authnid = gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME);
798 if(!creds.
authnid)
return GSASL_NO_AUTHID;
799 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
800 if(!creds.
authzid)
return GSASL_NO_AUTHZID;
801 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
804 case GSASL_VALIDATE_ANONYMOUS:
806 creds.
authnid = gsasl_property_fast(sd, GSASL_ANONYMOUS_TOKEN);
807 if(!creds.
authnid)
return GSASL_NO_ANONYMOUS_TOKEN;
809 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
812 case GSASL_VALIDATE_EXTERNAL:
816 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
821 if (ctx->
ext_id[i] == NULL)
825 value = strstr(ctx->
ext_id[i],
"@");
830 _sx_debug(
ZONE,
"sasl ctx->ext_id doesn't have '@' in it. Assuming s2s");
841 len = value - ctx->
ext_id[i];
842 node = (
char *) malloc(
sizeof(
char) * (len + 1));
843 strncpy(node, ctx->
ext_id[i], len);
846 len = strlen(value) - 1 + 1;
847 host = (
char *) malloc(
sizeof(
char) * (len));
848 strcpy(host, value + 1);
849 gsasl_property_set(sd, GSASL_AUTHID, node);
850 gsasl_property_set(sd, GSASL_REALM, host);
855 return GSASL_AUTHENTICATION_ERROR;
861 return GSASL_NO_CALLBACK;
872 if(ctx->
ext_id[i] != NULL)
890 appname = va_arg(args,
const char *);
891 if(appname == NULL) {
897 cbarg = va_arg(args,
void *);
901 ctx->
appname = strdup(appname);
908 if(ret != GSASL_OK) {
909 _sx_debug(
ZONE,
"couldn't initialize libgsasl (%d): %s", ret, gsasl_strerror (ret));
938 char *buf = NULL, *out = NULL;
941 size_t buflen, outlen;
946 assert((appname != NULL));
947 assert((mech != NULL));
948 assert((user != NULL));
949 assert((pass != NULL));
952 _sx_debug(
ZONE,
"need client in stream state for sasl auth");
957 ret = gsasl_client_start(ctx->
gsasl_ctx, mech, &sd);
958 if(ret != GSASL_OK) {
959 _sx_debug(
ZONE,
"gsasl_client_start failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
966 gethostname(hostname, 256);
967 hostname[255] =
'\0';
970 sctx = gsasl_session_hook_get(sd);
971 if (sctx != NULL) free(sctx);
979 gsasl_session_hook_set(sd, (
void *) sctx);
980 gsasl_property_set(sd, GSASL_AUTHID, user);
981 gsasl_property_set(sd, GSASL_PASSWORD, pass);
982 gsasl_property_set(sd, GSASL_SERVICE, appname);
983 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
986 ret = gsasl_step(sd, NULL, 0, &out, &outlen);
987 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
988 _sx_debug(
ZONE,
"gsasl_step failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
999 _sx_debug(
ZONE,
"sending auth request to server, mech '%s': %.*s", mech, outlen, out);
1002 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
1003 if(ret != GSASL_OK) {
1004 _sx_debug(
ZONE,
"gsasl_base64_to failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
1008 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
#define _sasl_err_NOT_AUTHORIZED
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
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
static nad_t _sx_sasl_failure(sx_t s, const char *err, const char *text)
utility: generate a failure nad
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