23 #error Cyrus SASL implementation is not supported! It is included here only for the brave ones, that do know what they are doing. You need to remove this line to compile it.
34 # include <saslutil.h>
35 # include <saslplug.h>
37 # include <sasl/sasl.h>
38 # include <sasl/saslutil.h>
39 # include <sasl/saslplug.h>
70 const char *plugin_name,
75 if (strcmp(option,
"auxprop_plugin") == 0) {
76 *result =
"jabberdsx";
78 *len = strlen(
"jabberdsx");
88 static int _sx_sasl_getpath(
void *glob_context,
const char **path_dest) {
89 static char win32_path[MAX_PATH] =
"\0";
97 GetModuleFileName(NULL, win32_path, MAX_PATH - 5);
98 if(!*win32_path || !(r = strrchr(win32_path,
'\\')))
100 strcpy(r + 1,
"sasl");
103 *path_dest = win32_path;
112 sasl_server_params_t *sparams,
116 const char *realm = NULL;
118 const struct propval *to_fetch, *current;
119 char *user_buf = NULL;
124 if (!sparams || !user)
131 user_buf = sparams->utils->malloc(ulen + 1);
135 memcpy(user_buf, user, ulen);
136 user_buf[ulen] =
'\0';
138 c = strchr(user_buf,
'@');
140 if (sparams->user_realm && sparams->user_realm[0])
141 realm = sparams->user_realm;
143 realm = sparams->serverFQDN;
150 to_fetch = sparams->utils->prop_get(sparams->propctx);
153 for (current = to_fetch; current->name; current++) {
154 if (strncmp(current->name, SASL_AUX_PASSWORD,
sizeof(SASL_AUX_PASSWORD)) == 0) {
156 if (current->values) {
157 if (flags & SASL_AUXPROP_OVERRIDE)
158 sparams->utils->prop_erase(sparams->propctx, current->name);
167 sparams->utils->prop_set(sparams->propctx, current->name,
168 value, strlen(value));
173 if (user_buf) sparams->utils->free(user_buf);
181 sasl_auxprop_plug_t **plug,
const char *plugname) {
183 if (!out_version || !plug)
184 return SASL_BADPARAM;
185 if (max_version < SASL_AUXPROP_PLUG_VERSION )
188 *out_version = SASL_AUXPROP_PLUG_VERSION;
198 static int _sx_sasl_checkpass(sasl_conn_t *conn,
void *ctx,
const char *user,
const char *
pass,
unsigned passlen,
struct propctx *propctx) {
232 static int _sx_sasl_canon_user(sasl_conn_t *conn,
void *ctx,
const char *user,
unsigned ulen,
unsigned flags,
const char *user_realm,
char *out_user,
unsigned out_umax,
unsigned *out_ulen) {
235 sasl_getprop(conn, SASL_MECHNAME, (
const void **) &buf);
236 if (strncmp(buf,
"ANONYMOUS", 10) == 0) {
238 strncpy(out_user, buf, out_umax);
239 out_user[out_umax]=
'\0';
240 *out_ulen=strlen(out_user);
242 memcpy(out_user,user,ulen);
252 static int _sx_sasl_proxy_policy(sasl_conn_t *conn,
void *ctx,
const char *requested_user,
int rlen,
const char *auth_identity,
int alen,
const char *
realm,
int urlen,
struct propctx *propctx) {
259 sasl_getprop(conn, SASL_MECHNAME, (
const void **) &buf);
260 if (strncmp(buf,
"ANONYMOUS", 10) == 0) {
266 if (!requested_user || !auth_identity || rlen == 0 || alen==0) {
267 sasl_seterror(conn, 0,
268 "Bad identities provided");
279 buf = malloc(urlen + 1);
280 strncpy(buf, realm?realm:
"", urlen);
294 buf = malloc(alen + 1);
295 strncpy(buf, auth_identity, alen);
297 c = strrchr(buf,
'@');
298 if (c && strcmp(c+1, creds.
realm) == 0)
310 buf = malloc(len + 1);
311 strncpy(buf, requested_user, rlen);
313 c = strrchr(buf,
'@');
314 if (c && strcmp(c + 1, creds.
realm) == 0)
329 free((
void *)creds.
realm);
334 sasl_seterror(conn, 0,
"Requested identity not permitted for authorization identity");
342 int *x, len, pos, reslen, maxbuf;
348 sasl_getprop(sasl, SASL_SSF, (
const void **) &x);
355 sasl_getprop(sasl, SASL_MAXOUTBUF, (
const void **) &x);
360 result = NULL; reslen = 0;
361 while(pos < buf->len) {
362 if((buf->
len - pos) < maxbuf)
363 maxbuf = buf->
len - pos;
365 sasl_encode(sasl, &buf->
data[pos], maxbuf, (
const char **) &out, &len);
367 result = (
char *) realloc(result,
sizeof(
char) * (reslen + len));
368 memcpy(&result[reslen], out, len);
391 sasl_getprop(sasl, SASL_SSF, (
const void **) &x);
398 if (sasl_decode(sasl, buf->
data, buf->
len, (
const char **) &out, &len)
423 sasl_getprop(sasl, SASL_MECHNAME, (
const void **) &buf);
425 method = (
char *) malloc(
sizeof(
char) * (strlen(buf) + 17));
426 sprintf(method,
"SASL/%s", buf);
430 sasl_getprop(sasl, SASL_SSF, (
const void **) &ssf);
435 sasl_getprop(sasl, SASL_USERNAME, (
const void **) &buf);
446 len+=strlen(s->
req_to) + 2;
447 authzid = malloc(len + 1);
448 strcpy(authzid, buf);
450 sasl_getprop(sasl, SASL_DEFUSERREALM, (
const void **) &buf);
452 c = strrchr(authzid,
'@');
453 if (c && buf && strcmp(c+1, buf) == 0)
455 if (s->
req_to && strchr(authzid,
'@') == 0) {
456 strcat(authzid,
"@");
457 strcat(authzid, s->
req_to);
476 char *
realm = NULL, *ext_id, *mech;
477 sasl_security_properties_t sec_props;
485 _sx_debug(
ZONE,
"application did not request sasl offer, not offering for this conn");
499 sd->callbacks = calloc(
sizeof(sasl_callback_t),4);
501 sd->callbacks[0].id = SASL_CB_PROXY_POLICY;
503 sd->callbacks[0].context = sd;
505 sd->callbacks[1].id = SASL_CB_CANON_USER;
507 sd->callbacks[1].context = sd;
509 sd->callbacks[2].id = SASL_CB_SERVER_USERDB_CHECKPASS;
511 sd->callbacks[2].context = sd;
513 sd->callbacks[3].id = SASL_CB_LIST_END;
516 ret = sasl_server_new(ctx->
appname, NULL,
518 NULL, NULL, sd->callbacks,
521 _sx_debug(
ZONE,
"sasl_server_new failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL));
530 for(i = 0; i < s->env->nplugins; i++)
531 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
532 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
536 ret = sasl_setprop(sasl, SASL_AUTH_EXTERNAL, ext_id);
538 ret = sasl_setprop(sasl, SASL_SSF_EXTERNAL, &s->ssf);
546 sec_props.max_ssf = 0;
549 ret = sasl_setprop(sasl, SASL_SEC_PROPS, &sec_props);
552 _sx_debug(
ZONE,
"sasl_setprop failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL));
564 s->plugin_data[p->
index] = (
void *) sd;
574 if (sasl_getprop(sasl, SASL_MECHNAME, (
void *) &mech) == SASL_NOTDONE) {
575 _sx_debug(
ZONE,
"not auth'd, not advancing to auth'd state yet");
586 char *mechs, *mech, *c;
591 if((ret = sasl_getprop(sd->
sasl, SASL_MECHNAME, (
void *) &mech)) != SASL_NOTDONE) {
592 _sx_debug(
ZONE,
"already auth'd, not offering sasl mechanisms");
597 _sx_debug(
ZONE,
"application didn't ask us to offer sasl, so we won't");
603 _sx_debug(
ZONE,
"ssl not established yet but the app requires it, not offering mechanisms");
610 ret = sasl_listmech(sd->
sasl, NULL,
"",
"|",
"", (
const char **) &mechs, NULL, &nmechs);
612 _sx_debug(
ZONE,
"sasl_listmech failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL));
618 _sx_debug(
ZONE,
"sasl_listmech returned no mechanisms, not offering sasl for this conn");
625 while(mech != NULL) {
626 c = strchr(mech,
'|');
722 *out = (
char *) malloc(
sizeof(
char) * (2 * inlen));
723 sasl_decode64(in,inlen,*out,2*inlen,outlen);
728 *out = (
char *) malloc(
sizeof(
char) * (2 * inlen));
729 sasl_encode64(in,inlen,*out,2*inlen,outlen);
747 char *buf = NULL, *out = NULL;
748 int buflen, outlen, ret;
754 _sx_debug(
ZONE,
"auth request from client (mechanism=%s)", mech);
756 _sx_debug(
ZONE,
"response from client (response: %.*s)", buflen, buf);
761 ret = sasl_server_start(sd->
sasl, mech, buf, buflen, (
const char **) &out, &outlen);
764 _sx_debug(
ZONE,
"response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
766 if(buf != NULL) free(buf);
769 ret = sasl_server_step(sd->
sasl, buf, buflen, (
const char **) &out, &outlen);
772 if(buf != NULL) free(buf);
789 if(ret == SASL_CONTINUE) {
790 _sx_debug(
ZONE,
"sasl handshake in progress (challenge: %.*s)", outlen, out);
803 buf = (
char *) sasl_errdetail(sd->
sasl);
805 buf =
"[no error message available]";
816 int buflen, outlen, ret;
825 ret = sasl_client_step(sd->
sasl, buf, buflen, NULL, (
const char **) &out, &outlen);
826 if(buf != NULL) free(buf);
829 if(ret == SASL_OK || ret == SASL_CONTINUE) {
830 _sx_debug(
ZONE,
"sasl handshake in progress (response: %.*s)", outlen, out);
837 if(buf != NULL) free(buf);
843 err_buf = sasl_errdetail(sd->
sasl);
845 err_buf =
"[no error message available]";
859 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
875 _sx_debug(
ZONE,
"they tried to do sasl, but we never offered it, ignoring");
882 _sx_debug(
ZONE,
"they tried to do sasl, but they have to do starttls first, ignoring");
891 if((attr =
nad_find_attr(nad, 0, -1,
"mechanism", NULL)) < 0) {
930 _sx_debug(
ZONE,
"got sasl client packets, but they never started sasl, ignoring");
952 if(s->
ns != NULL) ns = strdup(s->
ns);
964 _sx_debug(
ZONE,
"restarting stream with sasl layer established");
970 if(ns != NULL) free(ns);
971 if(to != NULL) free(to);
972 if(from != NULL) free(from);
973 if(version != NULL) free(version);
1008 if(sd->
sasl != NULL) sasl_dispose(&sd->
sasl);
1009 if(sd->
user != NULL) free(sd->
user);
1039 appname = va_arg(args,
char *);
1040 if(appname == NULL) {
1046 cbarg = va_arg(args,
void *);
1060 ctx->
appname = strdup(appname);
1066 _sx_auxprop_plugin.glob_context = (
void *) ctx;
1087 if(ret != SASL_OK) {
1088 _sx_debug(
ZONE,
"sasl_server_init() failed (%s), disabling", sasl_errstring(ret, NULL, NULL));
1094 _sx_debug(
ZONE,
"sasl context initialised; appname=%s", appname);
1120 *len = strlen(*result);
1132 if(conn == NULL || psecret == NULL ||
id != SASL_CB_PASS)
1133 return SASL_BADPARAM;
1144 char *buf, *out, *ext_id;
1145 int i, ret, buflen, outlen, ns;
1146 sasl_security_properties_t sec_props;
1149 static sasl_callback_t win32_callbacks[2] = {
1150 {SASL_CB_GETPATH, &_sx_sasl_getpath, NULL},
1151 {SASL_CB_LIST_END, NULL, NULL}};
1154 assert((
int) (p != NULL));
1155 assert((
int) (s != NULL));
1156 assert((
int) (appname != NULL));
1157 assert((
int) (mech != NULL));
1160 _sx_debug(
ZONE,
"need client in stream state for sasl auth");
1166 ret = sasl_client_init(win32_callbacks);
1168 ret = sasl_client_init(NULL);
1170 if(ret != SASL_OK) {
1171 _sx_debug(
ZONE,
"sasl_client_init() failed (%s), not authing", sasl_errstring(ret, NULL, NULL));
1178 sd->user = strdup(user);
1181 sd->psecret = (sasl_secret_t *) malloc(
sizeof(sasl_secret_t) + strlen(
pass) + 1);
1182 strcpy(sd->psecret->data,
pass);
1183 sd->psecret->len = strlen(
pass);
1186 sd->callbacks=calloc(
sizeof(sasl_callback_t),4);
1189 sd->callbacks[0].id = SASL_CB_AUTHNAME;
1191 sd->callbacks[0].context = (
void *) sd;
1194 sd->callbacks[1].id = SASL_CB_PASS;
1196 sd->callbacks[1].context = (
void *) sd;
1199 sd->callbacks[2].id = SASL_CB_USER;
1201 sd->callbacks[2].context = (
void *) sd;
1204 sd->callbacks[3].id = SASL_CB_LIST_END;
1205 sd->callbacks[3].proc = NULL;
1206 sd->callbacks[3].context = NULL;
1209 ret = sasl_client_new(appname, (s->req_to != NULL) ? s->req_to :
"", NULL, NULL, sd->callbacks, 0, &sd->sasl);
1210 if(ret != SASL_OK) {
1211 _sx_debug(
ZONE,
"sasl_client_new failed, (%s), not authing", sasl_errstring(ret, NULL, NULL));
1213 if (sd->user != NULL) free(sd->user);
1214 if (sd->psecret != NULL) free(sd->psecret);
1215 free(sd->callbacks);
1224 for(i = 0; i < s->env->nplugins; i++)
1225 if(s->env->plugins[i]->magic ==
SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
1226 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
1237 if(ext_id != NULL) {
1238 ret = sasl_setprop(sd->sasl, SASL_AUTH_EXTERNAL, ext_id);
1239 if(ret == SASL_OK) ret = sasl_setprop(sd->sasl, SASL_SSF_EXTERNAL, &s->ssf);
1244 sec_props = ctx->sec_props;
1247 sec_props.max_ssf = 0;
1249 ret = sasl_setprop(sd->sasl, SASL_SEC_PROPS, &sec_props);
1250 if(ret != SASL_OK) {
1251 _sx_debug(
ZONE,
"sasl_setprop failed (%s), not authing", sasl_errstring(ret, NULL, NULL));
1253 sasl_dispose(&sd->sasl);
1255 if (sd->user != NULL) free(sd->user);
1256 if (sd->psecret != NULL) free(sd->psecret);
1257 free(sd->callbacks);
1264 ret = sasl_client_start(sd->sasl, mech, NULL, (
const char **) &out, &outlen, NULL);
1265 if(ret != SASL_OK && ret != SASL_CONTINUE) {
1266 _sx_debug(
ZONE,
"sasl_client_start failed (%s), not authing", sasl_errstring(ret, NULL, NULL));
1268 sasl_dispose(&sd->sasl);
1270 if (sd->user != NULL) free(sd->user);
1271 if (sd->psecret != NULL) free(sd->psecret);
1272 free(sd->callbacks);
1279 s->plugin_data[p->index] = (
void *) sd;
1282 _sx_debug(
ZONE,
"sending auth request to server, mech '%s': %.*s", mech, outlen, out);