26 #include <gsasl-mech.h>
60 #ifndef GSASL_NO_OBSOLETE
67 #define DIGEST_MD5_LENGTH 16
101 #define DIGEST_MD5_RESPONSE_LENGTH 32
223 ret = gsasl_encode(sd, buf->
data, buf->
len, &out, &len);
224 if (ret != GSASL_OK) {
225 _sx_debug(
ZONE,
"gsasl_encode failed (%d): %s", ret, gsasl_strerror (ret));
251 ret = gsasl_decode(sd, buf->
data, buf->
len, &out, &len);
252 if (ret != GSASL_OK) {
253 _sx_debug(
ZONE,
"gsasl_decode failed (%d): %s", ret, gsasl_strerror (ret));
271 char *method, *authzid;
272 const char *realm = NULL;
277 method = (
char *) malloc(
sizeof(
char) * (strlen(sd->
mech->name) + 6));
278 sprintf(method,
"SASL/%s", sd->
mech->name);
281 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
282 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
283 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
285 if(0 && ctx && ctx->
cb) {
287 _sx_debug(
ZONE,
"stream authzid: %s verification failed, not advancing to auth state", creds.
authzid);
291 }
else if (NULL != gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME)) {
292 creds.
authzid = strdup(gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME));
301 authzid = (
char *) malloc(
sizeof(
char) * (strlen(creds.
authnid) + strlen(realm) + 2));
302 sprintf(authzid,
"%s@%s", creds.
authnid, realm);
310 if(authzid) free(authzid);
322 if(NULL == gsasl_property_fast(sd, GSASL_AUTHID)) {
323 _sx_debug(
ZONE,
"not auth'd, not advancing to auth'd state yet");
335 char *mechs, *mech, *c;
341 _sx_debug(
ZONE,
"already auth'd, not offering sasl mechanisms");
346 _sx_debug(
ZONE,
"application didn't ask us to offer sasl, so we won't");
352 _sx_debug(
ZONE,
"ssl not established yet but the app requires it, not offering mechanisms");
359 ret = gsasl_server_mechlist(ctx->
gsasl_ctx, &mechs);
360 if(ret != GSASL_OK) {
361 _sx_debug(
ZONE,
"gsasl_server_mechlist failed (%d): %s, not offering sasl for this conn", ret, gsasl_strerror (ret));
367 while(mech != NULL) {
368 c = strchr(mech,
' ');
408 char *buf = NULL, *out = NULL, *
realm = NULL, **ext_id;
414 size_t buflen, outlen;
417 _sx_debug(
ZONE,
"auth request from client (mechanism=%s)", mech);
419 if(!gsasl_server_support_p(ctx->
gsasl_ctx, mech)) {
420 _sx_debug(
ZONE,
"client requested mechanism (%s) that we didn't offer", mech);
426 ret = gsasl_server_start(ctx->
gsasl_ctx, mech, &sd);
427 if(ret != GSASL_OK) {
428 _sx_debug(
ZONE,
"gsasl_server_start failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
437 gsasl_session_hook_set(sd, (
void *) ctx);
438 gsasl_property_set(sd, GSASL_SERVICE, ctx->
appname);
439 gsasl_property_set(sd, GSASL_REALM,
realm);
442 if (!strncmp(mech,
"DIGEST-MD5", 10)) {
449 gethostname(hostname, 256);
450 hostname[255] =
'\0';
451 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
456 for(i = 0; i < s->env->nplugins; i++)
457 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
458 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
459 if (ext_id != NULL) {
463 if (ext_id[i] != NULL) {
464 ctx->
ext_id[i] = strdup(ext_id[i]);
474 s->plugin_data[p->
index] = (
void *) sd;
476 if(strcmp(mech,
"ANONYMOUS") == 0) {
485 buflen = strlen(buf);
486 }
else if (strstr(in,
"<") != NULL && strncmp(in,
"=", strstr(in,
"<") - in ) == 0) {
491 buflen = strlen(buf);
494 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
495 if (ret != GSASL_OK) {
496 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
498 if(buf != NULL) free(buf);
503 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
504 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
505 _sx_debug(
ZONE,
"gsasl_step failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
507 if(out != NULL) free(out);
508 if(buf != NULL) free(buf);
515 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
516 if (ret != GSASL_OK) {
517 _sx_debug(
ZONE,
"gsasl_base64_from failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
523 _sx_debug(
ZONE,
"response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
525 if(buf != NULL) free(buf);
528 _sx_debug(
ZONE,
"response from client (decoded: %.*s)", buflen, buf);
529 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
532 if(buf != NULL) free(buf);
535 if(ret == GSASL_OK) {
539 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
540 if (ret == GSASL_OK) {
550 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
552 if(buf != NULL) free(buf);
555 if(out != NULL) free(out);
561 if(ret == GSASL_NEEDS_MORE) {
562 _sx_debug(
ZONE,
"sasl handshake in progress (challenge: %.*s)", outlen, out);
565 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
566 if (ret == GSASL_OK) {
571 _sx_debug(
ZONE,
"gsasl_base64_to failed, no sasl for this conn; (%d): %s", ret, gsasl_strerror(ret));
573 if(buf != NULL) free(buf);
576 if(out != NULL) free(out);
581 if(out != NULL) free(out);
584 _sx_debug(
ZONE,
"sasl handshake failed; (%d): %s", ret, gsasl_strerror(ret));
592 char *buf = NULL, *out = NULL;
593 size_t buflen, outlen;
599 ret = gsasl_base64_from(in, inlen, &buf, &buflen);
601 if (ret == GSASL_OK) {
605 ret = gsasl_step(sd, buf, buflen, &out, &outlen);
606 if(buf != NULL) free(buf); buf = NULL;
609 if(ret == GSASL_OK || ret == GSASL_NEEDS_MORE) {
610 _sx_debug(
ZONE,
"sasl handshake in progress (response: %.*s)", outlen, out);
613 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
615 if (ret == GSASL_OK) {
619 if(out != NULL) free(out);
620 if(buf != NULL) free(buf);
625 if(out != NULL) free(out);
626 if(buf != NULL) free(buf);
629 _sx_debug(
ZONE,
"sasl handshake aborted; (%d): %s", ret, gsasl_strerror(ret));
641 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
657 _sx_debug(
ZONE,
"they tried to do sasl, but we never offered it, ignoring");
664 _sx_debug(
ZONE,
"they tried to do sasl, but they have to do starttls first, ignoring");
673 if((attr =
nad_find_attr(nad, 0, -1,
"mechanism", NULL)) < 0) {
712 _sx_debug(
ZONE,
"got sasl client packets, but they never started sasl, ignoring");
734 if(s->
ns != NULL) ns = strdup(s->
ns);
743 _sx_debug(
ZONE,
"restarting stream with sasl layer established");
749 if(ns != NULL) free(ns);
750 if(to != NULL) free(to);
751 if(from != NULL) free(from);
752 if(version != NULL) free(version);
796 char *value, *node, *host;
799 _sx_debug(
ZONE,
"in _sx_sasl_gsasl_callback, property: %d", prop);
803 assert((ctx->
cb != NULL));
804 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
805 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
806 if(!creds.
authnid)
return GSASL_NO_AUTHID;
807 if(!creds.
realm)
return GSASL_NO_AUTHZID;
809 gsasl_property_set(sd, GSASL_PASSWORD, value);
811 return GSASL_NEEDS_MORE;
814 gsasl_property_set(sd, GSASL_SERVICE,
"xmpp");
822 gethostname(hostname, 256);
823 hostname[255] =
'\0';
825 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
829 case GSASL_VALIDATE_SIMPLE:
831 assert((ctx->
cb != NULL));
832 creds.
authnid = gsasl_property_fast(sd, GSASL_AUTHID);
833 creds.
realm = gsasl_property_fast(sd, GSASL_REALM);
834 creds.
pass = gsasl_property_fast(sd, GSASL_PASSWORD);
835 if(!creds.
authnid)
return GSASL_NO_AUTHID;
836 if(!creds.
realm)
return GSASL_NO_AUTHZID;
837 if(!creds.
pass)
return GSASL_NO_PASSWORD;
841 return GSASL_AUTHENTICATION_ERROR;
843 case GSASL_VALIDATE_GSSAPI:
845 creds.
authnid = gsasl_property_fast(sd, GSASL_GSSAPI_DISPLAY_NAME);
846 if(!creds.
authnid)
return GSASL_NO_AUTHID;
847 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
848 if(!creds.
authzid)
return GSASL_NO_AUTHZID;
849 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
852 case GSASL_VALIDATE_ANONYMOUS:
854 creds.
authnid = gsasl_property_fast(sd, GSASL_ANONYMOUS_TOKEN);
855 if(!creds.
authnid)
return GSASL_NO_ANONYMOUS_TOKEN;
857 gsasl_property_set(sd, GSASL_AUTHID, creds.
authnid);
860 case GSASL_VALIDATE_EXTERNAL:
862 creds.
authzid = gsasl_property_fast(sd, GSASL_AUTHZID);
867 if (ctx->
ext_id[i] == NULL)
871 value = strstr(ctx->
ext_id[i],
"@");
876 _sx_debug(
ZONE,
"sasl ctx->ext_id doesn't have '@' in it. Assuming s2s");
887 len = value - ctx->
ext_id[i];
888 node = (
char *) malloc(
sizeof(
char) * (len + 1));
889 strncpy(node, ctx->
ext_id[i], len);
892 len = strlen(value) - 1 + 1;
893 host = (
char *) malloc(
sizeof(
char) * (len));
894 strcpy(host, value + 1);
895 gsasl_property_set(sd, GSASL_AUTHID, node);
896 gsasl_property_set(sd, GSASL_REALM, host);
901 return GSASL_AUTHENTICATION_ERROR;
907 return GSASL_NO_CALLBACK;
917 if(ctx->
ext_id[i] != NULL)
922 if (ctx != NULL) free(ctx);
935 appname = va_arg(args,
char *);
936 if(appname == NULL) {
942 cbarg = va_arg(args,
void *);
946 ctx->
appname = strdup(appname);
953 if(ret != GSASL_OK) {
954 _sx_debug(
ZONE,
"couldn't initialize libgsasl (%d): %s", ret, gsasl_strerror (ret));
982 char *buf = NULL, *out = NULL;
985 size_t buflen, outlen;
990 assert((appname != NULL));
991 assert((mech != NULL));
992 assert((user != NULL));
993 assert((pass != NULL));
996 _sx_debug(
ZONE,
"need client in stream state for sasl auth");
1001 ret = gsasl_client_start(ctx->
gsasl_ctx, mech, &sd);
1002 if(ret != GSASL_OK) {
1003 _sx_debug(
ZONE,
"gsasl_client_start failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
1010 gethostname(hostname, 256);
1011 hostname[255] =
'\0';
1014 gsasl_session_hook_set(sd, (
void *) ctx);
1015 gsasl_property_set(sd, GSASL_AUTHID, user);
1016 gsasl_property_set(sd, GSASL_PASSWORD, pass);
1017 gsasl_property_set(sd, GSASL_SERVICE, appname);
1018 gsasl_property_set(sd, GSASL_HOSTNAME, hostname);
1021 ret = gsasl_step(sd, NULL, 0, &out, &outlen);
1022 if(ret != GSASL_OK && ret != GSASL_NEEDS_MORE) {
1023 _sx_debug(
ZONE,
"gsasl_step failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
1034 _sx_debug(
ZONE,
"sending auth request to server, mech '%s': %.*s", mech, outlen, out);
1037 ret = gsasl_base64_to(out, outlen, &buf, &buflen);
1038 if(ret != GSASL_OK) {
1039 _sx_debug(
ZONE,
"gsasl_base64_to failed, not authing; (%d): %s", ret, gsasl_strerror(ret));
1043 if (out != NULL) free(out);